在Oracle SQL Developer中,如果我正在查看一个表上的信息,我可以查看约束,这让我看到外键(因此这个表引用了哪些表),我可以查看依赖关系,看看哪些包引用了这个表。但是我不确定如何查找引用表的表。

例如,假设我正在查看emp表。还有一个表emp_dept,它捕获哪些员工在哪些部门工作,它通过emp表的主键emp_id引用emp表。是否有一种方法(通过程序中的某些UI元素,而不是通过SQL)来查找emp_dept表引用emp表,而不需要知道emp_dept表存在?


当前回答

替换下面的MY_OWNER_NAME和MY_TABLE_NAME,你就可以递归了:

DECLARE
FUNCTION list_all_child_tables_and_constraints(asked_table_name in VARCHAR2, parent_table_name in VARCHAR2)
RETURN VARCHAR2 IS
    current_path VARCHAR2(100);
BEGIN
    FOR item IN
    (SELECT fk.TABLE_NAME, constraint_parent.FK FK1, constraint_child.FK FK2
        FROM all_constraints fk, all_constraints pk,
            (SELECT acc.CONSTRAINT_NAME, LISTAGG(acc.COLUMN_NAME, ', ') WITHIN GROUP (ORDER BY acc.COLUMN_NAME) AS FK
                FROM ALL_CONS_COLUMNS acc
                WHERE acc.OWNER = 'MY_OWNER_NAME'
                GROUP BY acc.CONSTRAINT_NAME) constraint_parent,
            (SELECT acc.CONSTRAINT_NAME, LISTAGG(acc.COLUMN_NAME, ', ') WITHIN GROUP (ORDER BY acc.COLUMN_NAME) AS FK
                FROM ALL_CONS_COLUMNS acc
                WHERE acc.OWNER = 'MY_OWNER_NAME'
                GROUP BY acc.CONSTRAINT_NAME) constraint_child
        WHERE pk.owner = fk.r_owner
            AND pk.constraint_name = fk.r_constraint_name
            AND fk.constraint_type = 'R'
            AND pk.table_name = asked_table_name
            AND constraint_parent.CONSTRAINT_NAME = fk.CONSTRAINT_NAME
            AND constraint_child.CONSTRAINT_NAME = fk.R_CONSTRAINT_NAME
            AND pk.owner = 'MY_OWNER_NAME'
            AND fk.owner = 'MY_OWNER_NAME')
    LOOP
        current_path := parent_table_name || ' // ' || item.TABLE_NAME;
        DBMS_OUTPUT.PUT_LINE(current_path);
        DBMS_OUTPUT.PUT_LINE('     [' || item.FK1 || ']  [' || item.FK2 || ']');
        DBMS_OUTPUT.PUT_LINE('');
        current_path := list_all_child_tables_and_constraints(item.TABLE_NAME, current_path);

    END LOOP;
    RETURN '-----------FINISHED-----------';

EXCEPTION
    WHEN OTHERS THEN
        RETURN '-----------FINISHED-----------';
END list_all_child_tables_and_constraints;
BEGIN
DBMS_OUTPUT.PUT_LINE(list_all_child_tables_and_constraints('MY_TABLE_NAME', ''));
END;

其他回答

这样怎么样:

SELECT c.constraint_name, c.constraint_type, c2.constraint_name, c2.constraint_type, c2.table_name
  FROM dba_constraints c JOIN dba_constraints c2 ON (c.r_constraint_name = c2.constraint_name)
 WHERE c.table_name = <TABLE_OF_INTEREST>
   AND c.constraint_TYPE = 'R';

这已经在产品中存在多年了——尽管在2011年的产品中还没有。

但是,只需单击Model页面。

请确保您使用的版本至少为4.0(2013年发布)才能访问此功能。

我喜欢使用直接的SQL查询来实现这一点,而不是在SQL Developer应用程序中瞎折腾。

我是这么做的。最好通读这篇文章,了解发生了什么,这样你就可以调整它来满足你的需求……

