2012-04-10 2 views
5

통합 계정 처리를 설정하려면 에 "정확히 동일한"소유자가있는 계정을 찾고 싶습니다.다른 레코드 그룹과 일치하는 레코드 그룹을 찾는 방법 (관계 구분)

동적 SQL을 사용하여 소유자를 피벗시킨 다음 순위 함수를 사용하는 것이 좋겠다고 생각하지만 그 방법을 추구하고 싶지는 않습니다. 나는 에 주어진 계정과 연결할 수있는 이름의 수에 상한선이 없으므로 동적 SQL을 피하고 싶습니다.

내 데이터는 내가 가장 DDA 계정이 그와 연관된 동일한 소유자 을 가지고 무엇 각 모듈-ACCOUNT를 위해, 발견 할

CREATE TABLE allacctRels 
(account INT NOT NULL, 
module CHAR(3) NOT NULL, 
custCode CHAR(20) NOT NULL) 


INSERT INTO allacctrels 
(account, module, custCode) 
VALUES 
(1, 'DDA', 'Wilkie, Walker'), 
(1, 'DDA', 'Houzemeal, Juvy'), 
(2, 'CDS', 'Chase, Billy'), 
(2, 'CDS', 'Norman, Storm'), 
(3, 'CDS', 'Chase, Billy'), 
(3, 'CDS', 'Norman, Storm'), 
(7, 'CDS', 'Perkins, Tony'), 
(15, 'SVG', 'Wilkie, Walker'), --typo in name before mwigdahl's response 
(16, 'SVG', 'Wilkie, Walker'), -- corrected typo here too 
(606, 'DDA', 'Norman, Storm'), 
(606, 'DDA', 'Chase, Billy'),-- corrected 2nd typo found 
(4, 'LNS', 'Wilkie, Walker'), 
(4, 'LNS', 'Houzemeal, Juvy'), 
(44, 'DDA', 'Perkins, Tony'), 
(222, 'DDA', 'Wilkie, Walker'), 
(222, 'DDA', 'Houzemeal, Juvy'), 
(17, 'SVG', 'Wilkie, Walker'), -- added these three rows in edit, SVG 17 doesn't match any dda 
(17, 'SVG', 'Welch, Raquel'), 
(17, 'SVG', 'Houzemeal, Juvy') 

(또한이 http://www.sqlfiddle.com/#!3/1d36e에있다).

예제 데이터에서 세 번째 열은 동일한 소유자가있는 가장 낮은 DDA 계정 인 입니다. 각 행마다 하나의 행 "DISTINCT 모듈을 선택, allAcctRels FROM 계정") 어떤 DDA 일치하지 않는

1, DDA, 1 
2, CDS, 606 
3, CDS, 606 
15, SVG, NULL 
16, SVG, NULL 
606, DDA, 606 
4, LNS, 1 
7, CDS, 44 
44, DDA, 44 
222, DDA, 1 
17, SVG, NULL -- added to original post. 

SVG 15 16 - 결과는 thereâ 다시 모듈/계정 콤보로 같은 수의 행을 가져야한다 계정이므로 서로 일치하는 은 중요하지 않으며 계정 통합을 위해 NULL을받습니다. EDIT : SVG 17은 어떤 것도 일치하지 않습니다. SVG 17에 모든 홀더가있는 DDA 기능이 있더라도 SVG 17의 홀더 조합은 어떤 DDA 기능에도 나타나지 않습니다. 동일한 소유자 및 DDA가 낮은 dda 계정이 존재하지 않는 한 모든 DDA 계정이 일치합니다 (DDA 222의 경우).

일반적인 접근 방법 중 하나는 각 계정을 피벗시키고 그룹 을 피벗 테이블로 지정하고 row_number를 사용하는 것입니다. 각각의 계정과 관련된 홀더 무한한 숫자를 감안할 때, 나는 피벗 것이라고 생각합니다 동적 SQL은 피하고 싶습니다.

이것은 "관계형 divsion"문제이고, 관계형 부문은 교차 적용에 의해 "공급"되고있는 것으로 보입니다. 나는 계정 홀더 테이블을 가지고 특정 계정으로 과 관련된 테이블을 가져다가 아래에 표시된 라인을 따라 가장 낮은 dda 계정을 찾을 수있는 함수를 작성해 보았습니다. 주어진 숫자가 모든 사람들에게 주어진 지 알 수있었습니다. 계정은 해당 계정이 주어진 dda 계정에 에 가입 할 때 사람 수와 같지만 기능에 계정 번호가 인 테이블을 "피드"하는 방법을 알 수 없습니다.

-- this is what I tried but I'm not sure it the logic would work 
-- and I can't figure out how to pass the account holders for each 
-- account in. This is a bit changed from the function I wrote, some 
    -- extraneous fields removed and cryptic column names changed. So it 
    -- probably won't run as is. 

    -- to support a parameter type to a tape 
-- CREATE type VisionCustomer as Table 
-- (customer varchar(30)) 

CREATE FUNCTION consolidatable 
(@custList dbo.VisionCustomer READONLY) 
RETURNS char(10) 
AS 
BEGIN 
DECLARE @retval Varchar(10) 
DECLARE @howmany int 
select @howmany=Count(*) FROM @custlist; 

