【问题标题】:Confusion with Oracle CONNECT BY与 Oracle CONNECT BY 混淆
【发布时间】:2013-09-05 12:46:23
【问题描述】:

查询:

select level from dual connect by rownum<10;

给出从 1 到 9 的数字。

另一个查询:

SELECT LEVEL FROM DUAL CONNECT BY rownum>5;

输出:1

我在经理/员工等分层数据中使用了 CONNECT BY。但是我无法解释上述两个查询的结果。

编辑: 我不想通过查询#2 来实现任何特别的目的。我只想知道 oracle 如何解释查询。由于使用了 CONNECT BY,是否有任何部分充当父子关系?为什么结果是 1?幕后发生了什么?

【问题讨论】:

    标签: sql oracle oracle11g


    【解决方案1】:

    如何执行和评估 CONNECT BY 查询 - 一步一步(通过示例)。

    假设我们有下表和一个通过查询连接:

    select * from mytable;
    
             X
    ----------
             1 
             2 
             3 
             4 
    
    SELECT level, m.* 
    FROM mytable m
    START with x = 1
    CONNECT BY PRIOR x +1 = x  OR  PRIOR x + 2 = x 
    ORDER BY level;
    

    第 1 步:

    从表mytable中选择满足START WITH条件的行,将LEVEL = 1赋给返回的结果集:

     CREATE TABLE step1 AS
     SELECT 1 "LEVEL", X from mytable
     WHERE x = 1;
    
     SELECT * FROM step1;
    
             LEVEL          X
        ---------- ----------
                 1          1
    

    第 2 步

    增加1级:

    LEVEL = LEVEL + 1
    

    使用CONNECT BY 条件作为连接条件,将上一步返回的结果集与mytable 连接起来。

    本句中PRIOR column-name指的是上一步返回的结果集,简单的column-name指的是mytable表:

    CREATE TABLE step2 AS
    SELECT 2 "LEVEL", mytable.X from mytable
    JOIN step1 "PRIOR"
    ON "PRIOR".x +1 = mytable.x or  "PRIOR".x + 2 = mytable.x;
    
    select * from step2;
    
         LEVEL          X
    ---------- ----------
             2          2 
             2          3
    

    第 x+1 步

    重复 #2 直到最后一个操作返回一个空结果集。

    第 3 步

    CREATE TABLE step3 AS
    SELECT 3 "LEVEL", mytable.X from mytable
    JOIN step2 "PRIOR"
    ON "PRIOR".x +1 = mytable.x or  "PRIOR".x + 2 = mytable.x;
    
    select * from step3;
    
         LEVEL          X
    ---------- ----------
             3          3 
             3          4 
             3          4
    

    第 4 步

    CREATE TABLE step4 AS
    SELECT 4 "LEVEL", mytable.X from mytable
    JOIN step3 "PRIOR"
    ON "PRIOR".x +1 = mytable.x or  "PRIOR".x + 2 = mytable.x;
    
    select * from step4;
    
         LEVEL          X
    ---------- ----------
             4          4 
    

    第 5 步

    CREATE TABLE step5 AS
    SELECT 5 "LEVEL", mytable.X from mytable
    JOIN step4 "PRIOR"
    ON "PRIOR".x +1 = mytable.x or  "PRIOR".x + 2 = mytable.x;
    
    select * from step5;
    
    no rows selected
    

    第 5 步没有返回任何行,所以现在我们完成查询

    最后一步

    UNION ALL所有步骤的结果并将其作为最终结果返回:

    SELECT * FROM step1
    UNION ALL
    SELECT * FROM step2
    UNION ALL
    SELECT * FROM step3
    UNION ALL
    SELECT * FROM step4
    UNION ALL
    
    SELECT * FROM step5;
    
         LEVEL          X
    ---------- ----------
             1          1 
             2          2 
             2          3 
             3          3 
             3          4 
             3          4 
             4          4 
    

    现在让我们将上述过程应用于您的查询:

    SELECT * FROM dual;
    
    DUMMY
    -----
    X 
    
    SELECT LEVEL FROM DUAL CONNECT BY rownum>5;
    

    第 1 步

    由于查询不包含START WITH子句,Oracle选择源表中的所有记录:

    CREATE TABLE step1 AS
    SELECT 1 "LEVEL" FROM dual;
    
    select * from step1;
    
         LEVEL
    ----------
             1 
    

    第 2 步

    CREATE TABLE step2 AS
    SELECT 2 "LEVEL" from dual
    JOIN step1 "PRIOR"
    ON rownum > 5
    
    select * from step2;
    
    no rows selected
    

    由于最后一步没有返回任何行,我们将完成查询。

    最后一步

    SELECT * FROM step1
    UNION ALL
    
    SELECT * FROM step2;
    
         LEVEL
    ----------
             1
    

    上一次查询的分析:

    select level from dual connect by rownum<10;
    

    我把作业留给你。

    【讨论】:

    • +1 感谢您的详细解释。您的解释比 oracle 网站上提供的任何文档都要好得多。现在对我来说很清楚:-)
    • 虽然这个答案在大多数情况下是正确的,但关于在 CONNECT BY 查询中如何分配 ROWNUM 是错误的特别是。在CONNECT BY 查询中,结果集是唯一的,ROWNUMLEVEL = 1 连续分配到更高级别;它不会在每个级别从 1 重新开始。稍后的线程中的详细信息,其中有人实际上试图做这个答案末尾留下的所谓的“家庭作业”。 stackoverflow.com/questions/52899897/oracle-connect-by-rownum/…
    【解决方案2】:

    这与 CONNECT BY 无关,而是您滥用 ROWNUM 的产物。

    引用the documentation

    对于查询返回的每一行,ROWNUM 伪列返回一个 指示 Oracle 从 a 中选择行的顺序的数字 表或一组连接的行。选择的第一行的 ROWNUM 为 1, 第二个有 2,依此类推。

    ROWNUM 是结果集而不是查询的一个因素。尽管这些是相互联系的,但它们并不完全相同;如果第一个结果不存在,则第 6th 个结果不可能存在。

    这在文档中也有解释:

    对大于正整数的 ROWNUM 值进行条件测试 总是假的。例如,此查询不返回任何行:

    SELECT *
      FROM employees
      WHERE ROWNUM > 1;
    

    获取的第一行的 ROWNUM 为 1,并使 条件为假。要获取的第二行现在是第一行,并且 还分配了 1 的 ROWNUM 并使条件为假。所有行 随后不满足条件,因此不返回任何行。

    【讨论】:

    • 我知道 rownum 与结果集有关。在这里,使用 level 而不是 rownum 给出了相同的结果。我不明白的是为什么第二个查询的结果是 1。
    • 我不想通过第二个查询来实现任何目标。我只是无法理解查询中的“父”和“子”。 oracle 如何解释查询?
    • 第二个查询的结果是 1,原因是我的回答中的文档引用的。在查询中,“父”是您从单行表中选择的前一行。子项始终是当前行。
    • 什么是“上一个”和“当前”行?我相信 select level from dual 只给出一行?
    • 它确实是@Robik,但 CONNECT BY 是一个分层查询;当您从 DUAL 中选择时,您有一个初始子节点,然后连接会在此创建一个子节点。上一行在第一个实例中是对偶的,当前是 level + 1.,等等。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-10-12
    • 1970-01-01
    • 2016-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多