Oracle 表依赖项的递归查询没有I';I’我想要
我有一个想法,我可以编写一个查询,根据外键查找根表的所有子表 查询如下所示:Oracle 表依赖项的递归查询没有I';I’我想要,oracle,recursion,oracle10g,recursive-query,Oracle,Recursion,Oracle10g,Recursive Query,我有一个想法,我可以编写一个查询,根据外键查找根表的所有子表 查询如下所示: select level, lpad(' ', 2 * (level - 1)) || uc.table_name as "TABLE", uc.constraint_name, uc.r_constraint_name from all_constraints uc where uc.constraint_type in ('R', 'P') start with uc.table_name = 'ROOT_TAB'
select level, lpad(' ', 2 * (level - 1)) || uc.table_name as "TABLE", uc.constraint_name, uc.r_constraint_name
from all_constraints uc
where uc.constraint_type in ('R', 'P')
start with uc.table_name = 'ROOT_TAB'
connect by nocycle prior uc.constraint_name = uc.r_constraint_name
order by level asc;
1 ROOT_TAB XPKROOTTAB
1 ROOT_TAB R_20 XPKPART_TAB
2 CHILD_TAB_1 R_40 XPKROOTTAB
2 CHILD_TAB_2 R_115 XPKROOTTAB
2 CHILD_TAB_3 R_50 XPKROOTTAB
select t.table_name, level,lpad(' ', 2 * (level - 1))||t.table_name
from user_tables t
join user_constraints c1
on (t.table_name = c1.table_name
and c1.constraint_type in ('U', 'P'))
left join user_constraints c2
on (t.table_name = c2.table_name
and c2.constraint_type='R')
start with t.table_name = 'ROOT_TAB'
connect by prior c1.constraint_name = c2.r_constraint_name
我得到的结果如下所示:
select level, lpad(' ', 2 * (level - 1)) || uc.table_name as "TABLE", uc.constraint_name, uc.r_constraint_name
from all_constraints uc
where uc.constraint_type in ('R', 'P')
start with uc.table_name = 'ROOT_TAB'
connect by nocycle prior uc.constraint_name = uc.r_constraint_name
order by level asc;
1 ROOT_TAB XPKROOTTAB
1 ROOT_TAB R_20 XPKPART_TAB
2 CHILD_TAB_1 R_40 XPKROOTTAB
2 CHILD_TAB_2 R_115 XPKROOTTAB
2 CHILD_TAB_3 R_50 XPKROOTTAB
select t.table_name, level,lpad(' ', 2 * (level - 1))||t.table_name
from user_tables t
join user_constraints c1
on (t.table_name = c1.table_name
and c1.constraint_type in ('U', 'P'))
left join user_constraints c2
on (t.table_name = c2.table_name
and c2.constraint_type='R')
start with t.table_name = 'ROOT_TAB'
connect by prior c1.constraint_name = c2.r_constraint_name
1根选项卡XPKROOTTAB
1根选项卡R\u 20 XPKPART选项卡
2个儿童选项卡1个R\U 40 XPKROOTTAB
2子标签2 R 115 XPKROOTTAB
2个儿童标签3个R 50 XPKROOTTAB
此结果是ROOT\u TAB
的所有子表,但查询不会递归到child\u TAB\u 1
、child\u TAB\u 2
或child\u TAB\u 3
的子表
递归查询对我来说是新的,所以我猜我在
connectby
子句中遗漏了一些东西,但是我在这里画了一个空白。实际上,是否可以在一个查询中获得根选项卡的完整层次结构,还是最好将查询包装在递归过程中?您希望这样:
select level, lpad(' ', 2 * (level - 1)) || uc.table_name as "TABLE", uc.constraint_name, uc.r_constraint_name
from all_constraints uc
where uc.constraint_type in ('R', 'P')
start with uc.table_name = 'ROOT_TAB'
connect by nocycle prior uc.constraint_name = uc.r_constraint_name
order by level asc;
1 ROOT_TAB XPKROOTTAB
1 ROOT_TAB R_20 XPKPART_TAB
2 CHILD_TAB_1 R_40 XPKROOTTAB
2 CHILD_TAB_2 R_115 XPKROOTTAB
2 CHILD_TAB_3 R_50 XPKROOTTAB
select t.table_name, level,lpad(' ', 2 * (level - 1))||t.table_name
from user_tables t
join user_constraints c1
on (t.table_name = c1.table_name
and c1.constraint_type in ('U', 'P'))
left join user_constraints c2
on (t.table_name = c2.table_name
and c2.constraint_type='R')
start with t.table_name = 'ROOT_TAB'
connect by prior c1.constraint_name = c2.r_constraint_name
原始查询的问题是子表的uc.constraint\u name是外键的名称。这对于将第一个子表连接到根表来说很好,但是您不需要将第二级的子表连接到第一级。这就是为什么需要针对约束进行两次连接——一次获取表的主键,一次获取外键
另一方面,如果要查询所有视图而不是用户视图,则通常需要在表名称和所有者(而不仅仅是表名称)上连接它们。如果多个模式具有相同名称的表,则仅连接表_名称将给出不正确的结果 对于具有多个架构和多个根表的情况,请尝试以下操作:
WITH constraining_tables AS (SELECT owner, constraint_name, table_name
FROM all_constraints
WHERE owner LIKE 'ZZZ%' AND constraint_type IN ('U', 'P')),
constrained_tables AS (SELECT owner, constraint_name, table_name, r_owner, r_constraint_name
FROM all_constraints
WHERE owner LIKE 'ZZZ%' AND constraint_type = 'R'),
root_tables AS (SELECT owner, table_name FROM constraining_tables
MINUS
SELECT owner, table_name FROM constrained_tables)
SELECT c1.owner || '.' || c1.table_name, LEVEL, LPAD (' ', 2 * (LEVEL - 1)) || c1.owner || '.' || c1.table_name
FROM constraining_tables c1
LEFT JOIN
constrained_tables c2
ON c1.owner = c2.owner AND c1.table_name = c2.table_name
START WITH c1.owner || '.' || c1.table_name IN (SELECT owner || '.' || table_name FROM root_tables)
CONNECT BY PRIOR c1.constraint_name = c2.r_constraint_name
在深入调查之后,我制作了自己的版本来处理所有表,并在层次结构中检索表的最大级别(它读取所有模式,同时考虑到没有父子关系的表,这些表将与根表一起位于级别1)。如果您有访问权限,请使用dba表而不是所有表
WITH hier AS (
SELECT child_table owner_table_name
, LEVEL lvl
, LPAD (' ', 4 * (LEVEL - 1)) || child_table indented_child_table
, sys_connect_by_path( child_table, '|' ) tree
FROM (
/*----------------------------------------------------------------------*/
/* Retrieve all tables. Set them as the Child column, and set their */
/* Parent Column to NULL. This is the root list (first iteration) */
/*----------------------------------------------------------------------*/
SELECT NULL parent_table
, a.owner || '.' || a.table_name child_table
FROM all_tables a
UNION
/*----------------------------------------------------------------------*/
/* List of all possible Parent-Child relations. This table is used as */
/* a link list, to link the current iteration with the next one, from */
/* root to last child (last child is what we are interested to find). */
/*----------------------------------------------------------------------*/
SELECT p.owner || '.' || p.table_name parent_table
, c.owner || '.' || c.table_name child_table
FROM all_constraints p, all_constraints c
WHERE p.owner || '.' || p.constraint_name = c.r_owner || '.' || c.r_constraint_name
AND (p.constraint_type = 'P' OR p.constraint_type = 'U')
AND c.constraint_type = 'R'
)
START WITH parent_table IS NULL
/*----------------------------------------------------------------------*/
/* NOCYCLE prevents infinite loops (i.e. self referencing table constr) */
/*----------------------------------------------------------------------*/
CONNECT BY NOCYCLE PRIOR child_table = parent_table
)
SELECT *
FROM hier
WHERE (owner_table_name, lvl) IN ( SELECT owner_table_name
, MAX(lvl)
FROM hier
GROUP BY owner_table_name
);
编辑:
在查找无限循环时,此查询存在“某种”问题
如果我们有这棵树:
b --> c --> d
b <-- c
b-->c-->d
b c
第2级至b级为:c-->b
对于d,它将检测b-->c-->d
所以它会分配3级
如你所见,问题是在循环内部,外部的值总是有它的最大正确lvl是的,这似乎起到了作用。我只是发现了一个稍有不同的查询,它做了同样的事情:为什么要回滚我的编辑?@Air我喜欢其中的一些部分,但不喜欢其他部分。我没有看到一种方法可以选择性地回滚部分内容,所以我只是回滚了整个内容。你一开始为什么要做那个编辑?有什么不对劲吗?;)我在编辑摘要中解释了这一点。你不应该在标题前加标签(请参阅),你的文章有几个拼写错误,我觉得我可以让它更可读。执行选择性回滚的方法是,只需使用所需的反转进行新编辑。@Air:是的,我以后可能会使用我喜欢的编辑进行新编辑。。。