WITH all_primary_keys AS (
  SELECT constraint_name AS pk_name,
         table_name
    FROM all_constraints
   WHERE owner = USER
     AND constraint_type = 'P'
)
  SELECT ac.table_name || ' table has a foreign key called ' || upper(ac.constraint_name)
         || ' which references the primary key ' || upper(ac.r_constraint_name) || ' on table ' || apk.table_name AS foreign_keys
    FROM all_constraints ac
         LEFT JOIN all_primary_keys apk
                ON ac.r_constraint_name = apk.pk_name
   WHERE ac.owner = USER
     AND ac.constraint_type = 'R'
     AND ac.table_name = nvl(upper(:table_name), ac.table_name)
ORDER BY ac.table_name, ac.constraint_name
;

替换下面的MY_OWNER_NAME和MY_TABLE_NAME,你就可以递归了:

DECLARE
FUNCTION list_all_child_tables_and_constraints(asked_table_name in VARCHAR2, parent_table_name in VARCHAR2)
RETURN VARCHAR2 IS
    current_path VARCHAR2(100);
BEGIN
    FOR item IN
    (SELECT fk.TABLE_NAME, constraint_parent.FK FK1, constraint_child.FK FK2
        FROM all_constraints fk, all_constraints pk,
            (SELECT acc.CONSTRAINT_NAME, LISTAGG(acc.COLUMN_NAME, ', ') WITHIN GROUP (ORDER BY acc.COLUMN_NAME) AS FK
                FROM ALL_CONS_COLUMNS acc
                WHERE acc.OWNER = 'MY_OWNER_NAME'
                GROUP BY acc.CONSTRAINT_NAME) constraint_parent,
            (SELECT acc.CONSTRAINT_NAME, LISTAGG(acc.COLUMN_NAME, ', ') WITHIN GROUP (ORDER BY acc.COLUMN_NAME) AS FK
                FROM ALL_CONS_COLUMNS acc
                WHERE acc.OWNER = 'MY_OWNER_NAME'
                GROUP BY acc.CONSTRAINT_NAME) constraint_child
        WHERE pk.owner = fk.r_owner
            AND pk.constraint_name = fk.r_constraint_name
            AND fk.constraint_type = 'R'
            AND pk.table_name = asked_table_name
            AND constraint_parent.CONSTRAINT_NAME = fk.CONSTRAINT_NAME
            AND constraint_child.CONSTRAINT_NAME = fk.R_CONSTRAINT_NAME
            AND pk.owner = 'MY_OWNER_NAME'
            AND fk.owner = 'MY_OWNER_NAME')
    LOOP
        current_path := parent_table_name || ' // ' || item.TABLE_NAME;
        DBMS_OUTPUT.PUT_LINE(current_path);
        DBMS_OUTPUT.PUT_LINE('     [' || item.FK1 || ']  [' || item.FK2 || ']');
        DBMS_OUTPUT.PUT_LINE('');
        current_path := list_all_child_tables_and_constraints(item.TABLE_NAME, current_path);

    END LOOP;
    RETURN '-----------FINISHED-----------';

EXCEPTION
    WHEN OTHERS THEN
        RETURN '-----------FINISHED-----------';
END list_all_child_tables_and_constraints;
BEGIN
DBMS_OUTPUT.PUT_LINE(list_all_child_tables_and_constraints('MY_TABLE_NAME', ''));
END;

为sql developer插件添加上面的答案,使用下面的xml将有助于获得与外键相关的列。

    <items>
        <item type="editor" node="TableNode" vertical="true">
        <title><![CDATA[FK References]]></title>
        <query>
            <sql>
                <![CDATA[select a.owner,
                                a.constraint_name,
                                a.table_name,
                                b.column_name,
                                a.status
                         from   all_constraints a
                         join   all_cons_columns b ON b.constraint_name = a.constraint_name
                         where  a.constraint_type = 'R'
                                and exists(
                                   select 1
                                   from   all_constraints
                                   where  constraint_name=a.r_constraint_name
                                          and constraint_type in ('P', 'U')
                                          and table_name = :OBJECT_NAME
                                          and owner = :OBJECT_OWNER)
                                   order by table_name, constraint_name]]>
            </sql>
        </query>
        </item>
    </items>