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 帐户是什么。

在示例数据中,我想要这些结果,第三列是具有相同所有者的最低 DDA 帐户。结果应该具有与模块/帐户组合相同的行数 - “SELECT DISTINCT module, account 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 不匹配任何东西,即使在 SVG 17 中有一个 DDA 账户,其所有持有人都在,但任何一个 DDA 账户都不会出现 SVG 17 中持有人的组合。 每个 DDA 帐户都将匹配自己,除非存在具有相同所有者和较低 DDA 的 dda 帐户(如 DDA 222 的情况)。

我可以看到一种通用的方法是对每个帐户进行透视,对透视表进行分组,然后使用 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 回答