如何查找指向Oracle中一条记录的外键依赖项?

问题描述 投票:19回答:6

我有一个非常大的Oracle数据库,有许多表和数百万行。我需要删除其中一个,但是要确保删除它不会破坏任何指向它作为外键记录的其他依赖行。有没有办法获得指向此行的所有其他记录或至少表格模式的列表?我知道我可以尝试自己删除它,并捕获异常,但我不会自己运行脚本,需要它第一次运行清理。

我有来自Oracle的SQL Developer工具和来自AllRoundAutomations的PL / SQL Developer。

提前致谢!

database oracle database-schema
6个回答
26
投票

我总是看着起始桌上的外键,然后回去工作。数据库工具通常具有依赖项或约束节点。我知道PL / SQL Developer有办法看到FK,但是我用了它已经有一段时间了,所以我无法解释它......

只需用表名替换XXXXXXXXXXXX ......

/* The following query lists all relationships */ 

select
 a.owner||'.'||a.table_name "Referenced Table"
,b.owner||'.'||b.table_name "Referenced by"
,b.constraint_name "Foreign Key"
from all_constraints a, all_constraints b 
where 
b.constraint_type = 'R'
and a.constraint_name = b.r_constraint_name 
and b.table_name='XXXXXXXXXXXX' -- Table name 
order by a.owner||'.'||a.table_name

31
投票

这是我列出对表的所有引用的解决方案:

select
  src_cc.owner as src_owner,
  src_cc.table_name as src_table,
  src_cc.column_name as src_column,
  dest_cc.owner as dest_owner,
  dest_cc.table_name as dest_table,
  dest_cc.column_name as dest_column,
  c.constraint_name
from
  all_constraints c
inner join all_cons_columns dest_cc on
  c.r_constraint_name = dest_cc.constraint_name
  and c.r_owner = dest_cc.owner
inner join all_cons_columns src_cc on
  c.constraint_name = src_cc.constraint_name
  and c.owner = src_cc.owner
where
  c.constraint_type = 'R'
  and dest_cc.owner = 'MY_TARGET_SCHEMA'
  and dest_cc.table_name = 'MY_TARGET_TABLE'
  --and dest_cc.column_name = 'MY_OPTIONNAL_TARGET_COLUMN'
;

使用此解决方案,您还可以获得哪个表的哪一列引用目标表的哪一列(并且可以对其进行过滤)的信息。


7
投票

我最近遇到了类似的问题,但很快就遇到了,找到直接的依赖关系是不够的。所以我写了一个查询来显示多级外键依赖关系的树:

SELECT LPAD(' ',4*(LEVEL-1)) || table1 || ' <-- ' || table2 tables, table2_fkey
FROM
  (SELECT a.table_name table1, b.table_name table2, b.constraint_name table2_fkey
  FROM user_constraints a, user_constraints b 
  WHERE a.constraint_type IN('P', 'U') 
  AND b.constraint_type = 'R' 
  AND a.constraint_name = b.r_constraint_name 
  AND a.table_name != b.table_name
  AND b.table_name <> 'MYTABLE')
CONNECT BY PRIOR  table2 = table1 AND LEVEL <= 5
START WITH table1 = 'MYTABLE';

在我的数据库中使用SHIPMENT作为MYTABLE时,它给出了这样的结果:

SHIPMENT <-- ADDRESS
SHIPMENT <-- PACKING_LIST
    PACKING_LIST <-- PACKING_LIST_DETAILS
    PACKING_LIST <-- PACKING_UNIT
        PACKING_UNIT <-- PACKING_LIST_ITEM
    PACKING_LIST <-- PO_PACKING_LIST
...

3
投票

我们可以使用数据字典来标识引用相关表的主键的表。从那里我们可以生成一些动态SQL来查询这些表以获取我们想要的值:

SQL> declare
  2      n pls_integer;
  3      tot pls_integer := 0;
  4  begin
  5      for lrec in ( select table_name from user_constraints
  6                    where r_constraint_name = 'T23_PK' )
  7      loop
  8          execute immediate 'select count(*) from '||lrec.table_name
  9                              ||' where col2 = :1' into n using &&target_val;
 10          if n = 0 then
 11              dbms_output.put_line('No impact on '||lrec.table_name);
 12          else
 13              dbms_output.put_line('Uh oh! '||lrec.table_name||' has '||n||' hits!');
 14          end if;
 15          tot := tot + n;
 16      end loop;
 17      if tot = 0
 18      then
 19          delete from t23 where col2 = &&target_val;
 20          dbms_output.put_line('row deleted!');
 21      else
 22          dbms_output.put_line('delete aborted!');
 23      end if;
 24  end;
 25  /
Enter value for target_val: 6
No impact on T34
Uh oh! T42 has 2 hits!
No impact on T69
delete aborted!

PL/SQL procedure successfully completed.

SQL>

这个例子有点欺骗。目标主键的名称是硬编码的,并且引用列在所有从属表上具有相同的名称。修复这些问题留给读者练习;)


0
投票

我很惊讶基于外键关系找到表的依赖顺序是多么困难。我需要它,因为我想从所有表中删除数据并再次导入。这是我写的用于按依赖顺序列出表的查询。我能够使用下面的查询编写删除脚本,并以相反的顺序使用查询结果再次导入。

   SELECT referenced_table
         ,MAX(lvl) for_deleting
         ,MIN(lvl) for_inserting
   FROM
         ( -- Hierarchy of dependencies
         SELECT LEVEL lvl
               ,t.table_name referenced_table
               ,b.table_name referenced_by
         FROM user_constraints A
         JOIN user_constraints b 
               ON  A.constraint_name = b.r_constraint_name
               and b.constraint_type = 'R'
         RIGHT JOIN user_tables t
               ON  t.table_name = A.table_name
         START WITH b.table_name IS NULL
         CONNECT BY b.table_name = PRIOR t.table_name
         )
   GROUP BY referenced_table
   ORDER BY for_deleting, for_inserting;

0
投票

Oracle约束使用表索引来引用数据。 要找出哪些表引用一个表,只需按相反的顺序查找索引。

/* Toggle ENABLED and DISABLE status for any referencing constraint: */ 

select 'ALTER TABLE '||b.owner||'.'||b.table_name||' '||
        decode(b.status, 'ENABLED', 'DISABLE ', 'ENABLE ')||
       'CONSTRAINT '||b.constraint_name||';' 
  from all_indexes a,
       all_constraints b
 where a.table_name='XXXXXXXXXXXX' -- Table name 
   and a.index_name = b.r_constraint_name;

Obs。:禁用引用可以显着改善DML命令(更新,删除和插入)的时间。

这可以在批量操作中提供很多帮助,您知道所有数据都是一致的。

/* List which columns are referenced in each constraint */

select ' TABLE "'||b.owner||'.'||b.table_name||'"'||
        '('||listagg (c.column_name, ',') within group (order by c.column_name)||')'|| 
        ' FK "'||b.constraint_name||'" -> '||a.table_name||
        ' INDEX "'||a.index_name||'"'
        "REFERENCES"
  from all_indexes a,
       all_constraints b,
       all_cons_columns c
 where rtrim(a.table_name) like 'XXXXXXXXXXXX' -- Table name 
   and a.index_name = b.r_constraint_name
   and c.constraint_name = b.constraint_name
 group by b.owner, b.table_name, b.constraint_name, a.table_name, a.index_name
 order by 1;
© www.soinside.com 2019 - 2024. All rights reserved.