Oracle Oracle分层查询禁用外键

Oracle Oracle hierarchical query to disable foreign keys

我有一些代码(见下文),它使用遍历 table 的分层查询来查找所有相关的外键。这似乎工作正常。

是否可以修改为不显示顶层 table,在本例中为 TABLE_NAME='PARENT',因为我想将此代码包装在 PL/SQL 中为了为 table.

的所有后代创建 enable/disable 外键所需的语法

在我的示例中,我有 3 个 table。孙子table,子REFERENCES子table,子table,子REFERENCES父table,子table 41=].

这样做的原因是要清理一些大量的 tables,我正试图找出进行此练习的最有效和最有效的方法。

我们没有 CASCADE DELETE 设置,因为那太危险了,不幸的是,有些人很难学到。

下面是我的测试用例和预期结果,我打算在一个过程中执行。

create table parent (
  id NUMBER(10),
  value      varchar2(30),
constraint parent_pk primary key (id)
);

CREATE TABLE child
( id NUMBER(10) not null,
value NUMBER(10) not null,
constraint child_pk primary key (id,value),
CONSTRAINT parent_child_fk
FOREIGN KEY (id)
REFERENCES parent(id));

CREATE TABLE grandchild
( id NUMBER(10) not null,
value NUMBER(10) not null,
constraint grandchild_pk primary key (id,value),
CONSTRAINT child_grandchild_fk
FOREIGN KEY (id,value)
REFERENCES child(id,value));

insert into parent values (1,'a');
insert into parent values (2,'b');
insert into parent values (3,'c');

insert into child  values (1,1);
insert into child  values (1,2);
insert into child  values (1,3);
insert into child  values (2,1);
insert into child  values (2,2);
insert into child  values (2,3);
insert into child  values (3,1);
insert into child  values (3,2);
insert into child  values (3,3);

insert into grandchild  values (1,1);
insert into grandchild  values (1,2);
insert into grandchild  values (1,3);
insert into grandchild  values (2,1);
insert into grandchild  values (2,2);
insert into grandchild  values (2,3);
insert into grandchild  values (3,1);
insert into grandchild  values (3,2);
insert into grandchild  values (3,3);

在查询中,我对列名称 ID 进行了硬编码。

如果可能的话,我想弄明白,否则我可以接受硬编码值。

select distinct table_name, constraint_name, column_name, r_table_name, position, constraint_type 
from (
    SELECT uc.table_name, 
    uc.constraint_name, 
    cols.column_name, 
    (select table_name from user_constraints where constraint_name = uc.r_constraint_name) 
        r_table_name,
    (select column_name from user_cons_columns where constraint_name = uc.r_constraint_name and position = cols.position) 
        r_column_name,
    cols.position,
    uc.constraint_type
    FROM user_constraints uc
    inner join user_cons_columns cols on uc.constraint_name = cols.constraint_name 
    where constraint_type != 'C'
) 
start with table_name = 'PARENT' and column_name = 'ID'  
connect by nocycle 
prior table_name = r_table_name 
and prior column_name = r_column_name;
TABLE_NAME CONSTRAINT_NAME COLUMN_NAME R_TABLE_NAME POSITION CONSTRAINT_TYPE
PARENT PARENT_PK ID - 1 P
GRANDCHILD CHILD_GRANDCHILD_FK ID CHILD 1 R
CHILD PARENT_CHILD_FK ID PARENT 1 R

我的测试用例的预期结果是生成此语法:

alter table CHILD disable constraint PARENT_CHILD_FK;
alter table GRANDCHILD disable constraint CHILD_GRANDCHILD_FK;

您可以使用:

SELECT 'ALTER TABLE "' || u.owner || '"."' || u.table_name || '" '
       || 'DISABLE CONSTRAINT "' || u.constraint_name || '"' AS statement
FROM   user_constraints u
       INNER JOIN user_constraints r
       ON (   u.constraint_type = 'R'
          AND r.constraint_type IN ('P', 'U')
          AND u.r_owner = r.owner
          AND u.r_constraint_name = r.constraint_name)
START WITH r.table_name       = 'PARENT'
CONNECT BY PRIOR u.owner      = r.owner
AND        PRIOR u.table_name = r.table_name;

db<>fiddle here

没必要硬编码,其实显示起来比较麻烦 top-level table

with tab1 as (
select t1.CONSTRAINT_NAME,
       t1.CONSTRAINT_TYPE,
       t1.TABLE_NAME,
       t1.R_CONSTRAINT_NAME,
       t2.CONSTRAINT_TYPE r_type,
       t2.TABLE_NAME r_name
  from user_constraints t1,
       user_constraints t2
 where t1.CONSTRAINT_TYPE = 'R'
   and t1.R_CONSTRAINT_NAME = t2.CONSTRAINT_NAME
)
, tab2 as(
select t1.*
  from tab1 t1
 start with not exists(
       select 1 from tab1 v1 where t1.r_name = v1.table_name
 )
 connect by prior t1.table_name = t1.r_name
)
select 'alter table ' || t1.table_name || ' disable constraint ' || t1.CONSTRAINT_NAME || ';'
  from tab2 t1
;