У меня есть данные, которые выглядят вот так
Я пытаюсь суммировать столбец «Номинал» для каждого соответствующего родителя, поэтому это будет выглядеть вот так
Я предоставил 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) - это специальный язык запросов для работы с реляционными базами данных.
Отмените рекурсию и сгруппируйте по аккаунтам, чтобы получить иерархию итогов.
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
Для этой задачи мы можем собрать всех дочерних аккаунтов для каждой учетной записи, а затем суммировать номиналы с родительской учетной записью.
Закрепите часть рекурсивного запроса.
Мы берем все учетные записи из таблицы как root.
Рекурсивная часть.
Рекурсивный сбор дочерних элементов (через ссылку на родителя), дочерних элементов дочерних элементов и так далее. Столбец rootAccount
одинаков для всех детей на каждой ветке дерева.
Вывод рекурсивного запроса ниже.
Совокупный номинал на rootAccount
.
Здесь столбцы lvl
и accs
— для отладки и ясности.
См. пример
Ваши исходные данные
Рекурсивный запрос
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
Подробности.
Вывод рекурсивного запроса перед агрегированием
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;