我已经更新了小提琴以包含问题中提供的确切架构/数据,包括 null 问题。它还包括我建议的更改的示例。
该解决方案基本上采用给定数据并在内部对其进行转换(在 CTE 术语 nodes 中),以便 2 个顶级类别行链接到 id 为 0 的公共行,以便我提供的原始逻辑可用于处理这是一个层次的类别列表。
首先,我们递归地找到所有的分支列表。每个分支都由相应的根标识。然后,我们聚合每个根/分支的节点数量。
The fiddle
WITH RECURSIVE nodes AS (
SELECT id, COALESCE(idParentCategory, 0) AS idParentCategory
, sumSubtotal, sumQuantity
FROM tenant_category_transaction_view
UNION
SELECT 0, null, 0, 0
)
, cte AS (
SELECT t.*, t.id AS root
, idParentCategory AS idParentCategory0
, sumSubtotal AS sumSubtotal0
, sumQuantity AS sumQuantity0
FROM nodes AS t
UNION ALL
SELECT t.* , t0.root
, t0.idParentCategory0
, t0.sumSubtotal0
, t0.sumQuantity0
FROM cte AS t0
JOIN nodes AS t
ON t.idParentCategory = t0.id
)
SELECT root
, MIN(idParentCategory0) AS idParentCategory
, MIN(sumSubtotal0) AS sumSubtotal
, MIN(sumQuantity0) AS sumQuantity
, SUM(t1.sumSubtotal) AS total
FROM cte AS t1
GROUP BY root
ORDER BY root
;
结果:
| root |
idParentCategory |
sumSubtotal |
sumQuantity |
total |
| 0 |
null |
0 |
0 |
9890 |
| 1 |
0 |
9800 |
98 |
9800 |
| 4 |
0 |
20 |
1 |
90 |
| 5 |
4 |
30 |
1 |
70 |
| 6 |
5 |
40 |
1 |
40 |
设置:
CREATE TABLE tenant_category_transaction_view (
id int primary key
, idParentCategory int
, sumSubtotal int
, sumQuantity int
);
INSERT INTO tenant_category_transaction_view VALUES
(1, null, 9800, 98)
, (4, null, 20, 1)
, (5, 4, 30, 1)
, (6, 5, 40, 1)
;
以下使用建议对原始表格和数据进行轻微调整。代替 id 为 1 和 4 的行的 2 个顶部空父引用,添加一个顶行(例如,id 为 99)并让 id 为 2 和 4 的行引用 parent = 99 的行。
WITH RECURSIVE cte AS (
SELECT t.*, t.id AS root
FROM tenant_category_transaction_view AS t
UNION ALL
SELECT t.*, t0.root
FROM cte AS t0
JOIN tenant_category_transaction_view AS t
ON t.idParentCategory = t0.id
)
SELECT root
, MIN(t2.idParentCategory) AS idParentCategory
, MIN(t2.sumSubtotal) AS sumSubtotal
, MIN(t2.sumQuantity) AS sumQuantity
, SUM(t1.sumSubtotal) AS total
FROM cte AS t1
JOIN tenant_category_transaction_view AS t2
ON t1.root = t2.id
GROUP BY root
ORDER BY root
;
结果:
| root |
idParentCategory |
sumSubtotal |
sumQuantity |
total |
| 99 |
null |
0 |
0 |
9890 |
| 1 |
99 |
9800 |
98 |
9800 |
| 4 |
99 |
20 |
1 |
90 |
| 5 |
4 |
30 |
1 |
70 |
| 6 |
5 |
40 |
1 |
40 |
此外,这可以写入基于 t2.id 的聚合,这是主键,由于功能依赖性,允许稍微简化。
WITH RECURSIVE cte AS (
SELECT t.*, t.id AS root
FROM tenant_category_transaction_view AS t
UNION ALL
SELECT t.*, t0.root
FROM cte AS t0
JOIN tenant_category_transaction_view AS t
ON t.idParentCategory = t0.id
)
SELECT t2.id
, t2.idParentCategory
, t2.sumSubtotal
, t2.sumQuantity
, SUM(t1.sumSubtotal) AS total
FROM cte AS t1
JOIN tenant_category_transaction_view AS t2
ON t1.root = t2.id
GROUP BY t2.id
ORDER BY t2.id
;
最后,我们可以通过在递归逻辑中携带其他根值来删除最后一个 JOIN:
WITH RECURSIVE cte AS (
SELECT t.*, t.id AS root
, idParentCategory AS idParentCategory0
, sumSubtotal AS sumSubtotal0
, sumQuantity AS sumQuantity0
FROM tenant_category_transaction_view AS t
UNION ALL
SELECT t.* , t0.root
, t0.idParentCategory0
, t0.sumSubtotal0
, t0.sumQuantity0
FROM cte AS t0
JOIN tenant_category_transaction_view AS t
ON t.idParentCategory = t0.id
)
SELECT root
, MIN(idParentCategory0) AS idParentCategory
, MIN(sumSubtotal0) AS sumSubtotal
, MIN(sumQuantity0) AS sumQuantity
, SUM(t1.sumSubtotal) AS total
FROM cte AS t1
GROUP BY root
ORDER BY root
;
设置:
DROP TABLE IF EXISTS tenant_category_transaction_view;
CREATE TABLE tenant_category_transaction_view (
id int primary key
, idParentCategory int
, sumSubtotal int
, sumQuantity int
);
INSERT INTO tenant_category_transaction_view VALUES
(99, null, 0, 0)
, ( 1, 99, 9800, 98)
, ( 4, 99, 20, 1)
, ( 5, 4, 30, 1)
, ( 6, 5, 40, 1)
;