使用 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;