oracle递归避免循环

时间:2018-02-05 09:07:53

标签: sql oracle recursion cycle

以下查询是在https://www.tutorialspoint.com/execute_sql_online.php上开发的,并按设计工作:

WITH helptab1 
     AS (SELECT "a"    AS cust, 
                1      AS numb, 
                "m006" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "b"    AS cust, 
                1      AS numb, 
                "m006" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "b"    AS cust, 
                1      AS numb, 
                "m777" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "b"    AS cust, 
                2      AS numb, 
                "m018" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "c"    AS cust, 
                2      AS numb, 
                "m454" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "c"    AS cust, 
                5      AS numb, 
                "m008" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "c"    AS cust, 
                5      AS numb, 
                "m090" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "c"    AS cust, 
                6      AS numb, 
                "m789" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "c"    AS cust, 
                7      AS numb, 
                "m191" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "d"    AS cust, 
                9      AS numb, 
                "m006" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "d"    AS cust, 
                1      AS numb, 
                "m123" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "e"    AS cust, 
                3      AS numb, 
                "m567" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "f"    AS cust, 
                3      AS numb, 
                "m777" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "g"    AS cust, 
                3      AS numb, 
                "m888" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "g"    AS cust, 
                3      AS numb, 
                "m765" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "g"    AS cust, 
                4      AS numb, 
                "m543" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "h"    AS cust, 
                6      AS numb, 
                "m888" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "h"    AS cust, 
                6      AS numb, 
                "m090" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "h"    AS cust, 
                6      AS numb, 
                "m001" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "h"    AS cust, 
                7      AS numb, 
                "m008" AS val 
         FROM   dual 
         UNION ALL 
         SELECT "h"    AS cust, 
                7      AS numb, 
                "m090" AS val 
         FROM   dual), 
     helptab2 
     AS (SELECT /*+materialize */ DISTINCT cust, 
                                           numb, 
                                           val, 
                                           1 AS counter 
         FROM   helptab1 
         WHERE  val = "m765"), 
     basic (cust, numb, val, counter) 
     AS (SELECT DISTINCT cust, 
                         numb, 
                         val, 
                         1 
         FROM   helptab2 
         UNION ALL 
         SELECT DISTINCT hlp1.cust, 
                         hlp1.numb, 
                         hlp1.val, 
                         counter + 1 
         FROM   basic bas 
                join helptab1 hlp1 
                  ON ( hlp1.cust = bas.cust 
                       AND hlp1.numb = bas.numb ) 
                      OR ( hlp1.val = bas.val ) 
         WHERE  counter <= 10), 
     helptab3 
     AS (SELECT DISTINCT cust, 
                         numb, 
                         val, 
                         counter 
         FROM   basic 
         ORDER  BY cust, 
                   numb, 
                   val) 
SELECT DISTINCT cust, 
                numb, 
                val 
FROM   helptab3;  

但有两个问题,部分&#34;其中counter&lt; = 10&#34;并不是非常聪明,它无法在Oracle(12g)开发人员身上执行。它需要做什么才能在Oracle上运行?以及如何处理递归部分,所以没有限制也没有循环?

1 个答案:

答案 0 :(得分:0)

您的查询中的一些问题:

  • 文字字符串需要用单引号分隔,而不是双引号。例如:'m765'而不是"m765"。后者被解释为列引用。
  • 在递归查询的递归(第二)部分中不允许
  • distinct。但是,由于您仍然在下一个distinct查询中应用了with,因此您可以在没有它的情况下生活,但会带来巨大的性能成本。注意:在查询的第一部分中不需要distinct,正如您在helptab2
  • 中所做的那样
  • 要使counter <= 10在递归查询中工作,它确实需要是一个连接条件,而不是where子句中的条件。

应用这些更改后,查询会起作用,但显然会变得很慢,因为递归部分会收集许多相同的记录并递归到循环中。

可以使用递归cycle查询后面的with子句来阻止循环:

