Рекурсивно суммировать номинал дочернего элемента с родительским на динамическом уровне структуры родитель-потомок

У меня есть данные, которые выглядят вот так

Я пытаюсь суммировать столбец «Номинал» для каждого соответствующего родителя, поэтому это будет выглядеть вот так

Я предоставил SQL-скрипт для данных:

CREATE TABLE [dbo].[Account](
    [AccountSeq] [bigint]  NOT NULL PRIMARY KEY,
    [ParentAccountSeq] [bigint] NULL,
    [AccountCode] [nvarchar](50) NOT NULL,
    [AccountName] [nvarchar](50) NOT NULL,
    [Nominal] [decimal](18, 2) NOT NULL
) 

INSERT [dbo].[Account] ([AccountSeq], [ParentAccountSeq], [AccountCode], [AccountName], [Nominal]) 
VALUES 
    (1, NULL, N'101', N'AKTIVA LANCAR', CAST(0.00 AS Decimal(18, 2)))
    ,(2, 1, N'10101', N'KAS', CAST(0.00 AS Decimal(18, 2)))
    ,(3, 2, N'1010101', N'KAS KECIL (IDR)', CAST(10000.00 AS Decimal(18, 2)))
    ,(4, 2, N'1010102', N'KAS KECIL ($$$)', CAST(15000.00 AS Decimal(18, 2)))
    ,(5, 1, N'10102', N'BANK', CAST(0.00 AS Decimal(18, 2)))
    ,(6, 5, N'1010201', N'BCA PKU AC: 220.391', CAST(20000.00 AS Decimal(18, 2)))
    ,(7, 5, N'1010202', N'BCA PKU AC: 220.279', CAST(25000.00 AS Decimal(18, 2)))
    ,(8, 1, N'10104', N'PIUTANG USAHA', CAST(30000.00 AS Decimal(18, 2)))
    ,(10, 1, N'10105', N'PIUTANG PROYEK', CAST(40000.00 AS Decimal(18, 2)))
    ,(11, NULL, N'201', N'HUTANG JANGKA PENDEK', CAST(50000.00 AS Decimal(18, 2)))
    ,(12, NULL, N'301', N'MODAL', CAST(60000.00 AS Decimal(18, 2)))

Последний SQL-запрос, который я пробовал:

WITH cteTest AS (
    SELECT
    AccountSeq,
    ParentAccountSeq,
    AccountCode,
    AccountName,
    CAST(Nominal AS DECIMAL(18,2)) AS Nominal
    FROM
    [Account]
    WHERE
    ParentAccountSeq IS NULL

    UNION ALL

    SELECT
    a.AccountSeq,
    a.ParentAccountSeq,
    a.AccountCode,
    a.AccountName,
    CAST((a.Nominal + cte.Nominal) AS DECIMAL(18,2)) AS Nominal
    FROM
    [Account] a
    INNER JOIN [cteTest] cte ON cte.AccountSeq = a.ParentAccountSeq
)
SELECT
*
FROM
[cteTest]
ORDER BY
AccountSeq

Пожалуйста, может ли кто-нибудь помочь мне решить эту проблему?

🤔 А знаете ли вы, что...
SQL (Structured Query Language) - это специальный язык запросов для работы с реляционными базами данных.


62
2

Ответы:

Отмените рекурсию и сгруппируйте по аккаунтам, чтобы получить иерархию итогов.

WITH cteTest AS (
    SELECT
    AccountSeq,
    ParentAccountSeq,
    AccountCode,
    AccountName,
    CAST(Nominal AS DECIMAL(18,2)) AS Nominal
    FROM
    [Account] a
    WHERE not exists (select 1 from [Account] b where a.AccountSeq =b.ParentAccountSeq)

    UNION ALL

    SELECT
    a.AccountSeq,
    a.ParentAccountSeq,
    a.AccountCode,
    a.AccountName,
    cte.Nominal
    FROM
    [Account] a
    INNER JOIN [cteTest] cte ON cte.ParentAccountSeq = a.AccountSeq
)
SELECT AccountSeq,
    ParentAccountSeq,
    AccountCode,
    AccountName,
    sum(Nominal) nom
FROM
[cteTest]
GROUP BY
    AccountSeq,
    ParentAccountSeq,
    AccountCode,
    AccountName
ORDER BY 
    AccountSeq

Решено

Для этой задачи мы можем собрать всех дочерних аккаунтов для каждой учетной записи, а затем суммировать номиналы с родительской учетной записью.

  1. Закрепите часть рекурсивного запроса.
    Мы берем все учетные записи из таблицы как root.

  2. Рекурсивная часть. Рекурсивный сбор дочерних элементов (через ссылку на родителя), дочерних элементов дочерних элементов и так далее. Столбец rootAccount одинаков для всех детей на каждой ветке дерева.
    Вывод рекурсивного запроса ниже.

  3. Совокупный номинал на rootAccount.

Здесь столбцы lvl и accs — для отладки и ясности. См. пример

Ваши исходные данные

