如何获取层次树中每一层子节点的总和?
How to get sum of the children nodes on every level in an hierarchical tree?
我有 table“A”,其分层数据如下:
create table dictionary_a
(
id number not null,
parent_id number,
c_name varchar2(50),
constraint pk_dictionary primary key (id),
constraint fk_dictionary foreign key (parent_id) references dictionary_a (id)
);
id parent_id c_name
1 name1
2 1 name2
3 1 name3
4 3 name4
5 3 name5
6 2 name6
7 6 name7
...
(实际分层数据 table 有 7 个级别,但这可能会发生变化)
和table“B”我需要总结的数据:
create table numeric_data
(
dict_id number not null,
n_sum number,
constraint fk_numeric_data foreign key (dict_id) references dictionary_a (id)
);
dict_id n_sum
1 36.0
2 20.0
3 16.0
4 10.5
5 5.5
7 20.0
...
请注意,更高级别的节点也有与之相关的总和。
我需要获取每个级别的所有子节点的总和,并将它们与列n_sum中的实际数据进行比较(此列由用户填充,我的工作是找出所有不一致的地方) :
dict_id n_sum actual_sum c_name
1 36.0 36.0 name1
2 20.0 20.0 name2
3 16.0 16.0 name3
4 10.5 10.5 name4
5 5.5 5.5 name5
6 20.0 name6
7 20.0 20.0 name7
我在网上搜索过,但我能找到的都是与具体问题密切相关,没有通用的解决方案。
测试数据:
insert into dictionary_a (ID, PARENT_ID, C_NAME)
values (1, null, 'Department 1');
insert into dictionary_a (ID, PARENT_ID, C_NAME)
values (2, 1, 'Department 2');
insert into dictionary_a (ID, PARENT_ID, C_NAME)
values (3, 1, 'Department 3');
insert into dictionary_a (ID, PARENT_ID, C_NAME)
values (4, 3, 'Department 4');
insert into dictionary_a (ID, PARENT_ID, C_NAME)
values (5, 3, 'Department 5');
insert into dictionary_a (ID, PARENT_ID, C_NAME)
values (6, 2, 'Department 6');
insert into dictionary_a (ID, PARENT_ID, C_NAME)
values (7, 6, 'Department 7');
insert into numeric_data (DICT_ID, N_SUM)
values (1, 36);
insert into numeric_data (DICT_ID, N_SUM)
values (2, 20);
insert into numeric_data (DICT_ID, N_SUM)
values (3, 16);
insert into numeric_data (DICT_ID, N_SUM)
values (4, 10.5);
insert into numeric_data (DICT_ID, N_SUM)
values (5, 5.5);
insert into numeric_data (DICT_ID, N_SUM)
values (7, 20);
commit;
我正在使用 Oracle 18c。
由于您正在生成随机数据,因此不清楚您的预期输出是什么;然而,要解决这个问题:
I need to get the sum of all child nodes at each level
可以生成所有的子节点,使用CONNECT_BY_ROOT
记录层级的根id;然后您可以对这些值求和以获得总数:
SELECT root_id,
MAX(c_name),
SUM(n_sum) AS total
FROM (
SELECT CONNECT_BY_ROOT(id) AS root_id,
CONNECT_BY_ROOT(c_name) AS c_name,
n.n_sum
FROM dictionary_a d
INNER JOIN numeric_data n
ON (d.id = n.dict_id)
CONNECT BY PRIOR d.id = d.parent_id
)
GROUP BY root_id
ORDER BY root_id
db<>fiddle here
您似乎想要的不是对所有子节点求和,而是对所有叶节点求和:
SELECT root_id,
MAX(c_name) AS c_name,
MAX(root_sum) As n_sum,
SUM(n_sum) AS total
FROM (
SELECT CONNECT_BY_ROOT id AS root_id,
CONNECT_BY_ROOT c_name AS c_name,
CONNECT_BY_ROOT n_sum AS root_sum,
d.id,
n.n_sum
FROM dictionary_a d
LEFT OUTER JOIN numeric_data n
ON (d.id = n.dict_id)
WHERE CONNECT_BY_ISLEAF = 1
CONNECT BY PRIOR d.id = d.parent_id
)
GROUP BY root_id
ORDER BY root_id
对于您的(非随机)样本数据,输出:
ROOT_ID
C_NAME
N_SUM
TOTAL
1
name1
36
36
2
name2
20
20
3
name3
16
16
4
name4
10.5
10.5
5
name5
5.5
5.5
6
name6
null
20
7
name7
20
20
db<>fiddle here
您可以在表之间使用外部联接:
select da.id, da.parent_id, da.c_name, coalesce(nd.n_sum, 0) as n_sum
from dictionary_a da
left join numeric_data nd on nd.dict_id = da.id;
然后将其用作分层查询的源,跟踪根 ID、名称和数量:
select id,
parent_id,
n_sum,
connect_by_root id as root_id,
connect_by_root n_sum as root_n_sum,
connect_by_root c_name as root_c_name,
connect_by_isleaf as isleaf
from (
select da.id, da.parent_id, da.c_name, coalesce(nd.n_sum, 0) as n_sum
from dictionary_a da
left join numeric_data nd on nd.dict_id = da.id
)
connect by parent_id = prior id;
然后对叶节点求和以获得您似乎想要的值:
with cte as (
select id,
parent_id,
n_sum,
connect_by_root id as root_id,
connect_by_root n_sum as root_n_sum,
connect_by_root c_name as root_c_name,
connect_by_isleaf as isleaf
from (
select da.id, da.parent_id, da.c_name, coalesce(nd.n_sum, 0) as n_sum
from dictionary_a da
left join numeric_data nd on nd.dict_id = da.id
)
connect by parent_id = prior id
)
select root_id as dict_id,
root_n_sum as n_sum,
sum(n_sum) as actual_sum,
root_c_name as c_name
from cte
where isleaf = 1
group by root_id, root_n_sum, root_c_name
order by root_id;
您的显式示例数据给出:
DICT_ID
N_SUM
ACTUAL_SUM
C_NAME
1
36
36
name1
2
20
20
name2
3
16
16
name3
4
10.5
10.5
name4
5
5.5
5.5
name5
6
0
20
name6
7
20
20
name7
我包含了 coalesce(nv.n_sum, 0)
,因此 ID 6 的 'original' n_sum
值显示为零而不是空值,您的示例没有;如果你只是删除合并,它将显示 null,但包括它意味着你可以添加一个简单的
having root_n_sum != sum(n_sum)
条款只看到差异。如果您单独保留空值,该子句只会变得更加复杂,但它可能更可取:
with cte as (
select id,
parent_id,
n_sum,
connect_by_root id as root_id,
connect_by_root n_sum as root_n_sum,
connect_by_root c_name as root_c_name,
connect_by_isleaf as isleaf
from (
select da.id, da.parent_id, da.c_name, nd.n_sum
from dictionary_a da
left join numeric_data nd on nd.dict_id = da.id
)
connect by parent_id = prior id
)
select root_id as dict_id,
root_n_sum as n_sum,
sum(n_sum) as actual_sum,
root_c_name as c_name
from cte
where isleaf = 1
group by root_id, root_n_sum, root_c_name
having (root_n_sum is null and sum(n_sum) is not null)
or (root_n_sum is not null and sum(n_sum) is null)
or root_n_sum != sum(n_sum)
order by root_id;
只给出:
DICT_ID
N_SUM
ACTUAL_SUM
C_NAME
6
null
20
name6
I need to get the sum of all child nodes at each level and compare them with the actual data from the column n_sum
不需要使用分层查询,如果您只比较每个父项与其子项的总和:
所以首先外部连接到您的 number table 两次,一次用于 id
一次用于 parent_id
.
所有子节点的 总和 与 parent_id
上的解析 SUM
一样简单。
比 select child_sum
与 节点总和 .
不匹配的所有行更简单
WITH dt AS (
select da.id, da.parent_id, da.c_name,
sum(nd.n_sum) OVER (partition by da.parent_id) as child_sum,
ndp.n_sum as id_sum
from dictionary_a da
left join numeric_data nd on nd.dict_id = da.id
left join numeric_data ndp on ndp.dict_id = da.parent_id
WHERE parent_id IS NOT NULL)
SELECT * FROM dt
WHERE nvl(child_sum,0) != nvl(id_sum,0)
不出所料,您遇到了两个问题
- 对于父
2
子总和 是 null
但节点总和是 20 和
- 对于父
6
子总和 是 20
但节点总和是 null
.
我有 table“A”,其分层数据如下:
create table dictionary_a
(
id number not null,
parent_id number,
c_name varchar2(50),
constraint pk_dictionary primary key (id),
constraint fk_dictionary foreign key (parent_id) references dictionary_a (id)
);
id parent_id c_name
1 name1
2 1 name2
3 1 name3
4 3 name4
5 3 name5
6 2 name6
7 6 name7
...
(实际分层数据 table 有 7 个级别,但这可能会发生变化)
和table“B”我需要总结的数据:
create table numeric_data
(
dict_id number not null,
n_sum number,
constraint fk_numeric_data foreign key (dict_id) references dictionary_a (id)
);
dict_id n_sum
1 36.0
2 20.0
3 16.0
4 10.5
5 5.5
7 20.0
...
请注意,更高级别的节点也有与之相关的总和。
我需要获取每个级别的所有子节点的总和,并将它们与列n_sum中的实际数据进行比较(此列由用户填充,我的工作是找出所有不一致的地方) :
dict_id n_sum actual_sum c_name
1 36.0 36.0 name1
2 20.0 20.0 name2
3 16.0 16.0 name3
4 10.5 10.5 name4
5 5.5 5.5 name5
6 20.0 name6
7 20.0 20.0 name7
我在网上搜索过,但我能找到的都是与具体问题密切相关,没有通用的解决方案。
测试数据:
insert into dictionary_a (ID, PARENT_ID, C_NAME)
values (1, null, 'Department 1');
insert into dictionary_a (ID, PARENT_ID, C_NAME)
values (2, 1, 'Department 2');
insert into dictionary_a (ID, PARENT_ID, C_NAME)
values (3, 1, 'Department 3');
insert into dictionary_a (ID, PARENT_ID, C_NAME)
values (4, 3, 'Department 4');
insert into dictionary_a (ID, PARENT_ID, C_NAME)
values (5, 3, 'Department 5');
insert into dictionary_a (ID, PARENT_ID, C_NAME)
values (6, 2, 'Department 6');
insert into dictionary_a (ID, PARENT_ID, C_NAME)
values (7, 6, 'Department 7');
insert into numeric_data (DICT_ID, N_SUM)
values (1, 36);
insert into numeric_data (DICT_ID, N_SUM)
values (2, 20);
insert into numeric_data (DICT_ID, N_SUM)
values (3, 16);
insert into numeric_data (DICT_ID, N_SUM)
values (4, 10.5);
insert into numeric_data (DICT_ID, N_SUM)
values (5, 5.5);
insert into numeric_data (DICT_ID, N_SUM)
values (7, 20);
commit;
我正在使用 Oracle 18c。
由于您正在生成随机数据,因此不清楚您的预期输出是什么;然而,要解决这个问题:
I need to get the sum of all child nodes at each level
可以生成所有的子节点,使用CONNECT_BY_ROOT
记录层级的根id;然后您可以对这些值求和以获得总数:
SELECT root_id,
MAX(c_name),
SUM(n_sum) AS total
FROM (
SELECT CONNECT_BY_ROOT(id) AS root_id,
CONNECT_BY_ROOT(c_name) AS c_name,
n.n_sum
FROM dictionary_a d
INNER JOIN numeric_data n
ON (d.id = n.dict_id)
CONNECT BY PRIOR d.id = d.parent_id
)
GROUP BY root_id
ORDER BY root_id
db<>fiddle here
您似乎想要的不是对所有子节点求和,而是对所有叶节点求和:
SELECT root_id,
MAX(c_name) AS c_name,
MAX(root_sum) As n_sum,
SUM(n_sum) AS total
FROM (
SELECT CONNECT_BY_ROOT id AS root_id,
CONNECT_BY_ROOT c_name AS c_name,
CONNECT_BY_ROOT n_sum AS root_sum,
d.id,
n.n_sum
FROM dictionary_a d
LEFT OUTER JOIN numeric_data n
ON (d.id = n.dict_id)
WHERE CONNECT_BY_ISLEAF = 1
CONNECT BY PRIOR d.id = d.parent_id
)
GROUP BY root_id
ORDER BY root_id
对于您的(非随机)样本数据,输出:
ROOT_ID C_NAME N_SUM TOTAL 1 name1 36 36 2 name2 20 20 3 name3 16 16 4 name4 10.5 10.5 5 name5 5.5 5.5 6 name6 null 20 7 name7 20 20
db<>fiddle here
您可以在表之间使用外部联接:
select da.id, da.parent_id, da.c_name, coalesce(nd.n_sum, 0) as n_sum
from dictionary_a da
left join numeric_data nd on nd.dict_id = da.id;
然后将其用作分层查询的源,跟踪根 ID、名称和数量:
select id,
parent_id,
n_sum,
connect_by_root id as root_id,
connect_by_root n_sum as root_n_sum,
connect_by_root c_name as root_c_name,
connect_by_isleaf as isleaf
from (
select da.id, da.parent_id, da.c_name, coalesce(nd.n_sum, 0) as n_sum
from dictionary_a da
left join numeric_data nd on nd.dict_id = da.id
)
connect by parent_id = prior id;
然后对叶节点求和以获得您似乎想要的值:
with cte as (
select id,
parent_id,
n_sum,
connect_by_root id as root_id,
connect_by_root n_sum as root_n_sum,
connect_by_root c_name as root_c_name,
connect_by_isleaf as isleaf
from (
select da.id, da.parent_id, da.c_name, coalesce(nd.n_sum, 0) as n_sum
from dictionary_a da
left join numeric_data nd on nd.dict_id = da.id
)
connect by parent_id = prior id
)
select root_id as dict_id,
root_n_sum as n_sum,
sum(n_sum) as actual_sum,
root_c_name as c_name
from cte
where isleaf = 1
group by root_id, root_n_sum, root_c_name
order by root_id;
您的显式示例数据给出:
DICT_ID | N_SUM | ACTUAL_SUM | C_NAME |
---|---|---|---|
1 | 36 | 36 | name1 |
2 | 20 | 20 | name2 |
3 | 16 | 16 | name3 |
4 | 10.5 | 10.5 | name4 |
5 | 5.5 | 5.5 | name5 |
6 | 0 | 20 | name6 |
7 | 20 | 20 | name7 |
我包含了 coalesce(nv.n_sum, 0)
,因此 ID 6 的 'original' n_sum
值显示为零而不是空值,您的示例没有;如果你只是删除合并,它将显示 null,但包括它意味着你可以添加一个简单的
having root_n_sum != sum(n_sum)
条款只看到差异。如果您单独保留空值,该子句只会变得更加复杂,但它可能更可取:
with cte as (
select id,
parent_id,
n_sum,
connect_by_root id as root_id,
connect_by_root n_sum as root_n_sum,
connect_by_root c_name as root_c_name,
connect_by_isleaf as isleaf
from (
select da.id, da.parent_id, da.c_name, nd.n_sum
from dictionary_a da
left join numeric_data nd on nd.dict_id = da.id
)
connect by parent_id = prior id
)
select root_id as dict_id,
root_n_sum as n_sum,
sum(n_sum) as actual_sum,
root_c_name as c_name
from cte
where isleaf = 1
group by root_id, root_n_sum, root_c_name
having (root_n_sum is null and sum(n_sum) is not null)
or (root_n_sum is not null and sum(n_sum) is null)
or root_n_sum != sum(n_sum)
order by root_id;
只给出:
DICT_ID | N_SUM | ACTUAL_SUM | C_NAME |
---|---|---|---|
6 | null | 20 | name6 |
I need to get the sum of all child nodes at each level and compare them with the actual data from the column n_sum
不需要使用分层查询,如果您只比较每个父项与其子项的总和:
所以首先外部连接到您的 number table 两次,一次用于 id
一次用于 parent_id
.
所有子节点的 总和 与 parent_id
上的解析 SUM
一样简单。
比 select child_sum
与 节点总和 .
WITH dt AS (
select da.id, da.parent_id, da.c_name,
sum(nd.n_sum) OVER (partition by da.parent_id) as child_sum,
ndp.n_sum as id_sum
from dictionary_a da
left join numeric_data nd on nd.dict_id = da.id
left join numeric_data ndp on ndp.dict_id = da.parent_id
WHERE parent_id IS NOT NULL)
SELECT * FROM dt
WHERE nvl(child_sum,0) != nvl(id_sum,0)
不出所料,您遇到了两个问题
- 对于父
2
子总和 是null
但节点总和是 20 和 - 对于父
6
子总和 是20
但节点总和是null
.