使用递归查询构建表依赖图

Posted

技术标签:

【中文标题】使用递归查询构建表依赖图【英文标题】:Building a Table Dependency Graph With A Recursive Query 【发布时间】:2010-09-10 09:56:21 【问题描述】:

我正在尝试基于它们之间的外键构建表的依赖关系图。该图需要以任意表名作为其根开始。我可以,给定一个表名,使用 all_constraints 视图查找引用它的表,然后查找引用它们的表,依此类推,但这会非常低效。我编写了一个递归查询,对所有表执行此操作,但是当我添加时:

START WITH Table_Name=:tablename

它不会返回整个树。

【问题讨论】:

【参考方案1】:
    select parent, child, level from (
select parent_table.table_name parent, child_table.table_name child
 from user_tables      parent_table,
      user_constraints parent_constraint,
      user_constraints child_constraint,
      user_tables      child_table
where parent_table.table_name = parent_constraint.table_name
  and parent_constraint.constraint_type IN( 'P', 'U' )
  and child_constraint.r_constraint_name = parent_constraint.constraint_name
  and child_constraint.constraint_type   = 'R'
  and child_table.table_name = child_constraint.table_name
  and child_table.table_name != parent_table.table_name
)
start with parent = 'DEPT'
connect by prior child = parent

假设一切都在同一个模式中,应该可以工作(当然,替换表名)。如果您需要处理跨模式依赖关系,请为 OWNER 和 R_OWNER 列使用数据字典表和条件的 DBA_ 版本。进一步思考,这也没有考虑自引用约束(即 MGR 列引用 EMPNO 列的 EMP 表上的约束),因此如果需要处理,您必须修改代码以处理这种情况具有自引用约束。

出于测试目的,我在 SCOTT 架构中添加了一些新表,这些表也引用了 DEPT 表(包括孙子依赖项)

SQL> create table dept_child2 (
  2  deptno number references dept( deptno )
  3  );

Table created.

SQL> create table dept_child3 (
  2    dept_child3_no number primary key,
  3    deptno number references dept( deptno )
  4  );

Table created.

SQL> create table dept_grandchild (
  2    dept_child3_no number references dept_child3( dept_child3_no )
  3  );

Table created.

并验证查询返回了预期的输出

SQL> ed
Wrote file afiedt.buf

  1  select parent, child, level from (
  2  select parent_table.table_name parent, child_table.table_name child
  3   from user_tables      parent_table,
  4        user_constraints parent_constraint,
  5        user_constraints child_constraint,
  6        user_tables      child_table
  7  where parent_table.table_name = parent_constraint.table_name
  8    and parent_constraint.constraint_type IN( 'P', 'U' )
  9    and child_constraint.r_constraint_name = parent_constraint.constraint_name
 10    and child_constraint.constraint_type   = 'R'
 11    and child_table.table_name = child_constraint.table_name
 12    and child_table.table_name != parent_table.table_name
 13  )
 14  start with parent = 'DEPT'
 15* connect by prior child = parent
SQL> /

PARENT                         CHILD                               LEVEL
------------------------------ ------------------------------ ----------
DEPT                           DEPT_CHILD3                             1
DEPT_CHILD3                    DEPT_GRANDCHILD                         2
DEPT                           DEPT_CHILD2                             1
DEPT                           EMP                                     1

【讨论】:

当我运行该查询时,我得到ORA-01437: cannot have join with CONNECT BY @user1598390 - 你是说当你运行我发布的确切测试用例时你得到一个错误?或者你正在做一些(甚至稍微)不同的事情?在没有看到您的代码的情况下,我们极不可能为您提供很多帮助。您可能需要创建一个新问题,您可以在其中发布您正在使用的确切查询,并且理想情况下,通过您发布的一些示例表显示它失败。 我复制您的 SQL,将其粘贴到 Oracle 客户端 (PL/SQL Developer),然后按 F8 运行它,然后得到错误。 @user1598390 - 好的,所以您使用默认的 SCOTT 架构,您创建了我在此处创建的表,并运行与我发布的完全相同的 SQL 语句以获取 @987654326 的依赖项@ 桌子?如您所见,它对我有用。您使用的是什么版本的 Oracle? 不,我正在使用具有大量表和依赖项的真实生产模式。 Oracle 版本为 8.1.7。【参考方案2】:

最简单的方法是将所有 FK 信息复制到一个简单的 2 列(父、子)表中,然后使用以下算法:

while (rows left in that table)
  list = rows where table name exists in child but not in parent
  print list
  remove list from rows

就是这样。基本上,您首先打印并删除所有不依赖任何内容的节点。完成后,其他一些节点将被释放,您可以重复该过程。

附:确保不要在初始列表中插入自引用表(child=parent)

【讨论】:

以上是关于使用递归查询构建表依赖图的主要内容,如果未能解决你的问题,请参考以下文章

使用递归查询访问有向图,就好像它是无向图一样

在自引用表上编写递归 SQL 查询

Oracle树形表和递归查询

SQL递归查询知多少

「SQL归纳」树形结构表的存储与查询功能的实现——通过路径方法(非递归)

mysql查询一个表,实现递归查询