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_ROOTNOT 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