Wyłącz wszystkie ograniczenia tabel w Oracle

96

Jak mogę wyłączyć wszystkie ograniczenia tabeli w Oracle za pomocą jednego polecenia? Może to dotyczyć pojedynczej tabeli, listy tabel lub wszystkich tabel.

się
źródło

Odpowiedzi:

148

Lepiej unikać wypisywania tymczasowych plików buforowania. Użyj bloku PL / SQL. Możesz to uruchomić z SQL * Plus lub umieścić to w pakiecie lub procedurze. Łączenie do USER_TABLES ma na celu uniknięcie ograniczeń widoku.

Jest mało prawdopodobne, że naprawdę chcesz wyłączyć wszystkie ograniczenia (w tym NOT NULL, klucze podstawowe itp.). Powinieneś pomyśleć o umieszczeniu constraint_type w klauzuli 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;
/

Ponowne włączenie ograniczeń jest nieco trudniejsze - musisz włączyć ograniczenia klucza podstawowego, zanim będziesz mógł odwoływać się do nich w ograniczeniu klucza obcego. Można to zrobić za pomocą ORDER BY na constraint_type. „P” = klucz podstawowy, „R” = klucz obcy.

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;
/
W W.
źródło
2
Czy ten pierwszy segment kodu nie będzie próbował wyłączyć kluczy podstawowych, zanim wyłączy klucze obce?
David Aldridge,
@David Myślę, że napotkałem ten problem z pierwszym segmentem. Rozwiązałem to, dodając „DESC” między „ORDER BY c.constraint_type” a zamykającym „)”
AndreiM
@WW Moje uznanie. To właśnie zaoszczędziło mi kłopotu z napisaniem instrukcji SQL do generowania instrukcji ograniczających Enable i Disable.
dave
1
W tabelach zorganizowanych według indeksu nie można wyłączyć kluczy podstawowych. Możesz sobie z tym poradzić, dodając AND NOT (t.iot_type IS NOT NULL AND c.constraint_type = 'P')do pierwszego segmentu kodu.
Andrew Miller
2
Ostrzeżenie: jeśli masz już WYŁĄCZONE ograniczenia, wszystkie ograniczenia zostaną aktywowane przy użyciu tej procedury PL / SQL. Musisz odfiltrować te ograniczenia, aby upewnić się, że są wyłączone.
nachouve
11

Aby policzyć zależności między ograniczeniami:

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;
/
Cyryl1972
źródło
5

To nie jest pojedyncze polecenie, ale oto jak to robię. Poniższy skrypt został zaprojektowany do działania w SQL * Plus. Uwaga, celowo napisałem to, aby działało tylko w ramach bieżącego schematu.

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

Aby ograniczyć to, co upuszczasz, filtruj dodaj klauzulę where do instrukcji select: -

  • filtruj według constraint_type, aby usunąć tylko określone typy ograniczeń
  • filtruj według nazwa_tabeli, aby zrobić to tylko dla jednej lub kilku tabel.

Aby działać na więcej niż bieżącym schemacie, zmodyfikuj instrukcję select, aby wybierać spośród all_constraints zamiast user_constraints.

Uwaga - z jakiegoś powodu nie mogę sprawić, aby podkreślenie NIE działało jak kursywa w poprzednim akapicie. Jeśli ktoś wie, jak to naprawić, prosimy o edycję tej odpowiedzi.

Mike McAllister
źródło
Jeśli chcesz WYŁĄCZYĆ ograniczenia zamiast je porzucić, po prostu edytuj powyższą instrukcję SELECT: „upuść ograniczenie”, aby przeczytać „wyłącz ograniczenie” HTH: o)
Andrew
Tak, to dobra sugestia - w przyszłości możesz edytować post, aby dodać te informacje. Dlatego mam swoje posty jako edytowalne wiki społeczności.
Mike McAllister,
5

Użyj następującego kursora, aby wyłączyć wszystkie ograniczenia .. I zmień zapytanie dla włączania ograniczeń ...

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;
/
user486360
źródło
4

Można to napisać w języku PL / SQL po prostu w oparciu o widok systemu DBA / ALL / USER_CONSTRAINTS, ale różne szczegóły nie są tak banalne, jak się wydaje. Musisz uważać na kolejność, w jakiej to się robi, a także wziąć pod uwagę obecność unikalnych indeksów.

Kolejność jest ważna, ponieważ nie można usunąć unikalnego lub podstawowego klucza, do którego odwołuje się klucz obcy, a w tabelach w innych schematach mogą znajdować się klucze obce, które odwołują się do kluczy podstawowych w twoim własnym, więc chyba że masz uprawnienie ALTER ANY TABLE nie może porzucić tych PK i UK. Nie można również zmienić indeksu unikatowego na indeks nieunikalny, więc musisz go porzucić, aby usunąć ograniczenie (z tego powodu prawie zawsze lepiej jest implementować unikalne ograniczenia jako „rzeczywiste” ograniczenie, które jest obsługiwane przez nie unikalny indeks).

David Aldridge
źródło
0

Nie wygląda na to, że możesz to zrobić za pomocą jednego polecenia, ale oto najbliższa rzecz, jaką udało mi się znaleźć.

Adam Bellaire
źródło
0

To kolejny sposób wyłączania ograniczeń (pochodzi z 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;

działa jak marzenie

Cyryl1972
źródło
0

W skrypcie „disable” kolejność klauzuli powinna wyglądać tak:

ORDER BY c.constraint_type DESC, c.last_change DESC

Celem tej klauzuli jest wyłączenie ograniczeń we właściwej kolejności.

Cristian Chaparro A.
źródło
0
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; 

Ta instrukcja zwraca polecenia, które wyłączają wszystkie ograniczenia, w tym klucz podstawowy, klucze obce i inne ograniczenia.

Ankireddy Polu
źródło
0

z kursorem dla pętli (użytkownik = 'TRANEE', tabela = '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;
/

(Jeśli zmienisz opcję wyłącz na włączenie, możesz włączyć wszystkie ograniczenia)

diaphol
źródło
0

Możesz wykonać wszystkie polecenia zwrócone przez następujące zapytanie:

select 'ALTER TABLE' || substr (c.nazwa_tabeli, 1,35) || 'DISABLE CONSTRAINT' || constraint_name || ' ; ' from user_constraints c --where c.table_name = 'TABLE_NAME';

Cristina Bazar
źródło