SQL - 聚合相关帐户 - 以实际方式设置ID

时间:2018-03-26 00:46:13

标签: sql-server tsql

我有两张桌子:

  • 帐号&金额列
  • 相关帐户列表

数据样本:

   Account |   Amount
   --------+---------
   001     |   $100
   002     |   $150
   003     |   $200
   004     |   $300

   Account |   Related Account
   --------+------------------
   001     |   002
   002     |   003
   003     |   002

我的目标是能够汇总所有相关帐户。从表二 - 001,002& 003实际上都是彼此相关的。我希望能够获得所有相关帐户的总和。可能是ID 001到003的帐号#1,所以我可以聚合它们。

以下结果

ID   | Account   | Amount
-----+-----------+--------
#1   |  001      | $100
#1   |  002      | $150
#1   |  003      | $200
#2   |  004      | $300 

然后我可以操作上面的表格(最终结果)

ID   | Amount
-----+--------
#1   | $450
#2   | $300

我尝试过加入,但它并没有达到我想要的效果。我仍然有一个问题,关于帐户001与003(他们是间接相关的,因为002与001和003都有关。

如果有人能指出我正确的方向,将不胜感激。

1 个答案:

答案 0 :(得分:2)

嗯,你真的应该更加努力。
如果您可以更改第二个表中的数据,那么它将不包含反向重复项(在您的样本数据中 - 2,3和3,2),这将简化解决方案。
如果您可以将两个表重构为单个表,related列是自引用可为空的外键,则可以进一步简化解决方案。

让我们假设你不能做一分钟,你必须按照提供的方式处理数据。所以你要做的第一件事是忽略第二个表中的反向重复。这可以使用公共表表达式和几个case表达式来完成。

首先,创建并填充样本表(在将来的问题中保存此步骤):

DECLARE @TAccount AS TABLE
(
    Account int,
    Amount int
)

INSERT INTO @TAccount (Account, Amount) VALUES
(1, 100),
(2, 150),
(3, 200),
(4, 300)

DECLARE @TRelatedAccounts AS TABLE
(
    Account int,
    Related int
)

INSERT INTO @TRelatedAccounts (Account, Related) VALUES 
(1,2),
(2,3),
(3,2)

您只想从@TRelatedAccounts表中获取前两个记录 这是 AccountAndRelated CTE 现在,您想要将@TAccount表加入此查询的结果,因此对于每个帐户,如果帐户与任何其他帐户无关,我们将拥有帐户,金额和相关帐户或NULL帐户或它是关系链中的第一个。
这是 CTERecursiveBase CTE 然后,基于此,您可以创建递归CTE(称为 CTERecursive ),最后根据递归的根选择递归CTE的总和。 这是整个脚本:

;WITH AccountAndRelated AS
(
    SELECT DISTINCT CASE WHEN Account > Related THEN Account Else Related END As Account, 
                    CASE WHEN Account > Related THEN Related Else Account END As Related
    FROM @TRelatedAccounts
)
, CTERecursiveBase AS
(
    SELECT A.Account, Related, Amount
    FROM @TAccount As A
    LEFT JOIN AccountAndRelated As R ON A.Account = R.Account
)
, CTERecursive AS
(
    SELECT Account As Id, Account, Related, Amount
    FROM CTERecursiveBase
    WHERE Related IS NULL
    UNION ALL
    SELECT Id, B.Account, B.Related, B.Amount
    FROM CTERecursiveBase AS B
    JOIN CTERecursive AS R ON B.Related = R.Account
)

SELECT Id, SUM(Amount) As TotalAmount
FROM CTERecursive
GROUP BY Id

结果:

Id  TotalAmount
1   450
4   300

You can see a live demo on rextester.

现在,我们假设您可以修改第二个表的数据。您可以使用AccountAndRelated cte获取您需要保留在@TRelatedAccounts表中的记录 - 这意味着您可以跳过AccountAndRelated cte并直接使用@TRelatedAccounts CTERecursiveBase cte。
You can see a live demo of that as well.

最后,我们假设您可以重构数据库。在这种情况下,我建议将两个表一起加入 - 所以你的@TAccount表看起来像这样:

Account Amount  Related
1       100     NULL
2       150     1
3       200     2
4       300     NULL

然后你只需要递归cte。 Here is a live demo of that option as well.