查找所有直接和间接结束child
Find all direct and indirect end child
我有 table 这样的 :
ID
Child ID
Flag
A01
C01
Y
A01
C02
Y
A01
AC01
N
AC01
C03
Y
AC01
AC02
N
AC02
C04
Y
所以这里的A01是直接parent的C01,C02,AC01。 AC01是C03和AC02的直接parent,AC02是C04.C01、C02、C03的直接parent和C04 没有任何 child。所以他们就像end children。这就是为什么他们的 标志是 'Y'。但是AC01和AC02不像纯端child。而且C03和C04是A01的间接child任 .
I want to list down all direct and indirect end children(Flag ='Y') of a particular ID.Something like below:
ID
Child ID
A01
C01
A01
C02
A01
C03
A01
C04
我使用的数据库Oracle 11G
我试过 递归 WITH 子句。
WITH child (id,child_id) AS (
SELECT id,
child_id,
0 AS level
FROM my_table
UNION ALL
SELECT e.id,
e.child_id,
level + 1
FROM my_table e
JOIN child s
ON e.id = s.child_id
)
SELECT
m.id,
s.child_id
FROM child s
JOIN my_table m
ON s.id = m.child_id;
但是我没有得到想要的输出。
因此,首先概括一下您的数据模型,您通常希望有一个 table 和一个 ID
作为 主键 ,一个额外的列指向到 parent_id
.
够了,ID
是 leaf(你所谓的 end child)没有必要存储为可以查询。
根据你的数据,你会得到这样的结果
create table tab as
select 'A01' id, null parent_id from dual union all
select 'C01' id, 'A01' parent_id from dual union all
select 'C02' id, 'A01' parent_id from dual union all
select 'AC01' id, 'A01' parent_id from dual union all
select 'C03' id, 'AC01' parent_id from dual union all
select 'AC02' id, 'AC01' parent_id from dual union all
select 'C04' id, 'AC02' parent_id from dual ;
ID PARENT_ID
---- ---------
A01
C01 A01
C02 A01
AC01 A01
C03 AC01
AC02 AC01
C04 AC02
现在 递归查询 获取所有 ID
直接或间接从节点说 A01
WITH rec (root_id, id, lvl) AS (
SELECT id as root_id,
id,
0 AS lvl
FROM tab where id = 'A01'
UNION ALL
SELECT rec.root_id root_id,
tab.id,
lvl + 1
FROM tab
JOIN rec
ON tab.parent_id = rec.id
)
SELECT
rec.root_id,
rec.id,
rec.lvl
FROM rec
ROOT ID LVL
---- ---- ----------
A01 A01 0
A01 C01 1
A01 C02 1
A01 AC01 1
A01 C03 2
A01 AC02 2
A01 C04 3
请注意,在递归查询的锚点部分,您必须限制要开始的节点(您没有这样做)。
这个问题不需要递归 with
子句。这是可以做到的,但识别“终结”儿童并非易事。
相反,老式的 connect by
查询(分层查询)可以快速完成这项工作。请注意,在我的查询(和输出)中,我没有包含 ID
列 - 如果您愿意,可以包含它,但它绝对不会给您任何信息;它只是将输入 ('A01'
) 复制到列中。这是您在 运行 查询之前就会知道的事情 - 实际上,甚至在编写查询之前!
关键是where
子句;在层次结构中,“结束”子级被称为 leaves,connect_by_isleaf
returns 1 代表叶子,0 否则。
select child_id
from my_table
where connect_by_isleaf = 1
start with id = 'A01'
connect by id = prior child_id
;
如果您坚持使用递归 with
子句的解决方案,这里有一种方法。请注意末尾的 search
子句 - 它是在下一个子查询中正确定义 is_leaf
列的关键。这种方法的一个优点是它使用 SQL 标准功能(递归 with
子句)模仿 Oracle 专有的分层查询 (connect by
)。
with
r (child_id, lvl) as (
select child_id, 1
from my_table
where id = 'A01'
union all
select t.child_id, r.lvl + 1
from my_table t join r on t.id = r.child_id
)
search depth first by child_id set ord
, prep (child_id, is_leaf) as (
select child_id,
case when lead(lvl) over (order by ord) > lvl then 0 else 1 end
from r
)
select child_id
from prep
where is_leaf = 1
;
我有 table 这样的 :
ID
Child ID
Flag
A01
C01
Y
A01
C02
Y
A01
AC01
N
AC01
C03
Y
AC01
AC02
N
AC02
C04
Y
所以这里的A01是直接parent的C01,C02,AC01。 AC01是C03和AC02的直接parent,AC02是C04.C01、C02、C03的直接parent和C04 没有任何 child。所以他们就像end children。这就是为什么他们的 标志是 'Y'。但是AC01和AC02不像纯端child。而且C03和C04是A01的间接child任 .
I want to list down all direct and indirect end children(Flag ='Y') of a particular ID.Something like below:
ID
Child ID
A01
C01
A01
C02
A01
C03
A01
C04
我使用的数据库Oracle 11G
我试过 递归 WITH 子句。
WITH child (id,child_id) AS (
SELECT id,
child_id,
0 AS level
FROM my_table
UNION ALL
SELECT e.id,
e.child_id,
level + 1
FROM my_table e
JOIN child s
ON e.id = s.child_id
)
SELECT
m.id,
s.child_id
FROM child s
JOIN my_table m
ON s.id = m.child_id;
但是我没有得到想要的输出。
因此,首先概括一下您的数据模型,您通常希望有一个 table 和一个 ID
作为 主键 ,一个额外的列指向到 parent_id
.
够了,ID
是 leaf(你所谓的 end child)没有必要存储为可以查询。
根据你的数据,你会得到这样的结果
create table tab as
select 'A01' id, null parent_id from dual union all
select 'C01' id, 'A01' parent_id from dual union all
select 'C02' id, 'A01' parent_id from dual union all
select 'AC01' id, 'A01' parent_id from dual union all
select 'C03' id, 'AC01' parent_id from dual union all
select 'AC02' id, 'AC01' parent_id from dual union all
select 'C04' id, 'AC02' parent_id from dual ;
ID PARENT_ID
---- ---------
A01
C01 A01
C02 A01
AC01 A01
C03 AC01
AC02 AC01
C04 AC02
现在 递归查询 获取所有 ID
直接或间接从节点说 A01
WITH rec (root_id, id, lvl) AS (
SELECT id as root_id,
id,
0 AS lvl
FROM tab where id = 'A01'
UNION ALL
SELECT rec.root_id root_id,
tab.id,
lvl + 1
FROM tab
JOIN rec
ON tab.parent_id = rec.id
)
SELECT
rec.root_id,
rec.id,
rec.lvl
FROM rec
ROOT ID LVL
---- ---- ----------
A01 A01 0
A01 C01 1
A01 C02 1
A01 AC01 1
A01 C03 2
A01 AC02 2
A01 C04 3
请注意,在递归查询的锚点部分,您必须限制要开始的节点(您没有这样做)。
这个问题不需要递归 with
子句。这是可以做到的,但识别“终结”儿童并非易事。
相反,老式的 connect by
查询(分层查询)可以快速完成这项工作。请注意,在我的查询(和输出)中,我没有包含 ID
列 - 如果您愿意,可以包含它,但它绝对不会给您任何信息;它只是将输入 ('A01'
) 复制到列中。这是您在 运行 查询之前就会知道的事情 - 实际上,甚至在编写查询之前!
关键是where
子句;在层次结构中,“结束”子级被称为 leaves,connect_by_isleaf
returns 1 代表叶子,0 否则。
select child_id
from my_table
where connect_by_isleaf = 1
start with id = 'A01'
connect by id = prior child_id
;
如果您坚持使用递归 with
子句的解决方案,这里有一种方法。请注意末尾的 search
子句 - 它是在下一个子查询中正确定义 is_leaf
列的关键。这种方法的一个优点是它使用 SQL 标准功能(递归 with
子句)模仿 Oracle 专有的分层查询 (connect by
)。
with
r (child_id, lvl) as (
select child_id, 1
from my_table
where id = 'A01'
union all
select t.child_id, r.lvl + 1
from my_table t join r on t.id = r.child_id
)
search depth first by child_id set ord
, prep (child_id, is_leaf) as (
select child_id,
case when lead(lvl) over (order by ord) > lvl then 0 else 1 end
from r
)
select child_id
from prep
where is_leaf = 1
;