SELECT @retval = min (acct) FROM allAcctRels 
    JOIN @custlist 
     On VendorCustNo = Customer 
      WHERE acctType = 'DDA' 
      GROUP BY acct 
      HAVING (count(*) = @howmany) 
      and 
      COUNT(*) = (select Count(*) FROM allAcctRels X 
    WHERE X.acctType = 'DDA' 
    AND X.account = AllAcctRels.account) ; 
RETURN @retval 
END; 
+0

주를 606 DDA 행의 "체이스, 빌리는"결과 집합으로 비웃음하지 않습니다 당신은 당신이 다시 싶은 말 ; 이게 "체이스, 빌리"가되고 싶다고 생각해, 그렇지? – mwigdahl

+0

예, 맞습니다. 죄송합니다. 감사합니다. 지금 다시 편집하겠습니다. –

답변

1

정확하게 이해하는 경우 실제로 이것은 매우 간단합니다. 이것을 시도하십시오 :

SELECT a.account, a.module, MIN(b.account) 
FROM allacctRels a 
    LEFT JOIN allacctRels b ON a.custCode = b.custCode AND b.module = 'DDA' 
GROUP BY a.account, a.module 

편집 : 위 설명은 설명 후에는 작동하지 않지만 이렇게해야합니다. 이것은 실제로 관계 구분의 한 유형입니다. 아마도 세계에서 가장 효율적인 쿼리 계획은 아니지만 작동합니다.

SELECT a.account, a.module, MIN(b.account) 
FROM allacctRels a 
    LEFT JOIN allacctRels b ON b.module = 'DDA' 
    AND 
    -- first test is to confirm that the number of matching names for this combination equals the number of names for the DDA set... 
    (
     SELECT COUNT(*) 
     FROM allacctRels b2 
      INNER JOIN allacctRels a2 ON b2.custCode = a2.custCode 
     WHERE a.account = a2.account AND b.account = b2.account 
    ) = 
    (
     SELECT COUNT(*) 
     FROM allacctRels b2 
     WHERE b.account = b2.account 
    ) 
    AND 
    -- second test is to confirm that the number of names for the DDA set equals the number of names for the base set... 
    (
     SELECT COUNT(*) 
     FROM allacctRels b2 
     WHERE b.account = b2.account 
    ) = 
    (
     SELECT COUNT(*) 
     FROM allacctRels a2 
     WHERE a.account = a2.account 
    ) 
GROUP BY a.account, a.module 
+0

+1; 이것은 내가 이것을보고있을 때 내 머리 속으로 튀어 나온 첫 번째 것입니다. – lyrisey

+0

하지만 여기서 'b'(DDA) 쪽에서 일치하는 모든 행을 보존합니다. 그렇지 않습니까? 예를 들어 DDA 계정이 아닌 모든 사용자에게 'Welch Raquel'을 추가하면 Non-dda 계정에 대한 결과는 변경되지 않지만 일치하지 않아야합니다. DDA 계정이 아닌 사용자에게는 Raquel Welch가 없습니다. "Walker Wilkie"에 두 가지 오타가 있었는데이 쿼리를 사용하여 예제와 동일한 결과를 얻었습니다. 그리고 "extra"라는 사람과 일치하지 않아야하는 계정 데이터에 예제가 없습니다. 나는 SQL 피들을 업데이트했고, 위의 예제도 업데이트 할 것이다. –

+0

설명해 주셔서 감사합니다. 나는 그것을 다시보고있다. – mwigdahl

1

나는 이것이 당신이 (http://www.sqlfiddle.com/#!3/f96c5/1) 찾고있는 것으로 판단 :

;WITH AccountsWithOwners AS 
(
    SELECT DISTINCT 
    DA.module 
    , DA.account 
    , STUFF((SELECT 
       ',' + AAR.custCode 
       FROM allacctRels AAR 
       WHERE AAR.module = DA.module 
       AND AAR.account = DA.account 
       ORDER BY AAR.custCode 
       FOR XML PATH('')) 
       , 1, 1, '') AS Result 
    FROM allacctRels DA 
) 
, WithLowestDda AS 
(
    SELECT 
     AWO.module 
     , AWO.account 
     , MatchingAccounts.account AS DdaAccount 
     , ROW_NUMBER() OVER(PARTITION BY AWO.module, AWO.account ORDER BY MatchingAccounts.account) AS Row 
    FROM AccountsWithOwners AWO 
    LEFT JOIN AccountsWithOwners MatchingAccounts 
     ON MatchingAccounts.module = 'DDA' 
     AND MatchingAccounts.Result = AWO.Result 
) 
SELECT 
    account 
    , module 
    , DdaAccount 
FROM WithLowestDda 
WHERE Row = 1 
+0

이것은 승자처럼 보입니다. 백업을 시작하고 집으로 돌아 가야하는 것처럼 보입니다. 오늘 밤 더 보게 될 것이지만 테스트 데이터에서 올바른 결과를 얻는 것을 볼 수 있습니다. FOR XML에 익숙하지 않아서 수락하기 전에 어떻게 작동하는지 파악하고 싶습니다. –

+0

@LevinMagruder 기본적으로 실제 마크 업이없는 XML을 만들고 있으며 쉼표로 구분 된 목록을 만드는 데 사용됩니다. 궁금한 점이 있으면 알려주세요. –