sql query (id,parentId) 结构中的层级累加和

Hierarchical cumulative sum in sql query (id,parentId) structure

我有两个表,我想获取所有帐户及其贷方金额和借方金额 甚至父记录也必须对它们的子值求和

我正在实施 Id ParentId 结构。

1- [AccountChart] Table 具有这些字段:

Id smallint
ParentId smallint Null
AccountName nvarchar(100)

2- [交易] Table 具有这些字段

AccountId smallInt
TransactionDate DateTime
Debit decimal(19,5)
Credit decimal(19,5)

这是我试过的

    Create table [AccountChart] (
    id int not null,
    parentId int null,
    AccountName nvarchar(100)

    PRIMARY KEY (ID)
      )

    Create table [TransactionData] (
    id int not null,
    TransactionDate DateTime not null,
    AccountId int not null,
    Credit decimal(19,5),
    Debit decimal(19,5)

    PRIMARY KEY (ID)
    )

    insert into [AccountChart] (id,parentId,AccountName) values (1,null,'level 0');
    insert into [AccountChart] (id,parentId,AccountName) values (2,1,'level 2');
    insert into [AccountChart] (id,parentId,AccountName) values (3,2,'level 3 - 1');
    insert into [AccountChart] (id,parentId,AccountName) values (4,2,'level 3 - 2 ');


    insert into [TransactionData] (id,TransactionDate,AccountId,Credit,Debit) values (1,'2020-03-17',3,1000.0,0.0)
    insert into [TransactionData] (id,TransactionDate,AccountId,Credit,Debit) values (2,'2020-03-17',3,0.0,1000.0)
    insert into [TransactionData] (id,TransactionDate,AccountId,Credit,Debit) values (3,'2020-03-17',4,4000.0,0.0)
    insert into [TransactionData] (id,TransactionDate,AccountId,Credit,Debit) values (4,'2020-03-17',3,6000.0,0.0)
    insert into [TransactionData] (id,TransactionDate,AccountId,Credit,Debit) values (5,'2020-03-17',4,3000.0,0.0)


    ;WITH cteBalances (AccountId, ParentId, Credit, Debit)
    AS (SELECT
      AccountChart.Id,
      AccountChart.ParentId,
      SUM([TransactionData].Credit) AS Credit,
      SUM([TransactionData].Debit) AS Debit
     FROM [TransactionData]
     INNER JOIN AccountChart ON ([TransactionData].AccountId = AccountChart.Id)
     GROUP BY AccountChart.Id,AccountChart.ParentId)

    SELECT
      AccountChart.id,
      AccountChart.ParentId,
      AccountChart.AccountName,
      cteBalances.Credit,
      cteBalances.Debit
    FROM  AccountChart 
    left JOIN cteBalances ON (AccountChart.ID = cteBalances.AccountID)

无法带上父记录汇总值的问题

我得到的结果是:

id  ParentId    AccountName   Credit        Debit
1   NULL        level 0       NULL          NULL
2   1           level 2       NULL          NULL
3   2           level 3 - 1   7000.00000    1000.00000
4   2           level 3 - 2   7000.00000    0.00000

但我希望像这样计算父级中的子级

id  ParentId    AccountName   Credit        Debit
1   NULL        level 0       14000.00000   1000.00000
2   1           level 2       14000.00000   1000.00000
3   2           level 3 - 1   7000.00000    1000.00000
4   2           level 3 - 2   7000.00000    0.00000

我喜欢使用范围键的技巧。 如果您的层次结构移动缓慢,我会创建一个table来存储这些值

只是为了扩展,范围键方便选择,和可变深度聚合。

您可能会注意到 SEQ 有一个 Order by AccountName。在我的 GL 系统中,我们有一列用于表示顺序。这控制顺序而不是帐户上名称或有效数字的字母顺序。

例子

Declare @Top  int         =  null   --<<  Sets top of Hier Try 2
Declare @Nest varchar(25) = '|---'  --<<  Optional: Added for readability

;with cteP as (
      Select Seq  = cast(10000+Row_Number() over (Order by AccountName) as varchar(500))
            ,ID
            ,ParentID 
            ,Lvl=1
            ,AccountName
      From   [AccountChart] 
      Where  IsNull(@Top,-1) = case when @Top is null then isnull(ParentID ,-1) else ID end
      Union  All
      Select Seq  = cast(concat(p.Seq,'.',10000+Row_Number() over (Order by r.AccountName)) as varchar(500))
            ,r.ID
            ,r.ParentID 
            ,p.Lvl+1
            ,r.AccountName
      From   [AccountChart] r
      Join   cteP p on r.ParentID  = p.ID)
     ,cteR1 as (Select *,R1=Row_Number() over (Order By Seq) From cteP)
     ,cteR2 as (Select A.ID,R2=Max(B.R1) From cteR1 A Join cteR1 B on (B.Seq like A.Seq+'%') Group By A.Seq,A.ID )
Select A.Lvl
      ,A.R1  
      ,B.R2
      ,A.ID
      ,A.ParentID 
      ,AccountName = max(Replicate(@Nest,A.Lvl-1) + A.AccountName)
      ,Credit      = sum(C.Credit)
      ,Debit       = sum(C.Debit)
 From cteR1 A
 Join cteR2 B on A.ID=B.ID
 Join (Select _R1=A.R1,B.* From cteR1 A Join [TransactionData] B on A.ID=B.AccountID ) C on (C._R1 between A.R1 and B.R2)
 Group By A.R1,B.R2,A.Lvl,A.ID,A.ParentID
 Order By A.R1

Returns