2012-04-10 1 views
5

が完全に同じ所有者のアカウントを探しています。他のレコードグループに一致するレコードのグループを見つけるにはどうすればいいですか(リレーショナル部門ですか?)

ダイナミックSQLでオーナーをピボットしてから、 ランク付け関数を使用することができますが、私はそのアプローチを追求したくありません。私は のアカウントに与えられたアカウントの数に上限がありますので、動的SQLは避けてください。

私のデータは(もこれはhttp://www.sqlfiddle.com/#!3/1d36eである)

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') 

私が知りたい、各MODULE-ACCOUNTのために、どのような最低DDA アカウントは、それはそれに関連付けられた、まったく同じ所有者 を持っています。

サンプルデータでは、これらの結果が欲しいと思います.3番目の列は同じ所有者を持つDDAアカウントのうち、最も低いものが です。 「DISTINCTモジュールを選択allAcctRels FROMアカウント」内の各列ごとに1行)

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は、任意のDDAと一致しない - 結果は、モジュール/アカウントコンボ再thereaと同じ行数を持つべきですアカウントであるため、 が互いに一致しても問題はありません。これらのアカウントは、アカウントを統合するためにNULLを取得します。 EDIT:SVG 17は何もマッチしません。SVG 17にすべての所有者を持つDDAアクトがあっても、SVG 17のホルダーの組み合わせはいずれのDDAアタッチに対しても発生しません。同じ所有者と低いDDAを持つ ddaアカウントが存在する場合を除いて、すべてのDDAアカウントは一致します(DDA 222の場合と同様)。

一般的なアプローチの1つは、各アカウントをピボットし、 ピボットテーブルをグループ化し、row_numberを使用することです。各アカウントに関連付けられている 所有者の無限の数を考えると、私はむしろ回転を とすると思います。

これは「関係分裂」問題であり、 リレーショナル部門はおそらくクロスアプリケーションによって「フィード」されているようです。私は のアカウント保有者のテーブルを特定のアカウントと関連付けられたアカウント保有者のテーブルを取る機能を書こうとしました.の人数がすべてであるかどうかを確認するために、以下に示す という行に沿って最低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

注意;私はあなたがこれを "チェイス、ビリー"にしたいと思う? – 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"という2つのタイプミスがあり、私の例と同じ結果が得られませんでした。私はSQLのフィドルを更新して、私も上記の例を更新します。 –

+0

ご清聴ありがとうございます。私は再びそれを見ている。 – mwigdahl

1

私は、これはあなたが(http://www.sqlfiddle.com/#!3/f96c5/1)探しているものであると考えている:606 DDAの行の「チェイス、ビリーは」あなたが戻って欲しいと言う結果セットにジャイブしないこと

;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を作成しており、コンマ区切りのリストを作成するために使用されます。ご質問がある場合はお知らせください。 –

関連する問題