AccountSeq РодительАккаунтСек Код счета Имя учетной записи Номинальный 1 нулевой 101 АКТИВА ЛАНКАР 0,00 2 1 10101 КАС 0,00 3 2 1010101 КАС КЕСИЛ (IDR) 10000,00 4 2 1010102 КАС КЕСИЛ ($$$) 15000,00 5 1 10102 БАНК 0,00 6 5 1010201 БСА ФКУ AC: 220.391 20000.00 7 5 1010202 БСА ФКУ AC: 220.279 25000,00 8 1 10104 ПИУТАНГ УСАХА 30000.00 10 1 10105 ПЬЮТАНГ ПРОЕК 40000.00 11 нулевой 201 ХУТАН ДЖАНКА ПЕНДЕК 50000,00 12 нулевой 301 МОДАЛЬНЫЙ 60000.00

Рекурсивный запрос

with r as(
  select 0 lvl,AccountSeq rootAccount,AccountSeq incAccount,Nominal
  from tAccount
  union all
  select lvl+1 lvl,r.rootAccount,t.AccountSeq incAccount,t.Nominal
  from r inner join tAccount t on t.ParentAccountSeq=r.incAccount
)
select a.*,t.sumNominal,accs
from tAccount a
left join(
   select rootAccount,sum(nominal)sumNominal
     ,string_agg(cast(incAccount as varchar),',') accs
   from r
   group by rootAccount
  ) t on a.AccountSeq=t.rootAccount

AccountSeq РодительАккаунтСек Код счета Имя учетной записи Номинальный суммаНоминальная аккаунты 1 нулевой 101 АКТИВА ЛАНКАР 0,00 140000.00 1,2,5,8,10,6,7,3,4 2 1 10101 КАС 0,00 25000,00 2,3,4 3 2 1010101 КАС КЕСИЛ (IDR) 10000,00 10000,00 3 4 2 1010102 КАС КЕСИЛ ($$$) 15000,00 15000,00 4 5 1 10102 БАНК 0,00 45000,00 5,6,7 6 5 1010201 БСА ФКУ AC: 220.391 20000.00 20000.00 6 7 5 1010202 БСА ФКУ AC: 220.279 25000,00 25000,00 7 8 1 10104 ПИУТАНГ УСАХА 30000.00 30000.00 8 10 1 10105 ПЬЮТАНГ ПРОЕК 40000.00 40000.00 10 11 нулевой 201 ХУТАН ДЖАНКА ПЕНДЕК 50000,00 50000,00 11 12 нулевой 301 МОДАЛЬНЫЙ 60000.00 60000.00 12

Подробности.
Вывод рекурсивного запроса перед агрегированием

with r as(
  select 0 lvl,AccountSeq rootAccount,AccountSeq incAccount,Nominal
    ,cast(AccountSeq as varchar(100)) path
    ,AccountName
  from tAccount
  union all
  select lvl+1 lvl,r.rootAccount,t.AccountSeq incAccount,t.Nominal
    ,cast(concat(path,',',cast(t.AccountSeq as varchar(100)))as varchar(100)) path
    ,t.AccountName
  from r inner join tAccount t on t.ParentAccountSeq=r.incAccount
)
select * from r order by rootAccount,lvl;
уровень rootAccount IncAccount Номинальный путь Имя учетной записи 0 1 1 0,00 1 АКТИВА ЛАНКАР 1 1 2 0,00 1,2 КАС 1 1 5 0,00 1,5 БАНК 1 1 8 30000.00 1,8 ПИУТАНГ УСАХА 1 1 10 40000.00 1,10 ПЬЮТАНГ ПРОЕК 2 1 6 20000.00 1,5,6 БСА ФКУ AC: 220.391 2 1 7 25000,00 1,5,7 БСА ФКУ AC: 220.279 2 1 3 10000,00 1,2,3 КАС КЕСИЛ (IDR) 2 1 4 15000,00 1,2,4 КАС КЕСИЛ ($$$) 0 2 2 0,00 2 КАС 1 2 3 10000,00 2,3 КАС КЕСИЛ (IDR) 1 2 4 15000,00 2,4 КАС КЕСИЛ ($$$) 0 3 3 10000,00 3 КАС КЕСИЛ (IDR) 0 4 4 15000,00 4 КАС КЕСИЛ ($$$) 0 5 5 0,00 5 БАНК 1 5 6 20000.00 5,6 БСА ФКУ AC: 220.391 1 5 7 25000,00 5,7 БСА ФКУ AC: 220.279 0 6 6 20000.00 6 БСА ФКУ AC: 220.391 0 7 7 25000,00 7 БСА ФКУ AC: 220.279 0 8 8 30000.00 8 ПИУТАНГ УСАХА 0 10 10 40000.00 10 ПЬЮТАНГ ПРОЕК 0 11 11 50000,00 11 ХУТАН ДЖАНКА ПЕНДЕК 0 12 12 60000.00 12 МОДАЛЬНЫЙ

рабочий пример