6

アカウントの統合処理を設定するために、所有者が「まったく同じ」アカウントを見つけたいと考えています。

動的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 アカウントです。結果には、モジュール/アカウントの組み合わせと同じ数の行が含まれている必要があります (「SELECT DISTINCT モジュール、アカウント FROM allAcctRels」の各行に 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 アカウントとも一致しないため、それらが互いに一致していても問題ありません。アカウントが統合されると、それらは NULL を取得します。 編集: SVG 17 にすべての所有者がいる DDA アカウントがあっても、SVG 17 は何にも一致しません。SVG 17 の所有者の組み合わせは、どの DDA アカウントにも発生しません。 同じ所有者で DDA が低い DDA アカウントが存在しない限り (DDA 222 の場合のように)、すべての DDA アカウントはそれ自体に一致します。

一般的なアプローチの 1 つは、各アカウントをピボットし、ピボットされたテーブルをグループ化し、row_number を使用することです。各アカウントに関連付けられている所有者の数に制限がないことを考えると、ピボットには避けたい動的 SQL が必要になると思います。

これは「関係分割」の問題であり、おそらく CROSS APPLY によって関係分割が「供給」されているように思えます。特定のアカウントに関連付けられたアカウント所有者のテーブルを取得し、以下に示す行に沿って最も低い 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;
4

2 に答える 2

2

これがあなたが探しているものだと思います(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
于 2012-04-10T21:47:13.403 に答える
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
于 2012-04-10T19:18:04.573 に答える