Lar*_*May 11 sql cycle hierarchy common-table-expression oracle11g
有没有人知道为什么当循环发生在顶级节点(根节点连接到根节点)时,Oracle继续遵循循环循环之外的路径?更重要的是,如何预防呢?
我有Oracle 11g第2版(11.2),我一直在探索分层查询.我将围绕Oracle数据库SQL语言参考第9-4页的图9-1中的树结构构建我的问题
我使用供应商和客户的概念为这棵树创建了一个表格结构:
create table t
( vendor varchar2(3)
, customer varchar2(3)
);
insert into t values ( '1' , '2' );
insert into t values ( '2' , '3' );
insert into t values ( '2' , '4' );
insert into t values ( '4' , '5' );
insert into t values ( '4' , '6' );
insert into t values ( '1' , '7' );
insert into t values ( '7' , '8' );
insert into t values ( '1' , '9' );
insert into t values ( '9' , '10' );
insert into t values ( '10' , '11' );
insert into t values ( '9' , '12' );
commit;
Run Code Online (Sandbox Code Playgroud)
以下select查询遍历树没有问题:
select vendor,
customer,
level,
connect_by_isleaf as isleaf,
connect_by_iscycle as iscycle,
connect_by_root vendor||sys_connect_by_path(customer,' ~ ') as path
from t
connect by nocycle
vendor=prior customer
start with vendor='1';
Run Code Online (Sandbox Code Playgroud)
给出结果:
Vendor Cust Level Isleaf Iscycle Path
1 2 1 0 0 1 ~ 2
2 3 2 1 0 1 ~ 2 ~ 3
2 4 2 0 0 1 ~ 2 ~ 4
4 5 3 1 0 1 ~ 2 ~ 4 ~ 5
4 6 3 1 0 1 ~ 2 ~ 4 ~ 6
1 7 1 0 0 1 ~ 7
7 8 2 1 0 1 ~ 7 ~ 8
1 9 1 0 0 1 ~ 9
9 10 2 0 0 1 ~ 9 ~ 10
10 11 3 1 0 1 ~ 9 ~ 10 ~ 11
9 12 2 1 0 1 ~ 9 ~ 12
Run Code Online (Sandbox Code Playgroud)
然后我通过在结构中添加循环来复杂化.首先是销售给自己的供应商的记录......
--self cycle
insert into t values ( '4' , '4' );
Run Code Online (Sandbox Code Playgroud)
还有一个供应商,其中客户是其供应商的供应商......
--ancestor cycle
insert into t values ( '6' , '2' );
Run Code Online (Sandbox Code Playgroud)
重新执行上面的选择查询导致与上面相同的输出,除了第3行和第5行(路径1~2~4和1~2~4~6)的Iscycle为1.请注意,CONNECT BY命名法标记循环的父记录而不是实际完成循环的子记录.(所以我知道4和6都循环回祖先,但我不知道哪个祖先.)
再添加两条记录会在原始树的分支上创建一个更大的循环:
--cycle crossing branches of tree
insert into t values ( '6' , '9' );
insert into t values ( '11' , '2' );
Run Code Online (Sandbox Code Playgroud)
再次执行select查询会提供以下输出:
Vendor Customer Level Isleaf Iscycle Path
1 2 1 0 0 1 ~ 2
2 3 2 1 0 1 ~ 2 ~ 3
2 4 2 0 1 1 ~ 2 ~ 4
4 5 3 1 0 1 ~ 2 ~ 4 ~ 5
4 6 3 0 1 1 ~ 2 ~ 4 ~ 6
6 9 4 0 0 1 ~ 2 ~ 4 ~ 6 ~ 9
9 10 5 0 0 1 ~ 2 ~ 4 ~ 6 ~ 9 ~ 10
10 11 6 1 1 1 ~ 2 ~ 4 ~ 6 ~ 9 ~ 10 ~ 11
9 12 5 1 0 1 ~ 2 ~ 4 ~ 6 ~ 9 ~ 12
1 7 1 0 0 1 ~ 7
7 8 2 1 0 1 ~ 7 ~ 8
1 9 1 0 0 1 ~ 9
9 10 2 0 0 1 ~ 9 ~ 10
10 11 3 0 0 1 ~ 9 ~ 10 ~ 11
11 2 4 0 0 1 ~ 9 ~ 10 ~ 11 ~ 2
2 3 5 1 0 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 3
2 4 5 0 1 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 4
4 5 6 1 0 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 4 ~ 5
4 6 6 1 1 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 4 ~ 6
9 12 2 1 0 1 ~ 9 ~ 12
Run Code Online (Sandbox Code Playgroud)
输出继续如预期.所有循环都是flaged,并且在遇到循环时映射停止.
现在问题是孩子......让我们为根节点添加一个自循环,这与上面用节点4创建的第一个循环完全相同; 仅适用于节点1.
insert into t values ( '1' , '1' );
Run Code Online (Sandbox Code Playgroud)
这次Oracle按预期检测到节点1的循环(第一行标记为Iscycle设置为1); 然而,它继续经过这个循环并构建了两次整个树结构.第2行到第21行是行22到41的复制,节点1的循环预先放在路径的前面.
Vendor Customer Level Isleaf Iscycle Path
1 1 1 0 1 1 ~ 1
1 2 2 0 0 1 ~ 1 ~ 2
2 3 3 1 0 1 ~ 1 ~ 2 ~ 3
2 4 3 0 1 1 ~ 1 ~ 2 ~ 4
4 5 4 1 0 1 ~ 1 ~ 2 ~ 4 ~ 5
4 6 4 0 1 1 ~ 1 ~ 2 ~ 4 ~ 6
6 9 5 0 0 1 ~ 1 ~ 2 ~ 4 ~ 6 ~ 9
9 10 6 0 0 1 ~ 1 ~ 2 ~ 4 ~ 6 ~ 9 ~ 10
10 11 7 1 1 1 ~ 1 ~ 2 ~ 4 ~ 6 ~ 9 ~ 10 ~ 11
9 12 6 1 0 1 ~ 1 ~ 2 ~ 4 ~ 6 ~ 9 ~ 12
1 7 2 0 0 1 ~ 1 ~ 7
7 8 3 1 0 1 ~ 1 ~ 7 ~ 8
1 9 2 0 0 1 ~ 1 ~ 9
9 10 3 0 0 1 ~ 1 ~ 9 ~ 10
10 11 4 0 0 1 ~ 1 ~ 9 ~ 10 ~ 11
11 2 5 0 0 1 ~ 1 ~ 9 ~ 10 ~ 11 ~ 2
2 3 6 1 0 1 ~ 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 3
2 4 6 0 1 1 ~ 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 4
4 5 7 1 0 1 ~ 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 4 ~ 5
4 6 7 1 1 1 ~ 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 4 ~ 6
9 12 3 1 0 1 ~ 1 ~ 9 ~ 12
1 2 1 0 0 1 ~ 2
2 3 2 1 0 1 ~ 2 ~ 3
2 4 2 0 1 1 ~ 2 ~ 4
4 5 3 1 0 1 ~ 2 ~ 4 ~ 5
4 6 3 0 1 1 ~ 2 ~ 4 ~ 6
6 9 4 0 0 1 ~ 2 ~ 4 ~ 6 ~ 9
9 10 5 0 0 1 ~ 2 ~ 4 ~ 6 ~ 9 ~ 10
10 11 6 1 1 1 ~ 2 ~ 4 ~ 6 ~ 9 ~ 10 ~ 11
9 12 5 1 0 1 ~ 2 ~ 4 ~ 6 ~ 9 ~ 12
1 7 1 0 0 1 ~ 7
7 8 2 1 0 1 ~ 7 ~ 8
1 9 1 0 0 1 ~ 9
9 10 2 0 0 1 ~ 9 ~ 10
10 11 3 0 0 1 ~ 9 ~ 10 ~ 11
11 2 4 0 0 1 ~ 9 ~ 10 ~ 11 ~ 2
2 3 5 1 0 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 3
2 4 5 0 1 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 4
4 5 6 1 0 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 4 ~ 5
4 6 6 1 1 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 4 ~ 6
9 12 2 1 0 1 ~ 9 ~ 12
Run Code Online (Sandbox Code Playgroud)
为什么1-1循环的处理与4-4循环不相同?我错过了什么?
为了减轻这种影响,我在CONNECT BY子句中添加了一个附加条件,要求客户不是'1'.
select vendor,
customer,
level,
connect_by_isleaf as isleaf,
connect_by_iscycle as iscycle,
connect_by_root vendor||sys_connect_by_path(customer,' ~ ') as path
from t
connect by nocycle
vendor=prior customer
and customer<>'1'
start with vendor='1';
Run Code Online (Sandbox Code Playgroud)
具有讽刺意味的是,所有这一切都是从第一行中删除循环标志.
任何帮助,将不胜感激.
Oracle 选择root row(s)
层次结构的行(满足 START WITH 条件的行)。Oracle 选择每个根行的子行。每个子行必须满足CONNECT BY
相对于根行之一的条件。
为了查找父行的子行,Oracle 会计算父行的 CONNECT BY 条件的 PRIOR 表达式以及表中每行的另一个表达式。条件为真的行是父行的子行。该CONNECT BY
条件可以包含其他条件以进一步过滤查询所选择的行。
A root row is the highest row within an inverted tree.
Run Code Online (Sandbox Code Playgroud)
如果您尝试使用相同的父级作为子级(22或33或44),它将起作用,因为它们不是根行而只是父级由于1是根并且也是具有1的子级,因此由于CONNECT_BY_ROOT子句,LEVEL被设置为循环
此后也出现了输出重复connect by works on root which is duplicated
。
Oracle is not able to restrict the uniqueness since Oracle can't give preference to one of the other
Run Code Online (Sandbox Code Playgroud)
要么使您的数据集唯一,要么对其进行编码,以便 Oracle 可以按层次结构中的偏好工作
跟进:OP 问题的解决方案
SELECT
VENDOR,
CUSTOMER,
LEVEL,
CONNECT_BY_ISLEAF AS ISLEAF,
CONNECT_BY_ISCYCLE AS ISCYCLE,
CONNECT_BY_ROOT VENDOR
|| SYS_CONNECT_BY_PATH ( CUSTOMER,
' ~ ' )
AS PATH
FROM
(SELECT
VENDOR,
CUSTOMER
FROM
T
WHERE
CUSTOMER <> '1')
CONNECT BY
NOCYCLE VENDOR = PRIOR CUSTOMER
START WITH
VENDOR = '1';
Run Code Online (Sandbox Code Playgroud)
结果:
VENDOR CUSTOMER LEVEL ISLEAF ISCYCLE PATH
------ -------- ---------- ---------- ------------------------------------------------------------------------------------------
1 2 1 0 0 1 ~ 2
2 3 2 1 0 1 ~ 2 ~ 3
2 4 2 0 1 1 ~ 2 ~ 4
4 5 3 1 0 1 ~ 2 ~ 4 ~ 5
4 6 3 0 1 1 ~ 2 ~ 4 ~ 6
6 9 4 0 0 1 ~ 2 ~ 4 ~ 6 ~ 9
9 10 5 0 0 1 ~ 2 ~ 4 ~ 6 ~ 9 ~ 10
10 11 6 1 1 1 ~ 2 ~ 4 ~ 6 ~ 9 ~ 10 ~ 11
9 12 5 1 0 1 ~ 2 ~ 4 ~ 6 ~ 9 ~ 12
1 7 1 0 0 1 ~ 7
7 8 2 1 0 1 ~ 7 ~ 8
1 9 1 0 0 1 ~ 9
9 10 2 0 0 1 ~ 9 ~ 10
10 11 3 0 0 1 ~ 9 ~ 10 ~ 11
11 2 4 0 0 1 ~ 9 ~ 10 ~ 11 ~ 2
2 3 5 1 0 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 3
2 4 5 0 1 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 4
4 5 6 1 0 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 4 ~ 5
4 6 6 1 1 1 ~ 9 ~ 10 ~ 11 ~ 2 ~ 4 ~ 6
9 12 2 1 0 1 ~ 9 ~ 12
20 rows selected
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
11442 次 |
最近记录: |