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.