简体   繁体   中英

How to get depth of recursive SQL using WITH rather than CONNECT BY in Oracle?

This simple example table will illustrate the recursive relationship...

CREATE TABLE tree
    (
    key NUMBER(5) NOT NULL PRIMARY KEY,
    name VARCHAR(15) NOT NULL,
    treeHier NUMBER(5)
    );

INSERT INTO tree VALUES('11','Software',NULL);
INSERT INTO tree VALUES('22','OS','11');
INSERT INTO tree VALUES('33','Linux','22');
INSERT INTO tree VALUES('44','Windows','22');
INSERT INTO tree VALUES('55','DB','11');
INSERT INTO tree VALUES('66','Oracle','55');
INSERT INTO tree VALUES('77','MS-SQL','55');

COMMIT;

Using Oracle 12c and a feature that has been around for many versions, I can make a recursive query to get all the child nodes using CONNECT BY and START WITH.

SELECT
    LPAD(' ',LEVEL*2,' ')||' '||
    name||' '||
    key||' '||
    NVL(TO_CHAR(treeHier),'NULL')
FROM
    tree
START WITH
    key = 11
CONNECT BY
    treeHier = PRIOR key
ORDER BY
    key ASC;

The pseudo column LEVEL makes it possible to know the depth of the recursion and indent the result.

   Software 11 NULL
     OS 22 11
       Linux 33 22
       Windoze 44 22
     DB 55 11
       Oracle 66 55
       MS-SQL 77 55

7 rows selected.

Since 11g I believe, Oracle has allowed coders to use the WITH clause to create recursive queries.

WITH myRecurse(key,name,treeHier) AS
    (
        SELECT
            tree.key, tree.name, tree.treeHier
        FROM
            tree
        WHERE
            tree.key = 11
    UNION ALL
        SELECT
            tree.key, tree.name, tree.treeHier
        FROM
            tree
        JOIN
            myRecur ON tree.treeHier= myRecurse.key
        ORDER BY
            3 DESC
    )
SELECT
    name||' '||
    key||' '||
    NVL(TO_CHAR(treeHier),'NULL')
FROM
    myRecurse;

However, the LEVEL pseudo column appears to be unavailable to indent the output.

Software 11 NULL
OS 22 11
DB 55 11
Linux 33 22
Windoze 44 22
Oracle 66 55
MS-SQL 77 55

7 rows selected.

Is there a methodology to use LEVEL or some alternative so I can indent using the WITH clause and get output that looks like the CONNECT BY, START WITH method?

Here is how you can clone the LEVEL pseudo-column (to use for indentation) as well as the DEPTH FIRST ordering of hierarchical CONNECT BY queries when you use the recursive WITH clause. You may want to see what happens when you remove the SEARCH... clause after the recursive subquery and the ORDER BY clause at the end - see in what way the output is affected.

with r ( lvl, key, name, treehier ) as (
         select  1, key, name, treehier
           from  tree
           where treehier is null
         union all
         select  r.lvl + 1, t.key, t.name, r.key
         from    r join tree t on r.key = t.treehier
       )
       search depth first by name set ord
select   rpad(' ', 2 * (lvl - 1), ' ') || name as name, key, treehier
from     r
order by ord
;

NAME                                  KEY   TREEHIER
------------------------------ ---------- ----------
Software                               11           
  DB                                   55         11
    MS-SQL                             77         55
    Oracle                             66         55
  OS                                   22         11
    Linux                              33         22
    Windows                            44         22

Then you can add the keyword DESC (for descending sort, instead of the default ascending sort) - in the ORDER BY clause, after ord (almost certainly NOT what you want!) or, after deleting DESC from the ORDER BY clause, add it after name in the SEARCH clause. You will see what difference WHERE you add the DESC keyword makes in the output. These are all options that will be available to you in the future, if needed. You may also want to experiment by using KEY instead of NAME in the SEARCH clause - see what changes that will cause.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM