connect-by-prior:使用 PRIOR 向上钻取 2 层
connect-by-prior: using PRIOR to drill 2-levels up
我有以下先验连接SQL,它基本上从叶节点开始,沿着树向上延伸到父“tree-trunc”(级别 1):
with my_tree as (
select 'level 4.1' node, 'level 3.1' parent_node from dual union
select 'level 4.2' node, 'level 3.2' parent_node from dual union
select 'level 3.1' node, 'level 2' parent_node from dual union
select 'level 3.2' node, 'level 2' parent_node from dual union
select 'level 2' node, 'level 1' parent_node from dual union
select 'level 1' node, '' parent_node from dual
)
select level, t.node, t.parent_node, prior t.node child_that_pointed_me_here
from my_tree t
connect by t.node = prior t.parent_node
start with t.node like 'level 4%'
它给我以下输出:
level node parent_node child_who_pointed_me_here
----- --------- ----------- -------------------------
1 level 4.1 level 3.1
2 level 3.1 level 2 level 4.1
3 level 2 level 1 level 3.1
4 level 1 level 2
1 level 4.2 level 3.2
2 level 3.2 level 2 level 4.2
3 level 2 level 1 level 3.2
4 level 1 level 2
您可以看到指令 prior t.node
(别名为列 child_who_pointed_me_here
)将我带到“先前”记录中的数据(即我开始的子节点),它正是我想要的。换句话说,PRIOR
关键字让我可以访问“上一个”记录中的数据。
但我想要访问前 2 级(或 3 或 4 级)的数据。像 prior prior t.node
这样的东西。所需的输出如下所示:
level node parent_node child_who_pointed_me_here grandchild_who_pointed_me_here
----- --------- ----------- ------------------------- ------------------------------
1 level 4.1 level 3.1
2 level 3.1 level 2 level 4.1
3 level 2 level 1 level 3.1 level 4.1
4 level 1 level 2 level 3.1
1 level 4.2 level 3.2
2 level 3.2 level 2 level 4.2
3 level 2 level 1 level 3.2 level 4.2
4 level 1 level 2 level 3.2
我已经尝试了明显的 prior prior t.node
,但它显然只会导致不支持的语法类型错误。
因此问题是: connect-by SQL 中是否有一个构造允许我沿着路径向后(或向上)返回 2 个级别?
我正在使用 Oracle 12c 来构造这个 SQL,但是任何 SQL 风格的答案都值得赞赏。
sys_connect_by_path 将为您提供从到达当前行的位置开始的整个谱系。
我通过反转和选择第二个“/”和第三个“/”的索引位置来对 sys_connect_by_path 执行字符串操作,以提取中间的数据
使用此字符串,我们可以使用以下内容提取 2 层,如下所示。
with my_tree as (
select 'level 4.1' node, 'level 3.1' parent_node from dual union
select 'level 4.2' node, 'level 3.2' parent_node from dual union
select 'level 3.1' node, 'level 2' parent_node from dual union
select 'level 3.2' node, 'level 2' parent_node from dual union
select 'level 2' node, 'level 1' parent_node from dual union
select 'level 1' node, '' parent_node from dual
)
select level, t.node, t.parent_node, prior t.node child_that_pointed_me_here
,sys_connect_by_path(t.node,'/') as lineage
,rtrim(
reverse(
substr(
reverse(sys_connect_by_path(t.node,'/'))
,instr(reverse(sys_connect_by_path(t.node,'/')),'/',1,2)
,instr(reverse(sys_connect_by_path(t.node,'/')),'/',1,3)
-
instr(reverse(sys_connect_by_path(t.node,'/')),'/',1,2)
)
)
,'/') as two_level_up
from my_tree t
connect by t.node = prior t.parent_node
start with t.node like 'level 4%'
+-------+-----------+-------------+----------------------------+--------------------------------------+--------------+
| LEVEL | NODE | PARENT_NODE | CHILD_THAT_POINTED_ME_HERE | LINEAGE | TWO_LEVEL_UP |
+-------+-----------+-------------+----------------------------+--------------------------------------+--------------+
| 1 | level 4.1 | level 3.1 | null | /level 4.1 | |
| 2 | level 3.1 | level 2 | level 4.1 | /level 4.1/level 3.1 | |
| 3 | level 2 | level 1 | level 3.1 | /level 4.1/level 3.1/level 2 | level 4.1 |
| 4 | level 1 | | level 2 | /level 4.1/level 3.1/level 2/level 1 | level 3.1 |
| 1 | level 4.2 | level 3.2 | | /level 4.2 | |
| 2 | level 3.2 | level 2 | level 4.2 | /level 4.2/level 3.2 | |
| 3 | level 2 | level 1 | level 3.2 | /level 4.2/level 3.2/level 2 | level 4.2 |
| 4 | level 1 | | level 2 | /level 4.2/level 3.2/level 2/level 1 | level 3.2 |
+-------+-----------+-------------+----------------------------+--------------------------------------+--------------+
dbfiddle
https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=0448131cc387e52eab3126dfce0a7cde
我有以下先验连接SQL,它基本上从叶节点开始,沿着树向上延伸到父“tree-trunc”(级别 1):
with my_tree as (
select 'level 4.1' node, 'level 3.1' parent_node from dual union
select 'level 4.2' node, 'level 3.2' parent_node from dual union
select 'level 3.1' node, 'level 2' parent_node from dual union
select 'level 3.2' node, 'level 2' parent_node from dual union
select 'level 2' node, 'level 1' parent_node from dual union
select 'level 1' node, '' parent_node from dual
)
select level, t.node, t.parent_node, prior t.node child_that_pointed_me_here
from my_tree t
connect by t.node = prior t.parent_node
start with t.node like 'level 4%'
它给我以下输出:
level node parent_node child_who_pointed_me_here
----- --------- ----------- -------------------------
1 level 4.1 level 3.1
2 level 3.1 level 2 level 4.1
3 level 2 level 1 level 3.1
4 level 1 level 2
1 level 4.2 level 3.2
2 level 3.2 level 2 level 4.2
3 level 2 level 1 level 3.2
4 level 1 level 2
您可以看到指令 prior t.node
(别名为列 child_who_pointed_me_here
)将我带到“先前”记录中的数据(即我开始的子节点),它正是我想要的。换句话说,PRIOR
关键字让我可以访问“上一个”记录中的数据。
但我想要访问前 2 级(或 3 或 4 级)的数据。像 prior prior t.node
这样的东西。所需的输出如下所示:
level node parent_node child_who_pointed_me_here grandchild_who_pointed_me_here
----- --------- ----------- ------------------------- ------------------------------
1 level 4.1 level 3.1
2 level 3.1 level 2 level 4.1
3 level 2 level 1 level 3.1 level 4.1
4 level 1 level 2 level 3.1
1 level 4.2 level 3.2
2 level 3.2 level 2 level 4.2
3 level 2 level 1 level 3.2 level 4.2
4 level 1 level 2 level 3.2
我已经尝试了明显的 prior prior t.node
,但它显然只会导致不支持的语法类型错误。
因此问题是: connect-by SQL 中是否有一个构造允许我沿着路径向后(或向上)返回 2 个级别?
我正在使用 Oracle 12c 来构造这个 SQL,但是任何 SQL 风格的答案都值得赞赏。
sys_connect_by_path 将为您提供从到达当前行的位置开始的整个谱系。
我通过反转和选择第二个“/”和第三个“/”的索引位置来对 sys_connect_by_path 执行字符串操作,以提取中间的数据
使用此字符串,我们可以使用以下内容提取 2 层,如下所示。
with my_tree as (
select 'level 4.1' node, 'level 3.1' parent_node from dual union
select 'level 4.2' node, 'level 3.2' parent_node from dual union
select 'level 3.1' node, 'level 2' parent_node from dual union
select 'level 3.2' node, 'level 2' parent_node from dual union
select 'level 2' node, 'level 1' parent_node from dual union
select 'level 1' node, '' parent_node from dual
)
select level, t.node, t.parent_node, prior t.node child_that_pointed_me_here
,sys_connect_by_path(t.node,'/') as lineage
,rtrim(
reverse(
substr(
reverse(sys_connect_by_path(t.node,'/'))
,instr(reverse(sys_connect_by_path(t.node,'/')),'/',1,2)
,instr(reverse(sys_connect_by_path(t.node,'/')),'/',1,3)
-
instr(reverse(sys_connect_by_path(t.node,'/')),'/',1,2)
)
)
,'/') as two_level_up
from my_tree t
connect by t.node = prior t.parent_node
start with t.node like 'level 4%'
+-------+-----------+-------------+----------------------------+--------------------------------------+--------------+
| LEVEL | NODE | PARENT_NODE | CHILD_THAT_POINTED_ME_HERE | LINEAGE | TWO_LEVEL_UP |
+-------+-----------+-------------+----------------------------+--------------------------------------+--------------+
| 1 | level 4.1 | level 3.1 | null | /level 4.1 | |
| 2 | level 3.1 | level 2 | level 4.1 | /level 4.1/level 3.1 | |
| 3 | level 2 | level 1 | level 3.1 | /level 4.1/level 3.1/level 2 | level 4.1 |
| 4 | level 1 | | level 2 | /level 4.1/level 3.1/level 2/level 1 | level 3.1 |
| 1 | level 4.2 | level 3.2 | | /level 4.2 | |
| 2 | level 3.2 | level 2 | level 4.2 | /level 4.2/level 3.2 | |
| 3 | level 2 | level 1 | level 3.2 | /level 4.2/level 3.2/level 2 | level 4.2 |
| 4 | level 1 | | level 2 | /level 4.2/level 3.2/level 2/level 1 | level 3.2 |
+-------+-----------+-------------+----------------------------+--------------------------------------+--------------+
dbfiddle https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=0448131cc387e52eab3126dfce0a7cde