oracle 获取层次查询中每个父节点正下方的子节点的总和

uinbv5nw  于 2022-12-18  发布在  Oracle
关注(0)|答案(1)|浏览(155)

我有一个包含列id, label, cost, parent_id的表objective,我有以下查询

select 
b.id,
b.parent_id,
b.label,
b.cost
from objective b
start with b.parent_id is null
connect by 
prior b.id=b.parent_id
ORDER SIBLINGS BY b.id

只有叶子(有时是叶子的父节点)具有不为空的列cost,其它的几乎总是空,是否可以得到每个节点的成本(对正下方的节点的成本求和)。
我知道它可以用join和sum来完成,但我想也许有一个更简单的方法来完成它。如果这是表的内容:

ID  PARENT_ID   LABEL   COST
1   null        A       0
2   1           B       1
3   2           C       3
4   1           D       0
5   4           E       3
6   5           F       7
7   4           G       5

结果应该是这样的:

ID  PARENT_ID   LABEL   COST    CALCULATED_COST
1   null        A       0       15(meaning 0 is a wrong value) 
2   1           B       1       3 (meaning 1 is a wrong value)
3   2           C       3       3
4   1           D       0       12
5   4           E       3       7 (meaning 3 is a wrong value)
6   5           F       7       7
7   4           G       5       5

pftdvrlh

pftdvrlh1#

只有叶(有时是叶的父)的列成本不为空,其他的几乎总是空
如果规则是“只有一个叶节点或一个叶节点的父节点有非空的cost,其他节点总是空”,那么你可以用途:

SELECT id,
       parent_id,
       label,
       COALESCE(PRIOR cost, 0) + COALESCE(cost, 0) AS cost
FROM   objective
START WITH
       parent_id IS NULL
CONNECT BY
       PRIOR id = parent_id
ORDER SIBLINGS BY
       id

如果规则是“任何行都可以有一个非空的cost“,那么您需要在两个方向上解析数据结构:

SELECT id,
       parent_id,
       label,
       ( SELECT COALESCE(SUM(cost), 0)
         FROM   objective c
         START WITH c.id = o.id
         CONNECT BY PRIOR parent_id = id -- Reverse the direction
       ) AS cost
FROM   objective o
START WITH
       parent_id IS NULL
CONNECT BY
       PRIOR id = parent_id
ORDER SIBLINGS BY
       id

或者使用递归子查询分解子句:

WITH rsqfc (id, parent_id, label, cost) AS (
  SELECT id, parent_id, label, COALESCE(cost, 0)
  FROM   objective
  WHERE  parent_id IS NULL
UNION ALL
  SELECT o.id, o.parent_id, o.label, COALESCE(o.cost, 0) + r.cost
  FROM   objective o
         INNER JOIN rsqfc r
         ON (r.id = o.parent_id)
) SEARCH DEPTH FIRST BY id SET order_id
SELECT *
FROM   rsqfc;


fiddle

更新

如果要计算某行及其所有后代的成本总和,则可以用途:

SELECT id,
       parent_id,
       label,
       cost,
       ( SELECT COALESCE(SUM(cost), 0)
         FROM   objective c
         START WITH c.id = o.id
         CONNECT BY PRIOR id = parent_id
       ) AS total_cost
FROM   objective o
START WITH
       parent_id IS NULL
CONNECT BY
       PRIOR id = parent_id
ORDER SIBLINGS BY
       id;

对于样本数据输出:

CREATE TABLE objective ( id, parent_id, label, cost ) AS
SELECT 1, NULL, 'A', 0 FROM DUAL UNION ALL
SELECT 2, 1, 'B', 1 FROM DUAL UNION ALL
SELECT 3, 2, 'C', 3 FROM DUAL UNION ALL
SELECT 4, 1, 'D', 0 FROM DUAL UNION ALL
SELECT 5, 4, 'E', 3 FROM DUAL UNION ALL
SELECT 6, 5, 'F', 7 FROM DUAL UNION ALL
SELECT 7, 4, 'G', 5 FROM DUAL;

输出:
| 识别号|母体ID|标签|成本|总计_成本|
| - ------|- ------|- ------|- ------|- ------|
| 1个| * 无效 *| A类|无|十九|
| 第二章|1个|B| 1个|四个|
| 三个|第二章|C级|三个|三个|
| 四个|1个|D级|无|十五|
| 五个|四个|E级|三个|十个|
| 第六章|五个|F级|七|七|
| 七|四个|G级|五个|五个|
fiddle

更新2:

如果只想合计叶子的后代,则:

SELECT id,
       parent_id,
       label,
       cost,
       ( SELECT COALESCE(SUM(cost), 0)
         FROM   objective c
         WHERE  CONNECT_BY_ISLEAF = 1
         START WITH c.id = o.id
         CONNECT BY PRIOR id = parent_id
       ) AS total_cost
FROM   objective o
START WITH
       parent_id IS NULL
CONNECT BY
       PRIOR id = parent_id
ORDER SIBLINGS BY
       id;

对于样本数据,它输出:
| 识别号|母体ID|标签|成本|总计_成本|
| - ------|- ------|- ------|- ------|- ------|
| 1个| * 无效 *| A类|无|十五|
| 第二章|1个|B| 1个|三个|
| 三个|第二章|C级|三个|三个|
| 四个|1个|D级|无|十二|
| 五个|四个|E级|三个|七|
| 第六章|五个|F级|七|七|
| 七|四个|G级|五个|五个|
fiddle

相关问题