98

How can I disable all table constrains in Oracle with a single command? This can be either for a single table, a list of tables, or for all tables.

oneself
  • 38,641
  • 34
  • 96
  • 120

11 Answers11

155

It is better to avoid writing out temporary spool files. Use a PL/SQL block. You can run this from SQL*Plus or put this thing into a package or procedure. The join to USER_TABLES is there to avoid view constraints.

It's unlikely that you really want to disable all constraints (including NOT NULL, primary keys, etc). You should think about putting constraint_type in the WHERE clause.

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

Enabling the constraints again is a bit tricker - you need to enable primary key constraints before you can reference them in a foreign key constraint. This can be done using an ORDER BY on constraint_type. 'P' = primary key, 'R' = foreign key.

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;
/
WW.
  • 23,793
  • 13
  • 94
  • 121
  • 2
    Isn't that first code segment going to try to disable primary keys before it disables foreign keys? – David Aldridge Sep 25 '08 at 17:07
  • @David I think I ran into this issue with the first segment. I solved it by adding 'DESC' between 'ORDER BY c.constraint_type' and the closing ')' – AndreiM Jun 24 '10 at 15:33
  • @WW My appreciation. This just saved me the trouble of writing a SQL statement to generate the Enable and Disable constraint statements. – dave Jun 20 '11 at 20:47
  • @Stefan: Done. I never use names that require quotes so I did not think of that. – WW. Mar 28 '12 at 21:36
  • @Toru Your suggested edit didn't change anything because ordering by constraint type alphabetically is causes primary key constraints ("P") to be disabled before foreign key constraints ("R"). David Aldridge pointed this out in the first comment and I updated then. – WW. Oct 30 '13 at 04:27
  • For me, only `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) LOOP dbms_utility.exec_ddl_statement('alter table ' || c.table_name || ' disable constraint "' || c.constraint_name || '"'); END LOOP; END; /` works. – yamass Jan 14 '15 at 13:18
  • 1
    Primary keys cannot be disabled on index-organized tables. You can handle these by adding `AND NOT (t.iot_type IS NOT NULL AND c.constraint_type = 'P')` to the first code segment. – Andrew Miller May 07 '15 at 15:15
  • 2
    Warning: if you have already DISABLED contraints, all constraints will be activated using that PL/SQL procedure. You have to filter those contraints on the where to ensure they keep disabled. – nachouve Nov 24 '15 at 11:19
14

To take in count the dependencies between the 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;
/
Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
Cyryl1972
  • 594
  • 3
  • 6
5

It's not a single command, but here's how I do it. The following script has been designed to run in SQL*Plus. Note, I've purposely written this to only work within the current schema.

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

To restrict what you drop, filter add a where clause to the select statement:-

  • filter on constraint_type to drop only particular types of constraints
  • filter on table_name to do it only for one or a few tables.

To run on more than the current schema, modify the select statement to select from all_constraints rather than user_constraints.

Note - for some reason I can't get the underscore to NOT act like an italicization in the previous paragraph. If someone knows how to fix it, please feel free to edit this answer.

sehe
  • 374,641
  • 47
  • 450
  • 633
Mike McAllister
  • 1,479
  • 2
  • 12
  • 15
  • If you want to DISABLE the constraints instead of DROPing them, simply edit the above SELECT statement: ' drop constraint ' to read ' disable constraint ' HTH :o) – Andrew Sep 25 '08 at 08:41
  • Yes, that's a good suggestion - in the future, feel free to edit the post to add this information. That's why I have my posts as community wiki editable. – Mike McAllister Sep 25 '08 at 12:41
5

Use following cursor to disable all constraint.. And alter query for enable constraints...

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;
/
sehe
  • 374,641
  • 47
  • 450
  • 633
user486360
  • 51
  • 1
  • 1
4

This can be scripted in PL/SQL pretty simply based on the DBA/ALL/USER_CONSTRAINTS system view, but various details make not as trivial as it sounds. You have to be careful about the order in which it is done and you also have to take account of the presence of unique indexes.

The order is important because you cannot drop a unique or primary key that is referenced by a foreign key, and there could be foreign keys on tables in other schemas that reference primary keys in your own, so unless you have ALTER ANY TABLE privilege then you cannot drop those PKs and UKs. Also you cannot switch a unique index to being a non-unique index so you have to drop it in order to drop the constraint (for this reason it's almost always better to implement unique constraints as a "real" constraint that is supported by a non-unique index).

David Aldridge
  • 51,479
  • 8
  • 68
  • 96
1
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; 

This statement returns the commands which turn off all the constraints including primary key, foreign keys, and another constraints.

Cristian
  • 1,480
  • 5
  • 32
  • 65
Ankireddy Polu
  • 1,824
  • 16
  • 16
1

This is another way for disabling constraints (it came from 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;

works like a charm

Twinkles
  • 1,984
  • 1
  • 17
  • 31
Cyryl1972
  • 594
  • 3
  • 6
0

In the "disable" script, the order by clause should be that:

ORDER BY c.constraint_type DESC, c.last_change DESC

The goal of this clause is disable the constraints in the right order.

Cristian
  • 1,480
  • 5
  • 32
  • 65
0

It doesn't look like you can do this with a single command, but here's the closest thing to it that I could find.

Adam Bellaire
  • 108,003
  • 19
  • 148
  • 163
0

with cursor for loop (user = 'TRANEE', table = '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;
/

(If you change disable to enable, you can make all constraints enable)

diaphol
  • 117
  • 1
  • 9
0

You can execute all the commands returned by the following query :

select 'ALTER TABLE '||substr(c.table_name,1,35)|| 
' DISABLE CONSTRAINT '||constraint_name||' ;' 
from user_constraints c
--where c.table_name = 'TABLE_NAME' ;
insomniac
  • 11,146
  • 6
  • 44
  • 55