with helptab1 as ( 
        select 'A' as cust, 1 as numb, 'm006' as val from dual union all 
        select 'B' as cust, 1 as numb, 'm006' as val from dual union all 
        select 'B' as cust, 1 as numb, 'm777' as val from dual union all 
        select 'B' as cust, 2 as numb, 'm018' as val from dual union all 
        select 'C' as cust, 2 as numb, 'm454' as val from dual union all
        select 'C' as cust, 5 as numb, 'm008' as val from dual union all
        select 'C' as cust, 5 as numb, 'm090' as val from dual union all
        select 'C' as cust, 6 as numb, 'm789' as val from dual union all
        select 'C' as cust, 7 as numb, 'm191' as val from dual union all
        select 'D' as cust, 9 as numb, 'm006' as val from dual union all
        select 'D' as cust, 1 as numb, 'm123' as val from dual union all
        select 'E' as cust, 3 as numb, 'm567' as val from dual union all
        select 'F' as cust, 3 as numb, 'm777' as val from dual union all
        select 'G' as cust, 3 as numb, 'm888' as val from dual union all
        select 'G' as cust, 3 as numb, 'm765' as val from dual union all
        select 'G' as cust, 4 as numb, 'm543' as val from dual union all
        select 'H' as cust, 6 as numb, 'm888' as val from dual union all
        select 'H' as cust, 6 as numb, 'm090' as val from dual union all
        select 'H' as cust, 6 as numb, 'm001' as val from dual union all
        select 'H' as cust, 7 as numb, 'm008' as val from dual union all
        select 'H' as cust, 7 as numb, 'm090' as val from dual), 
    basic (cust,numb,val) as (
        select distinct cust, numb, val
        from   helptab1
        where  val = 'm765' 
        union all
        select hlp1.cust, hlp1.numb, hlp1.val
        from   basic bas 
        join   helptab1 hlp1 
                on hlp1.cust = bas.cust and hlp1.numb = bas.numb
                or hlp1.val = bas.val)
        cycle cust, numb, val set cycle to 1 default 0
    select   distinct cust, numb, val
    from     basic;

对于具有connect by选项的分层查询的替代nocycles语法,也可以这样做:

with helptab1 as ( 
        select 'A' as cust, 1 as numb, 'm006' as val from dual union all 
        select 'B' as cust, 1 as numb, 'm006' as val from dual union all 
        select 'B' as cust, 1 as numb, 'm777' as val from dual union all 
        select 'B' as cust, 2 as numb, 'm018' as val from dual union all 
        select 'C' as cust, 2 as numb, 'm454' as val from dual union all
        select 'C' as cust, 5 as numb, 'm008' as val from dual union all
        select 'C' as cust, 5 as numb, 'm090' as val from dual union all
        select 'C' as cust, 6 as numb, 'm789' as val from dual union all
        select 'C' as cust, 7 as numb, 'm191' as val from dual union all
        select 'D' as cust, 9 as numb, 'm006' as val from dual union all
        select 'D' as cust, 1 as numb, 'm123' as val from dual union all
        select 'E' as cust, 3 as numb, 'm567' as val from dual union all
        select 'F' as cust, 3 as numb, 'm777' as val from dual union all
        select 'G' as cust, 3 as numb, 'm888' as val from dual union all
        select 'G' as cust, 3 as numb, 'm765' as val from dual union all
        select 'G' as cust, 4 as numb, 'm543' as val from dual union all
        select 'H' as cust, 6 as numb, 'm888' as val from dual union all
        select 'H' as cust, 6 as numb, 'm090' as val from dual union all
        select 'H' as cust, 6 as numb, 'm001' as val from dual union all
        select 'H' as cust, 7 as numb, 'm008' as val from dual union all
        select 'H' as cust, 7 as numb, 'm090' as val from dual), 
    basic as (
        select     cust, numb, val
        from       helptab1
        connect by nocycle
                   prior cust = cust and prior numb = numb
                or prior val = val
        start with val = 'm765')
    select   distinct cust, numb, val
    from     basic;