使用 Oracle PL/SQL 禁用来自 table 的所有相关约束
Disable all related constraints from a table with Oracle PL/SQL
CREATE OR REPLACE PROCEDURE disable_all_constraints
(p_owner IN VARCHAR2,
p_table_name IN VARCHAR2)
IS
CURSOR check_status IS
(SELECT status
FROM all_constraints
WHERE owner = p_owner
AND table_name = p_table_name );
v_status VARCHAR2(10);
BEGIN
OPEN check_status;
FETCH check_status
INTO v_status;
IF (check_status %NOTFOUND)
THEN
DBMS_OUTPUT.PUT_LINE('No Constraints added to the table, give me another table to process!');
ELSE
FOR cur IN (SELECT owner, constraint_name , table_name
FROM all_constraints
WHERE owner = p_owner
AND table_name = p_table_name)
LOOP
EXECUTE IMMEDIATE 'ALTER TABLE '||cur.owner||'.'||cur.table_name||' MODIFY CONSTRAINT '||cur.constraint_name||' DISABLE CASCADE ';
END LOOP;
END IF;
CLOSE check_status;
SELECT DISTINCT status
INTO v_status
FROM all_constraints
WHERE owner = p_owner
AND table_name = p_table_name;
IF v_status = 'DISABLED'
THEN
DBMS_OUTPUT.PUT_LINE('All related constraints disable succesufully!');
ELSE
DBMS_OUTPUT.PUT_LINE('Something went wrong, but that is impossible!');
END IF;
END;
所以我写了上面的文章。我测试了它,我认为它做得很好。但我的问题是,它有多正确或有多糟糕?可以这么说,以更简单和最佳的方式完成吗?谢谢
您执行此操作的方式本质上没有错,但存在许多潜在问题和一些不必要的代码。
- 你的第一个游标是不必要的,无论如何你都会循环 ALL_CONSTRAINTS - 如果你不进入循环那么 table 就没有约束
- 您可以尝试禁用已经禁用的约束 - 您只需要 select 当前启用的那些约束。
- 你最后的 select 查看是否有任何非禁用约束将 总是 如果有多个状态,你将失败,因为你会得到一个 TOO_MANY_ROWS 异常(用于返回多行)。这意味着您的最终 ELSE 语句将永远不会被输入。
- 高度不可能在不引发异常的情况下不禁用约束。我什至不会为最后的检查而烦恼。
更一般地说,将信息输出到屏幕几乎没有意义。它需要有人阅读它。如果一切正常,或者在发生错误时引发异常,通常会更好。
我会将其大量简化为类似下面的内容,它只是循环遍历非禁用约束并禁用它们。
create or replace procedure disable_all_constraints (
p_owner in varchar2
, p_table_name in varchar2
) is
begin
for cur in ( select owner || '.' || table_name as object
, constraint_name
from all_constraints
where owner = p_owner
and table_name = p_table_name
and status <> 'DISABLED'
) loop
execute immediate 'alter table ' || cur.object || '
modify constraint ' || cur.constraint_name || '
disable cascade';
end loop;
end;
如果您觉得必须进行额外的检查和打印,这可以做得更干净:
create or replace procedure disable_all_constraints (
p_owner in varchar2
, p_table_name in varchar2
) is
l_has_constraint boolean := False;
l_ct number;
begin
for cur in ( select owner || '.' || table_name as object
, constraint_name
from all_constraints
where owner = p_owner
and table_name = p_table_name
and status <> 'DISABLED'
) loop
l_has_constraint := True;
execute immediate 'alter table ' || cur.object || '
modify constraint ' || cur.constraint_name || '
disable cascade';
end loop;
if not l_has_constraint then
dbms_output.put_line('No Constraints added to the table.');
else
select count(*) into l_ct
from all_constraints
where owner = p_owner
and table_name = p_table_name
and status <> 'DISABLED'
;
if l_ct = 0 then
dbms_output.put_line('All related constraints disable successfully');
else
dbms_output.put_line('Something went wrong, but that is impossible');
end if;
end if;
end;
CREATE OR REPLACE PROCEDURE disable_all_constraints
(p_owner IN VARCHAR2,
p_table_name IN VARCHAR2)
IS
CURSOR check_status IS
(SELECT status
FROM all_constraints
WHERE owner = p_owner
AND table_name = p_table_name );
v_status VARCHAR2(10);
BEGIN
OPEN check_status;
FETCH check_status
INTO v_status;
IF (check_status %NOTFOUND)
THEN
DBMS_OUTPUT.PUT_LINE('No Constraints added to the table, give me another table to process!');
ELSE
FOR cur IN (SELECT owner, constraint_name , table_name
FROM all_constraints
WHERE owner = p_owner
AND table_name = p_table_name)
LOOP
EXECUTE IMMEDIATE 'ALTER TABLE '||cur.owner||'.'||cur.table_name||' MODIFY CONSTRAINT '||cur.constraint_name||' DISABLE CASCADE ';
END LOOP;
END IF;
CLOSE check_status;
SELECT DISTINCT status
INTO v_status
FROM all_constraints
WHERE owner = p_owner
AND table_name = p_table_name;
IF v_status = 'DISABLED'
THEN
DBMS_OUTPUT.PUT_LINE('All related constraints disable succesufully!');
ELSE
DBMS_OUTPUT.PUT_LINE('Something went wrong, but that is impossible!');
END IF;
END;
所以我写了上面的文章。我测试了它,我认为它做得很好。但我的问题是,它有多正确或有多糟糕?可以这么说,以更简单和最佳的方式完成吗?谢谢
您执行此操作的方式本质上没有错,但存在许多潜在问题和一些不必要的代码。
- 你的第一个游标是不必要的,无论如何你都会循环 ALL_CONSTRAINTS - 如果你不进入循环那么 table 就没有约束
- 您可以尝试禁用已经禁用的约束 - 您只需要 select 当前启用的那些约束。
- 你最后的 select 查看是否有任何非禁用约束将 总是 如果有多个状态,你将失败,因为你会得到一个 TOO_MANY_ROWS 异常(用于返回多行)。这意味着您的最终 ELSE 语句将永远不会被输入。
- 高度不可能在不引发异常的情况下不禁用约束。我什至不会为最后的检查而烦恼。
更一般地说,将信息输出到屏幕几乎没有意义。它需要有人阅读它。如果一切正常,或者在发生错误时引发异常,通常会更好。
我会将其大量简化为类似下面的内容,它只是循环遍历非禁用约束并禁用它们。
create or replace procedure disable_all_constraints (
p_owner in varchar2
, p_table_name in varchar2
) is
begin
for cur in ( select owner || '.' || table_name as object
, constraint_name
from all_constraints
where owner = p_owner
and table_name = p_table_name
and status <> 'DISABLED'
) loop
execute immediate 'alter table ' || cur.object || '
modify constraint ' || cur.constraint_name || '
disable cascade';
end loop;
end;
如果您觉得必须进行额外的检查和打印,这可以做得更干净:
create or replace procedure disable_all_constraints (
p_owner in varchar2
, p_table_name in varchar2
) is
l_has_constraint boolean := False;
l_ct number;
begin
for cur in ( select owner || '.' || table_name as object
, constraint_name
from all_constraints
where owner = p_owner
and table_name = p_table_name
and status <> 'DISABLED'
) loop
l_has_constraint := True;
execute immediate 'alter table ' || cur.object || '
modify constraint ' || cur.constraint_name || '
disable cascade';
end loop;
if not l_has_constraint then
dbms_output.put_line('No Constraints added to the table.');
else
select count(*) into l_ct
from all_constraints
where owner = p_owner
and table_name = p_table_name
and status <> 'DISABLED'
;
if l_ct = 0 then
dbms_output.put_line('All related constraints disable successfully');
else
dbms_output.put_line('Something went wrong, but that is impossible');
end if;
end if;
end;