我正试图自动化一个过程,以禁用和启用外键,这样我就可以删除“坏数据”。
下面是我们的一个应用程序模式的示例。我发现这个Tom Kyte查询可以显示一些表之间的关系。
create table c ( x NUMBER,
CONSTRAINT c_pk PRIMARY KEY(x)
);
create table c1 ( x NUMBER,
CONSTRAINT c1_pk PRIMARY KEY(x),
CONSTRAINT c1_fk FOREIGN KEY (x) REFERENCES c(x));
create table c2 ( x NUMBER,
CONSTRAINT c2_pk PRIMARY KEY(x),
CONSTRAINT c2_fk FOREIGN KEY (x) REFERENCES c2(x));
create table c3 ( x NUMBER,
CONSTRAINT c3_pk PRIMARY KEY(x),
CONSTRAINT c3_fk FOREIGN KEY (x) REFERENCES c2(x));
create table c4 ( x NUMBER,
CONSTRAINT c4_pk PRIMARY KEY(x),
CONSTRAINT c4_fk FOREIGN KEY (x) REFERENCES c2(x));
/* child/parent relationship */
with cte as (
select table_name, constraint_type, constraint_name, r_constraint_name,
max(decode(constraint_type,'R',1,0)) over(partition by table_name) is_r
from user_constraints
where constraint_type in ('P', 'U', 'R')
)
, child_parent as (
select distinct s.table_name child, d.table_name parent, d.constraint_type
from (select * from cte where constraint_type = 'R' or is_r = 0) s
left join cte d
on s.r_constraint_name = d.constraint_name
and s.table_name != d.table_name
)
select level lvl, child, parent, constraint_type
from child_parent
start with parent is null
connect by parent = prior child
order siblings by parent, child;
LVL CHILD PARENT CONSTRAINT_TYPE
1 C - -
2 C1 C P
1 C2 - -
2 C3 C2 P
2 C4 C2 P
我有以下代码,这将禁用和启用FK的。我知道这可以合并成一段代码(过程,它接受参数???)但我还没有达到这一点。
正如你从下面的输出中看到的,它禁用和启用了模式中的所有FK,我只需要代码对一组引用执行此操作。
例如,如果我传入表“C”,我的代码应该只禁用和启用FK C1_FK。如果传入表“C2”,则代码应仅禁用和启用C3_FK、C4_FK
任何帮助将不胜感激。提前感谢所有回答的人。注意,如果有更好的方法来编码这个解决方案,我愿意接受所有的建议
/* disable foreign keys */
DECLARE
sql_command varchar2(500);
BEGIN
FOR r IN (
SELECT '"' || a.owner
|| '"."'
|| a.table_name
|| '"' AS full_table_name,
a.constraint_name
FROM user_constraints a
JOIN user_constraints b
ON ( a.r_constraint_name = b.constraint_name
AND a.r_owner = b.owner )
WHERE a.constraint_type = 'R'
AND a.status = 'ENABLED'
ORDER BY 1 )
LOOP
sql_command := 'alter table ' || r.full_table_name || ' disable constraint ' || r.constraint_name;
dbms_output.put_line(sql_command);
execute immediate sql_command;
END LOOP ;
END ;
/
Statement processed.
alter table "XXX"."C1" disable constraint C1_FK
alter table "XXX"."C2" disable constraint C2_FK
alter table "XXX"."C3" disable constraint C3_FK
alter table "XXX"."C4" disable constraint C4_FK
DECLARE
sql_command varchar2(500);
BEGIN
FOR r IN (
SELECT '"' || a.owner
|| '"."'
|| a.table_name
|| '"' AS full_table_name,
a.constraint_name
FROM user_constraints a
JOIN user_constraints b
ON ( a.r_constraint_name = b.constraint_name
AND a.r_owner = b.owner )
WHERE a.constraint_type = 'R'
AND a.status = 'DISABLED'
ORDER BY 1 )
LOOP
sql_command := 'alter table ' || r.full_table_name || ' enable constraint ' || r.constraint_name;
dbms_output.put_line(sql_command);
execute immediate sql_command;
END LOOP ;
END ;
/
Statement processed.
alter table "XXX"."C1" enable constraint C1_FK
alter table "XXX"."C2" enable constraint C2_FK
alter table "XXX"."C3" enable constraint C3_FK
alter table "XXX"."C4" enable constraint
1条答案
按热度按时间5jdjgkvh1#
如果你试图从父表中删除行,你不能禁用和重新启用它的外键。通常,子表中仍会有指向父行(现在已丢失)的行。
所以要么你需要
null
novalidate
选项重新启用外键如果您试图从父级中删除的是“坏数据”,那么您几乎肯定也希望从子级中删除它。在这种情况下,您还需要对这些子表运行删除/更新。
这使得启用/禁用FK的过程是相当浪费的工作。只要在表中从子表到父表运行DML,它就“正常工作”,同时启用FK。
如果你想简化这个过程,你可以将外键声明为
on delete [cascade | set null]
。这会自动将所有删除从父表传播到子表。设置
on delete cascade
时要非常小心。有了这个,在一个小的查找表上运行一个delete
就很容易了,最终会清除大量的数据!例如: