Oracle中的简单递归查询
Simple recursive query in Oracle
我目前在理解和编写递归查询时遇到了一些困难。我知道递归查询用于搜索信息的层次结构,但我还没有在网上找到可以向上移动层次结构的简单解决方案。例如,假设我有一个模拟家谱的关系:
create table family_tree (
child varchar(10)
parent varchar(10)
);
如果我想编写一个递归查询沿着这个家谱向上移动,收集所有 parents 直到起源,我应该怎么做?
提前致谢。
您可以使用 connect by
子句。
在您的情况下,SQL 可能如下所示:
select child, parent, level
from family_tree
connect by prior parent = child
你熟悉 SCOTT.EMP
table 吗?它在 "standard" SCOTT
模式中(不幸的是,从 12.1 左右的版本开始,它不再与 Oracle 数据库的每个副本一起预先打包)。检查您的数据库:您可能会在那里找到它。或者询问您的 DBA。
总之:table 显示了一个小企业的 14 名员工,它包括员工的 ID 以及他或她的经理的员工 ID。因此,假设您从给定的员工开始,并且您想要找到他或她的最高级别的老板。 (类似于您的测试问题。)在这个特定的层次结构中,最高级别 "ancestor" 是唯一的,但这无关紧要;如果每个部门都有一个 "head of department" 并且部门负责人之上没有 CEO,则递归查询将以相同的方式工作。
在这种安排中,很容易识别 "boss of all bosses" - 他没有老板。在他的行中,经理 ID 是 null
。这是树状层次结构 "root"(或 "roots")的一种非常常见的安排。
这是找到老板的方法,从特定的员工 ID 开始,并使用递归查询 - 据我所知,这就是您要练习的内容。 (也就是说:如果我理解正确,你对解决问题不感兴趣 "by any means";相反,你想看看递归查询是如何工作的,在一个小例子中,这样你就可以理解发生的一切。)
with
r ( empno, mgr ) as (
select empno, mgr -- ANCHOR leg of recursive query
from scott.emp
where empno = 7499
union all
select e.empno, e.mgr -- RECURSIVE leg of recursive query
from scott.emp e inner join r on e.empno = r.mgr
)
select empno
from r
where mgr is null
;
我不会试图猜测您可能在哪些地方难以理解这个例子。相反,我会等你问。
If I wanted to write a recursive query that travelled up this family tree, collecting all parents until origin, how should I go about this?
使用分层查询和 SYS_CONNECT_BY_PATH( column_name, delimiter )
函数:
Oracle 18 设置:
create table family_tree (
child varchar(10),
parent varchar(10)
);
INSERT INTO family_tree ( child, parent )
SELECT 'B', 'A' FROM DUAL UNION ALL
SELECT 'C', 'B' FROM DUAL UNION ALL
SELECT 'D', 'C' FROM DUAL UNION ALL
SELECT 'E', 'D' FROM DUAL UNION ALL
SELECT 'F', 'C' FROM DUAL;
查询 1:
SELECT SYS_CONNECT_BY_PATH( parent, ' -> ' ) || ' -> ' || child AS path
FROM family_tree
START WITH parent = 'A'
CONNECT BY PRIOR child = parent;
结果:
PATH
-------------------------
-> A -> B
-> A -> B -> C
-> A -> B -> C -> D
-> A -> B -> C -> D -> E
-> A -> B -> C -> F
有一种我不太熟悉的 ANSI 语法,有一种我通常使用的 Oracle 语法。 Oracle 语法使用 CONNECT BY ... PRIOR
子句构建树,并使用 START WITH
子句告诉数据库从哪里开始遍历树。它看起来像这样:
SELECT child, parent, level
FROM family_tree
CONNECT BY ...
START WITH ...
START WITH
子句更简单。您正在寻找 "up" 树,因此您可以选择一个 child 开始在树上行走的地方。所以这看起来像 START WITH parent = 'John'
。这是我们的 1 级行。我假设 John 的行将他作为 parent 而没有 children,因为它是树的底部。
现在,想想树中的行如何相互关联。如果我们正在查看 2 级行,我们如何知道它是否是 "John" 行的正确行?在本例中,John 将出现在 child 列中。所以我们想要一个子句:CONNECT BY PRIOR parent = child
。这意味着 "the prior row's parent equals this row's child"
所以查询看起来像:
SELECT child, parent, level
FROM family_tree
CONNECT BY PRIOR parent = child
START WITH parent = 'John'
(这个例子有点奇怪,因为实际的 children 有两个 parent,但这会使它变得更复杂。)
我目前在理解和编写递归查询时遇到了一些困难。我知道递归查询用于搜索信息的层次结构,但我还没有在网上找到可以向上移动层次结构的简单解决方案。例如,假设我有一个模拟家谱的关系:
create table family_tree (
child varchar(10)
parent varchar(10)
);
如果我想编写一个递归查询沿着这个家谱向上移动,收集所有 parents 直到起源,我应该怎么做?
提前致谢。
您可以使用 connect by
子句。
在您的情况下,SQL 可能如下所示:
select child, parent, level
from family_tree
connect by prior parent = child
你熟悉 SCOTT.EMP
table 吗?它在 "standard" SCOTT
模式中(不幸的是,从 12.1 左右的版本开始,它不再与 Oracle 数据库的每个副本一起预先打包)。检查您的数据库:您可能会在那里找到它。或者询问您的 DBA。
总之:table 显示了一个小企业的 14 名员工,它包括员工的 ID 以及他或她的经理的员工 ID。因此,假设您从给定的员工开始,并且您想要找到他或她的最高级别的老板。 (类似于您的测试问题。)在这个特定的层次结构中,最高级别 "ancestor" 是唯一的,但这无关紧要;如果每个部门都有一个 "head of department" 并且部门负责人之上没有 CEO,则递归查询将以相同的方式工作。
在这种安排中,很容易识别 "boss of all bosses" - 他没有老板。在他的行中,经理 ID 是 null
。这是树状层次结构 "root"(或 "roots")的一种非常常见的安排。
这是找到老板的方法,从特定的员工 ID 开始,并使用递归查询 - 据我所知,这就是您要练习的内容。 (也就是说:如果我理解正确,你对解决问题不感兴趣 "by any means";相反,你想看看递归查询是如何工作的,在一个小例子中,这样你就可以理解发生的一切。)
with
r ( empno, mgr ) as (
select empno, mgr -- ANCHOR leg of recursive query
from scott.emp
where empno = 7499
union all
select e.empno, e.mgr -- RECURSIVE leg of recursive query
from scott.emp e inner join r on e.empno = r.mgr
)
select empno
from r
where mgr is null
;
我不会试图猜测您可能在哪些地方难以理解这个例子。相反,我会等你问。
If I wanted to write a recursive query that travelled up this family tree, collecting all parents until origin, how should I go about this?
使用分层查询和 SYS_CONNECT_BY_PATH( column_name, delimiter )
函数:
Oracle 18 设置:
create table family_tree (
child varchar(10),
parent varchar(10)
);
INSERT INTO family_tree ( child, parent )
SELECT 'B', 'A' FROM DUAL UNION ALL
SELECT 'C', 'B' FROM DUAL UNION ALL
SELECT 'D', 'C' FROM DUAL UNION ALL
SELECT 'E', 'D' FROM DUAL UNION ALL
SELECT 'F', 'C' FROM DUAL;
查询 1:
SELECT SYS_CONNECT_BY_PATH( parent, ' -> ' ) || ' -> ' || child AS path
FROM family_tree
START WITH parent = 'A'
CONNECT BY PRIOR child = parent;
结果:
PATH
-------------------------
-> A -> B
-> A -> B -> C
-> A -> B -> C -> D
-> A -> B -> C -> D -> E
-> A -> B -> C -> F
有一种我不太熟悉的 ANSI 语法,有一种我通常使用的 Oracle 语法。 Oracle 语法使用 CONNECT BY ... PRIOR
子句构建树,并使用 START WITH
子句告诉数据库从哪里开始遍历树。它看起来像这样:
SELECT child, parent, level
FROM family_tree
CONNECT BY ...
START WITH ...
START WITH
子句更简单。您正在寻找 "up" 树,因此您可以选择一个 child 开始在树上行走的地方。所以这看起来像 START WITH parent = 'John'
。这是我们的 1 级行。我假设 John 的行将他作为 parent 而没有 children,因为它是树的底部。
现在,想想树中的行如何相互关联。如果我们正在查看 2 级行,我们如何知道它是否是 "John" 行的正确行?在本例中,John 将出现在 child 列中。所以我们想要一个子句:CONNECT BY PRIOR parent = child
。这意味着 "the prior row's parent equals this row's child"
所以查询看起来像:
SELECT child, parent, level
FROM family_tree
CONNECT BY PRIOR parent = child
START WITH parent = 'John'
(这个例子有点奇怪,因为实际的 children 有两个 parent,但这会使它变得更复杂。)