Oracle

时间:2018-05-01 20:31:40

标签: sql oracle recursive-query

我目前在理解和编写递归查询方面遇到了一些麻烦。我知道递归查询用于搜索信息的层次结构,但我还没有找到一个可以在层次结构中上传的简单在线解决方案。例如,假设我有一个模拟家谱的关系:

create table family_tree (
child varchar(10)
parent varchar(10)
);

如果我想写一个遍历这个家谱的递归查询,收集所有父母直到起源,我该怎么办呢?

提前致谢。

4 个答案:

答案 0 :(得分:3)

您可以使用connect by子句。

在您的情况下,SQL可能如下所示:

select child, parent, level
from family_tree 
connect by prior parent = child

答案 1 :(得分:1)

有一种我并不熟悉的ANSI语法,并且我经常使用Oracle语法。 Oracle语法使用CONNECT BY ... PRIOR子句构建树,并使用START WITH子句告诉数据库从哪里开始遍历树。它看起来像这样:

SELECT child, parent, level
  FROM family_tree
CONNECT BY ...
START WITH ...

START WITH子句更容易。你正在寻找" up"树,所以你要选择一个你想要开始走树的孩子。所以这看起来像START WITH parent = 'John'。这是我们的第1级。我假设约翰的行将他作为父母,而不是孩子,因为它是树的底部。

现在,考虑一下树中的行如何相互关联。如果我们正在查看第2级行,我们如何知道它是否是" John"行?在这种情况下,它将在子列中包含John。所以我们需要一个:CONNECT BY PRIOR parent = child的子句。这意味着"前一行的父母等于这一行的孩子"

所以查询看起来像:

SELECT child, parent, level
  FROM family_tree
CONNECT BY PRIOR parent = child
START WITH parent = 'John'

SQL Fiddle example

(这是一个奇怪的例子,因为实际的孩子有两个父母,但这会使它更复杂。)

答案 2 :(得分:0)

您熟悉SCOTT.EMP表吗?它符合标准" SCOTT模式(遗憾的是,从12.1版开始,不再预先打包了Oracle数据库的每个副本)。检查您的数据库:您可以在那里找到它。或者问你的DBA。

无论如何:该表显示了小型企业的14名员工,其中包括员工的ID以及他或她的经理的员工ID。所以,假设你从一个给定的员工开始,你想找到他或她最高级别的老板。 (与您的测试问题类似。)在这个特定的层次结构中,最高级别的"祖先"是独一无二的,但这是无关紧要的;如果每个部门都有一个部门负责人,那么递归查询将以相同的方式工作。部门负责人之上没有首席执行官。

在这种安排下,很容易识别所有老板的老板" - 他没有老板。在他的行中,经理ID为null。对于" root"这是一种非常常见的安排。 (或"根")树状层次结构。

以下是您如何找到老板,从特定员工ID开始,并使用递归查询 - 这就是我所理解的您正在寻求实践的内容。 (也就是说:如果我理解正确,你对解决这个问题不感兴趣"无论如何,你想看看递归查询是如何工作的,在一个小例子里你可以理解一切上。)

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
;

我不会试图猜测你可能难以理解这个例子。相反,我会等你问。

答案 3 :(得分:0)

  

如果我想写一个遍历这个家谱的递归查询,收集所有父母直到起源,我该怎么办呢?

使用分层查询和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