2012-04-10 78 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

相关问题