【问题标题】:Disable all table constraints in Oracle禁用Oracle中的所有表约束
【发布时间】:2010-09-12 19:39:45
【问题描述】:

如何使用单个命令禁用 Oracle 中的所有表约束? 这可以是单个表、表列表或所有表。

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    您可以执行以下查询返回的所有命令:

    选择'ALTER TABLE'||substr(c.table_name,1,35)|| '禁用约束'||constraint_name||' ;' 来自 user_constraints c --其中 c.table_name = 'TABLE_NAME' ;

    【讨论】:

      【解决方案2】:

      带光标循环(用户 = '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,可以让所有的约束都启用)

      【讨论】:

        【解决方案3】:
        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; 
        

        此语句返回关闭所有约束的命令,包括主键、外键和其他约束。

        【讨论】:

          【解决方案4】:

          在“禁用”脚本中,order by 子句应该是:

          ORDER BY c.constraint_type DESC, c.last_change DESC
          

          此子句的目标是以正确的顺序禁用约束。

          【讨论】:

            【解决方案5】:

            这是禁用约束的另一种方式(来自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;
            

            像魅力一样工作

            【讨论】:

              【解决方案6】:

              最好避免写出临时假脱机文件。使用 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;
              /
              

              【讨论】:

              • 第一个代码段不是在禁用外键之前尝试禁用主键吗?
              • @David 我想我在第一部分遇到了这个问题。我通过在 'ORDER BY c.constraint_type' 和结束 ')' 之间添加 'DESC' 来解决它
              • @WW 非常感谢。这只是省去了我编写 SQL 语句来生成启用和禁用约束语句的麻烦。
              • 不能在索引组织的表上禁用主键。您可以通过将AND NOT (t.iot_type IS NOT NULL AND c.constraint_type = 'P') 添加到第一个代码段来处理这些问题。
              • 警告:如果您已经禁用了约束,所有约束都将使用该 PL/SQL 过程激活。您必须在 where 上过滤这些约束以确保它们保持禁用状态。
              【解决方案7】:

              使用以下光标禁用所有约束..并更改查询以启用约束...

              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;
              /
              

              【讨论】:

                【解决方案8】:

                这不是一个命令,但我是这样做的。以下脚本设计为在 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 子句:-

                • 对约束类型进行过滤以仅删除特定类型的约束
                • 对 table_name 进行过滤以仅针对一个或几个表执行此操作。

                要在当前架构之外运行,请将 select 语句修改为 select from all_constraints 而不是 user_constraints。

                注意 - 由于某种原因,我无法让下划线不像上一段中的斜体。如果有人知道如何解决它,请随时编辑此答案。

                【讨论】:

                • 如果你想禁用约束而不是删除它们,只需编辑上面的 SELECT 语句:'drop constraint' 读取'禁用约束'HTH :o)
                • 是的,这是一个很好的建议 - 将来,请随时编辑帖子以添加此信息。这就是为什么我将我的帖子作为社区 wiki 可编辑的原因。
                【解决方案9】:

                计算约束之间的依赖关系:

                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;
                /
                

                【讨论】:

                  【解决方案10】:

                  这可以非常简单地基于 DBA/ALL/USER_CONSTRAINTS 系统视图在 PL/SQL 中编写脚本,但各种细节并不像听起来那么简单。您必须注意完成的顺序,还必须考虑唯一索引的存在。

                  顺序很重要,因为您不能删除由外键引用的唯一键或主键,并且其他模式中的表上可能有外键引用您自己的主键,因此除非您有 ALTER ANY TABLE特权,那么您不能放弃那些 PK 和 UK。此外,您不能将唯一索引切换为非唯一索引,因此您必须删除它才能删除约束(因此,将唯一约束实现为非唯一约束支持的“真实”约束几乎总是更好的) -唯一索引)。

                  【讨论】:

                    【解决方案11】:

                    看起来你不能用一个命令来做到这一点,但here's 是我能找到的最接近它的东西。

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2022-01-26
                      • 2014-02-16
                      • 1970-01-01
                      • 2012-07-23
                      • 1970-01-01
                      • 2010-11-07
                      • 1970-01-01
                      相关资源
                      最近更新 更多