如何在 Oracle 中使用 WITH 而不是 CONNECT BY 获得递归 SQL 的深度?
How to get depth of recursive SQL using WITH rather than CONNECT BY in Oracle?
这个简单的例子table将说明递归关系...
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;
使用 Oracle 12c 和许多版本都有的功能,我可以使用 CONNECT BY 和 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;
伪列 LEVEL 可以了解递归的深度并缩进结果。
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.
我相信从 11g 开始,Oracle 就允许编码人员使用 WITH 子句来创建递归查询。
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;
但是,LEVEL 伪列似乎无法缩进输出。
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.
是否有使用 LEVEL 或其他替代方法的方法,以便我可以使用 WITH 子句缩进并获得类似于 CONNECT BY、START WITH 方法的输出?
以下是如何克隆 LEVEL 伪列(用于缩进)以及在使用递归 WITH 子句时分层 CONNECT BY 查询的深度优先顺序。您可能想看看当您删除递归子查询后的 SEARCH... 子句和末尾的 ORDER BY 子句时会发生什么 - 查看输出受到何种影响。
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
然后您可以在 ORDER BY 子句中添加关键字 DESC(用于降序排序,而不是默认的升序排序)- 在 ord
之后(几乎肯定不是您想要的!),或者在删除之后ORDER BY 子句中的 DESC,将其添加到 SEARCH 子句中的 name
之后。您将看到在输出中添加 DESC 关键字的位置有何不同。如果需要,这些都是您将来可以使用的选项。您可能还想尝试在 SEARCH 子句中使用 KEY 而不是 NAME - 看看会导致什么变化。
这个简单的例子table将说明递归关系...
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;
使用 Oracle 12c 和许多版本都有的功能,我可以使用 CONNECT BY 和 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;
伪列 LEVEL 可以了解递归的深度并缩进结果。
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.
我相信从 11g 开始,Oracle 就允许编码人员使用 WITH 子句来创建递归查询。
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;
但是,LEVEL 伪列似乎无法缩进输出。
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.
是否有使用 LEVEL 或其他替代方法的方法,以便我可以使用 WITH 子句缩进并获得类似于 CONNECT BY、START WITH 方法的输出?
以下是如何克隆 LEVEL 伪列(用于缩进)以及在使用递归 WITH 子句时分层 CONNECT BY 查询的深度优先顺序。您可能想看看当您删除递归子查询后的 SEARCH... 子句和末尾的 ORDER BY 子句时会发生什么 - 查看输出受到何种影响。
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
然后您可以在 ORDER BY 子句中添加关键字 DESC(用于降序排序,而不是默认的升序排序)- 在 ord
之后(几乎肯定不是您想要的!),或者在删除之后ORDER BY 子句中的 DESC,将其添加到 SEARCH 子句中的 name
之后。您将看到在输出中添加 DESC 关键字的位置有何不同。如果需要,这些都是您将来可以使用的选项。您可能还想尝试在 SEARCH 子句中使用 KEY 而不是 NAME - 看看会导致什么变化。