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
;
我有一些代码(见下文),它使用遍历 table 的分层查询来查找所有相关的外键。这似乎工作正常。
是否可以修改为不显示顶层 table,在本例中为 TABLE_NAME
='PARENT'
,因为我想将此代码包装在 PL/SQL 中为了为 table.
在我的示例中,我有 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
;