【发布时间】:2010-09-12 19:39:45
【问题描述】:
如何使用单个命令禁用 Oracle 中的所有表约束? 这可以是单个表、表列表或所有表。
【问题讨论】:
如何使用单个命令禁用 Oracle 中的所有表约束? 这可以是单个表、表列表或所有表。
【问题讨论】:
您可以执行以下查询返回的所有命令:
选择'ALTER TABLE'||substr(c.table_name,1,35)|| '禁用约束'||constraint_name||' ;' 来自 user_constraints c --其中 c.table_name = 'TABLE_NAME' ;
【讨论】:
带光标循环(用户 = 'TRANEE',表 = 'D')
declare
constr all_constraints.constraint_name%TYPE;
begin
for constr in
(select constraint_name from all_constraints
where table_name = 'D'
and owner = 'TRANEE')
loop
execute immediate 'alter table D disable constraint '||constr.constraint_name;
end loop;
end;
/
(如果你把disable改成enable,可以让所有的约束都启用)
【讨论】:
SELECT 'ALTER TABLE '||substr(c.table_name,1,35)||
' DISABLE CONSTRAINT '||constraint_name||' ;'
FROM user_constraints c, user_tables u
WHERE c.table_name = u.table_name;
此语句返回关闭所有约束的命令,包括主键、外键和其他约束。
【讨论】:
在“禁用”脚本中,order by 子句应该是:
ORDER BY c.constraint_type DESC, c.last_change DESC
此子句的目标是以正确的顺序禁用约束。
【讨论】:
这是禁用约束的另一种方式(来自https://asktom.oracle.com/pls/asktom/f?p=100:11:2402577774283132::::P11_QUESTION_ID:399218963817)
WITH qry0 AS
(SELECT 'ALTER TABLE '
|| child_tname
|| ' DISABLE CONSTRAINT '
|| child_cons_name
disable_fk
, 'ALTER TABLE '
|| parent_tname
|| ' DISABLE CONSTRAINT '
|| parent.parent_cons_name
disable_pk
FROM (SELECT a.table_name child_tname
,a.constraint_name child_cons_name
,b.r_constraint_name parent_cons_name
,LISTAGG ( column_name, ',') WITHIN GROUP (ORDER BY position) child_columns
FROM user_cons_columns a
,user_constraints b
WHERE a.constraint_name = b.constraint_name AND b.constraint_type = 'R'
GROUP BY a.table_name, a.constraint_name
,b.r_constraint_name) child
,(SELECT a.constraint_name parent_cons_name
,a.table_name parent_tname
,LISTAGG ( column_name, ',') WITHIN GROUP (ORDER BY position) parent_columns
FROM user_cons_columns a
,user_constraints b
WHERE a.constraint_name = b.constraint_name AND b.constraint_type IN ('P', 'U')
GROUP BY a.table_name, a.constraint_name) parent
WHERE child.parent_cons_name = parent.parent_cons_name
AND (parent.parent_tname LIKE 'V2_%' OR child.child_tname LIKE 'V2_%'))
SELECT DISTINCT disable_pk
FROM qry0
UNION
SELECT DISTINCT disable_fk
FROM qry0;
像魅力一样工作
【讨论】:
最好避免写出临时假脱机文件。使用 PL/SQL 块。您可以从 SQL*Plus 运行它或将它放入包或过程中。加入 USER_TABLES 是为了避免视图约束。
您不太可能真的想要禁用所有约束(包括 NOT NULL、主键等)。您应该考虑将 constraint_type 放在 WHERE 子句中。
BEGIN
FOR c IN
(SELECT c.owner, c.table_name, c.constraint_name
FROM user_constraints c, user_tables t
WHERE c.table_name = t.table_name
AND c.status = 'ENABLED'
AND NOT (t.iot_type IS NOT NULL AND c.constraint_type = 'P')
ORDER BY c.constraint_type DESC)
LOOP
dbms_utility.exec_ddl_statement('alter table "' || c.owner || '"."' || c.table_name || '" disable constraint ' || c.constraint_name);
END LOOP;
END;
/
再次启用约束有点棘手 - 您需要先启用主键约束,然后才能在外键约束中引用它们。这可以使用约束类型上的 ORDER BY 来完成。 'P' = 主键,'R' = 外键。
BEGIN
FOR c IN
(SELECT c.owner, c.table_name, c.constraint_name
FROM user_constraints c, user_tables t
WHERE c.table_name = t.table_name
AND c.status = 'DISABLED'
ORDER BY c.constraint_type)
LOOP
dbms_utility.exec_ddl_statement('alter table "' || c.owner || '"."' || c.table_name || '" enable constraint ' || c.constraint_name);
END LOOP;
END;
/
【讨论】:
AND NOT (t.iot_type IS NOT NULL AND c.constraint_type = 'P') 添加到第一个代码段来处理这些问题。
使用以下光标禁用所有约束..并更改查询以启用约束...
DECLARE
cursor r1 is select * from user_constraints;
cursor r2 is select * from user_tables;
BEGIN
FOR c1 IN r1
loop
for c2 in r2
loop
if c1.table_name = c2.table_name and c1.status = 'ENABLED' THEN
dbms_utility.exec_ddl_statement('alter table ' || c1.owner || '.' || c1.table_name || ' disable constraint ' || c1.constraint_name);
end if;
end loop;
END LOOP;
END;
/
【讨论】:
这不是一个命令,但我是这样做的。以下脚本设计为在 SQL*Plus 中运行。请注意,我特意将其编写为仅适用于当前架构。
set heading off
spool drop_constraints.out
select
'alter table ' ||
owner || '.' ||
table_name ||
' disable constraint ' || -- or 'drop' if you want to permanently remove
constraint_name || ';'
from
user_constraints;
spool off
set heading on
@drop_constraints.out
要限制您删除的内容,请在 select 语句中添加一个 where 子句:-
要在当前架构之外运行,请将 select 语句修改为 select from all_constraints 而不是 user_constraints。
注意 - 由于某种原因,我无法让下划线不像上一段中的斜体。如果有人知道如何解决它,请随时编辑此答案。
【讨论】:
计算约束之间的依赖关系:
SET Serveroutput ON
BEGIN
FOR c IN
(SELECT c.owner,c.table_name,c.constraint_name
FROM user_constraints c,user_tables t
WHERE c.table_name=t.table_name
AND c.status='ENABLED'
ORDER BY c.constraint_type DESC,c.last_change DESC
)
LOOP
FOR D IN
(SELECT P.Table_Name Parent_Table,C1.Table_Name Child_Table,C1.Owner,P.Constraint_Name Parent_Constraint,
c1.constraint_name Child_Constraint
FROM user_constraints p
JOIN user_constraints c1 ON(p.constraint_name=c1.r_constraint_name)
WHERE(p.constraint_type='P'
OR p.constraint_type='U')
AND c1.constraint_type='R'
AND p.table_name=UPPER(c.table_name)
)
LOOP
dbms_output.put_line('. Disable the constraint ' || d.Child_Constraint ||' (on table '||d.owner || '.' ||
d.Child_Table || ')') ;
dbms_utility.exec_ddl_statement('alter table ' || d.owner || '.' ||d.Child_Table || ' disable constraint ' ||
d.Child_Constraint) ;
END LOOP;
END LOOP;
END;
/
【讨论】:
这可以非常简单地基于 DBA/ALL/USER_CONSTRAINTS 系统视图在 PL/SQL 中编写脚本,但各种细节并不像听起来那么简单。您必须注意完成的顺序,还必须考虑唯一索引的存在。
顺序很重要,因为您不能删除由外键引用的唯一键或主键,并且其他模式中的表上可能有外键引用您自己的主键,因此除非您有 ALTER ANY TABLE特权,那么您不能放弃那些 PK 和 UK。此外,您不能将唯一索引切换为非唯一索引,因此您必须删除它才能删除约束(因此,将唯一约束实现为非唯一约束支持的“真实”约束几乎总是更好的) -唯一索引)。
【讨论】:
看起来你不能用一个命令来做到这一点,但here's 是我能找到的最接近它的东西。
【讨论】: