2012-04-10 104 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') 

我想搞清楚,每個模塊科目,什麼最低DDA 帳戶是具有與它相關的完全相同的業主 。

在示例數據中,我想要這些結果,第三列是 擁有相同所有者的最低DDA帳戶。結果應具有相同的行數作爲therea re模塊/帳戶連擊 - 每行每一個行中的「SELECT DISTINCT模塊,帳戶FROM allAcctRels」)

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 acct在SVG 17中擁有所有的持有者,SVG 17中的持有者組合也不會出現任何一個DDA acct。每個DDA帳戶都會自行匹配,除非存在具有相同所有者和較低DDA的 dda帳戶(如DDA 222的情況)。

我可以看到,一種常規方法是將每個帳戶,組 的pivoted表,並使用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; 
+0

注意,「大通,比利的」 DDA 606行中不與嘲弄結果集,你說你要回來;我認爲你希望這是「Chase,Billy」,對吧? – mwigdahl 2012-04-10 22:00:02

+0

是的,這是正確的,對此感到抱歉,並且謝謝,我現在將重新編輯 – 2012-04-10 22:05:31

回答

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 2012-04-10 19:21:16

+0

但是,在這裏你保留了所有在'b'(DDA)端有任何匹配的行,不是嗎?例如,如果我將「Welch Raquel」添加到每個非DDA帳戶,Non-dda accts的結果不會改變,但不應該有任何匹配,因爲沒有非DDA acct擁有Raquel Welch。在我的示例數據中,我在「Walker Wilkie」中有兩個拼寫錯誤,這使得該查詢得到了與我的示例相同的結果,並且我沒有任何應用不匹配的「額外」人員的帳戶數據示例。我更新了sql小提琴,我也會更新上面的例子。 – 2012-04-10 19:38:05

+0

感謝您澄清。我正在看一遍。 – mwigdahl 2012-04-10 20:07:06

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,所以我想在接受之前弄清楚它是如何工作的。 – 2012-04-10 22:03:44

+0

@LevinMagruder它基本上使XML沒有實際的標記,並用於創建一個逗號分隔列表。如果您有任何問題,請告訴我。 – 2012-04-10 22:21:23

相關問題