SQL 层次结构布尔汇总
SQL hierarchy boolean roll up
我有两个 table:Data 和 Data2。 Data 有 3 个布尔值,Data2 是 link table 以显示数据的层次结构 class。我试图找到一个只显示 Data2 的根的查询,如果该树中的任何值的每个布尔值都为真。
数据Table
Name
Atrue
Btrue
Ctrue
parent1
parent2
child1
X
X
child2
child3
X
X
Data2Table
parent_id
child_id
parent1
child1
parent2
child2
child2
child3
所以理论上我会展示
Name
Atrue
Btrue
Ctrue
parent1
1
1
parent2
1
1
我不需要计算有多少 boolens 为真,只需要说明是否有任何子项具有真值,但如果更容易的话,我仍然可以使用计数。
将您的关系 table 加入您的 table 布尔值后,您可以使用 CONNECT BY
将 parents 绑定到 children。您还可以使用 CONNECT_BY_ROOT
和 NOT EXISTS
语句仅获取顶级 parents 而不是整个关系中的每个 child。
查询
WITH
data1 (name,
atrue,
btrue,
ctrue)
AS
(SELECT 'parent1', NULL, NULL, NULL FROM DUAL
UNION ALL
SELECT 'parent2', NULL, NULL, NULL FROM DUAL
UNION ALL
SELECT 'child1', 'X', 'X', NULL FROM DUAL
UNION ALL
SELECT 'child2', NULL, NULL, NULL FROM DUAL
UNION ALL
SELECT 'child3', NULL, 'X', 'X' FROM DUAL),
data2 (parent_id, child_id)
AS
(SELECT 'parent1', 'child1' FROM DUAL
UNION ALL
SELECT 'parent2', 'child2' FROM DUAL
UNION ALL
SELECT 'child2', 'child3' FROM DUAL)
SELECT parent_name,
MAX (atrue) AS atrue,
MAX (btrue) AS btrue,
MAX (ctrue) AS ctrue
FROM ( SELECT CONNECT_BY_ROOT d2.parent_id AS parent_name,
d1.atrue,
d1.btrue,
d1.ctrue
FROM data2 d2 JOIN data1 d1 ON d2.child_id = d1.name
CONNECT BY d2.parent_id = PRIOR d2.child_id)
WHERE NOT EXISTS
(SELECT 1
FROM data2
WHERE child_id = parent_name)
GROUP BY parent_name
ORDER BY parent_name;
结果
PARENT_NAME ATRUE BTRUE CTRUE
______________ ________ ________ ________
parent1 X X
parent2 X X
像这样:
with
h (name, descendant) as (
select connect_by_root(parent_id) as name, child_id
from data2
start with parent_id like 'parent%' -- adapt as needed
connect by parent_id = prior child_id
)
select h.name, max(d.atrue) as atrue, max(d.btrue) as btrue, max(d.ctrue) as ctrue
from h left outer join data d on h.descendant = d.name
group by h.name
;
NAME ATRUE BTRUE CTRUE
------- ----- ----- -----
parent2 X X
parent1 X X
首先 运行 直接分层查询(“连接依据”)并为每个 child 标记根(“parent”)。然后加入真值 table,并在根上聚合(parents)。我使用了左外连接,因为层次 table 中的 child 根本没有出现在事实 table 中(将其解释为“所有列都为空 child)。在分层查询中,在 start with
子句中,我假设根名称以 'parent'
开头 - 这不是一个好的做法,更好的做法是让行“parent”显示为 child,其 parent 显示为 null
。(您也可以 start with parent_id not in (select child_id from data2)
- 这将导致 data2
扫描了两次。)
您可以使用从有效子项开始并返回到根的分层查询(其中,通过层次结构反转路径将是叶子):
SELECT d.name,
MAX(CONNECT_BY_ROOT atrue) AS Atrue,
MAX(CONNECT_BY_ROOT btrue) AS Btrue,
MAX(CONNECT_BY_ROOT ctrue) AS Ctrue
FROM data d
LEFT OUTER JOIN Data2 r
ON (d.name = r.parent_id)
WHERE CONNECT_BY_ISLEAF = 1
START WITH
Atrue IS NOT NULL
OR Btrue IS NOT NULL
OR Ctrue IS NOT NULL
CONNECT BY PRIOR d.name = r.child_id
GROUP BY d.name
其中,对于示例数据:
CREATE TABLE Data (Name, Atrue, Btrue, Ctrue) AS
SELECT 'parent1', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'parent2', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'parent3', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'parent4', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'parent5', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'child1', 'X', 'X', NULL FROM DUAL UNION ALL
SELECT 'child2', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'child3', NULL, 'X', 'X' FROM DUAL UNION ALL
SELECT 'child4', NULL, NULL, 'X' FROM DUAL UNION ALL
SELECT 'child5', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'child6', NULL, 'X', NULL FROM DUAL UNION ALL
SELECT 'child7', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'child8', NULL, NULL, NULL FROM DUAL;
CREATE TABLE Data2 (parent_id, child_id) AS
SELECT 'parent1', 'child1' FROM DUAL UNION ALL
SELECT 'parent2', 'child2' FROM DUAL UNION ALL
SELECT 'parent3', 'child4' FROM DUAL UNION ALL
SELECT 'parent3', 'child5' FROM DUAL UNION ALL
SELECT 'parent5', 'child7' FROM DUAL UNION ALL
SELECT 'child2', 'child3' FROM DUAL UNION ALL
SELECT 'child5', 'child6' FROM DUAL UNION ALL
SELECT 'child7', 'child8' FROM DUAL;
输出:
NAME
ATRUE
BTRUE
CTRUE
parent2
null
X
X
parent1
X
X
null
parent3
null
X
X
db<>fiddle here
我有两个 table:Data 和 Data2。 Data 有 3 个布尔值,Data2 是 link table 以显示数据的层次结构 class。我试图找到一个只显示 Data2 的根的查询,如果该树中的任何值的每个布尔值都为真。
数据Table
Name | Atrue | Btrue | Ctrue |
---|---|---|---|
parent1 | |||
parent2 | |||
child1 | X | X | |
child2 | |||
child3 | X | X |
Data2Table
parent_id | child_id |
---|---|
parent1 | child1 |
parent2 | child2 |
child2 | child3 |
所以理论上我会展示
Name | Atrue | Btrue | Ctrue |
---|---|---|---|
parent1 | 1 | 1 | |
parent2 | 1 | 1 |
我不需要计算有多少 boolens 为真,只需要说明是否有任何子项具有真值,但如果更容易的话,我仍然可以使用计数。
将您的关系 table 加入您的 table 布尔值后,您可以使用 CONNECT BY
将 parents 绑定到 children。您还可以使用 CONNECT_BY_ROOT
和 NOT EXISTS
语句仅获取顶级 parents 而不是整个关系中的每个 child。
查询
WITH
data1 (name,
atrue,
btrue,
ctrue)
AS
(SELECT 'parent1', NULL, NULL, NULL FROM DUAL
UNION ALL
SELECT 'parent2', NULL, NULL, NULL FROM DUAL
UNION ALL
SELECT 'child1', 'X', 'X', NULL FROM DUAL
UNION ALL
SELECT 'child2', NULL, NULL, NULL FROM DUAL
UNION ALL
SELECT 'child3', NULL, 'X', 'X' FROM DUAL),
data2 (parent_id, child_id)
AS
(SELECT 'parent1', 'child1' FROM DUAL
UNION ALL
SELECT 'parent2', 'child2' FROM DUAL
UNION ALL
SELECT 'child2', 'child3' FROM DUAL)
SELECT parent_name,
MAX (atrue) AS atrue,
MAX (btrue) AS btrue,
MAX (ctrue) AS ctrue
FROM ( SELECT CONNECT_BY_ROOT d2.parent_id AS parent_name,
d1.atrue,
d1.btrue,
d1.ctrue
FROM data2 d2 JOIN data1 d1 ON d2.child_id = d1.name
CONNECT BY d2.parent_id = PRIOR d2.child_id)
WHERE NOT EXISTS
(SELECT 1
FROM data2
WHERE child_id = parent_name)
GROUP BY parent_name
ORDER BY parent_name;
结果
PARENT_NAME ATRUE BTRUE CTRUE
______________ ________ ________ ________
parent1 X X
parent2 X X
像这样:
with
h (name, descendant) as (
select connect_by_root(parent_id) as name, child_id
from data2
start with parent_id like 'parent%' -- adapt as needed
connect by parent_id = prior child_id
)
select h.name, max(d.atrue) as atrue, max(d.btrue) as btrue, max(d.ctrue) as ctrue
from h left outer join data d on h.descendant = d.name
group by h.name
;
NAME ATRUE BTRUE CTRUE
------- ----- ----- -----
parent2 X X
parent1 X X
首先 运行 直接分层查询(“连接依据”)并为每个 child 标记根(“parent”)。然后加入真值 table,并在根上聚合(parents)。我使用了左外连接,因为层次 table 中的 child 根本没有出现在事实 table 中(将其解释为“所有列都为空 child)。在分层查询中,在 start with
子句中,我假设根名称以 'parent'
开头 - 这不是一个好的做法,更好的做法是让行“parent”显示为 child,其 parent 显示为 null
。(您也可以 start with parent_id not in (select child_id from data2)
- 这将导致 data2
扫描了两次。)
您可以使用从有效子项开始并返回到根的分层查询(其中,通过层次结构反转路径将是叶子):
SELECT d.name,
MAX(CONNECT_BY_ROOT atrue) AS Atrue,
MAX(CONNECT_BY_ROOT btrue) AS Btrue,
MAX(CONNECT_BY_ROOT ctrue) AS Ctrue
FROM data d
LEFT OUTER JOIN Data2 r
ON (d.name = r.parent_id)
WHERE CONNECT_BY_ISLEAF = 1
START WITH
Atrue IS NOT NULL
OR Btrue IS NOT NULL
OR Ctrue IS NOT NULL
CONNECT BY PRIOR d.name = r.child_id
GROUP BY d.name
其中,对于示例数据:
CREATE TABLE Data (Name, Atrue, Btrue, Ctrue) AS
SELECT 'parent1', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'parent2', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'parent3', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'parent4', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'parent5', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'child1', 'X', 'X', NULL FROM DUAL UNION ALL
SELECT 'child2', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'child3', NULL, 'X', 'X' FROM DUAL UNION ALL
SELECT 'child4', NULL, NULL, 'X' FROM DUAL UNION ALL
SELECT 'child5', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'child6', NULL, 'X', NULL FROM DUAL UNION ALL
SELECT 'child7', NULL, NULL, NULL FROM DUAL UNION ALL
SELECT 'child8', NULL, NULL, NULL FROM DUAL;
CREATE TABLE Data2 (parent_id, child_id) AS
SELECT 'parent1', 'child1' FROM DUAL UNION ALL
SELECT 'parent2', 'child2' FROM DUAL UNION ALL
SELECT 'parent3', 'child4' FROM DUAL UNION ALL
SELECT 'parent3', 'child5' FROM DUAL UNION ALL
SELECT 'parent5', 'child7' FROM DUAL UNION ALL
SELECT 'child2', 'child3' FROM DUAL UNION ALL
SELECT 'child5', 'child6' FROM DUAL UNION ALL
SELECT 'child7', 'child8' FROM DUAL;
输出:
NAME ATRUE BTRUE CTRUE parent2 null X X parent1 X X null parent3 null X X
db<>fiddle here