回答:
一時スプールファイルを書き出さないようにすることをお勧めします。PL / SQLブロックを使用します。これはSQL * Plusから実行することも、パッケージまたはプロシージャに入れることもできます。USER_TABLESへの結合は、ビューの制約を回避するためにあります。
すべての制約(NOT NULL、主キーなどを含む)を本当に無効にしたいとは思わないでしょう。WHERE句にconstraint_typeを配置することを検討する必要があります。
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;
/
制約を再度有効にするのは少し注意が必要です。外部キー制約で主キー制約を参照するには、主キー制約を有効にする必要があります。これは、constraint_typeで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;
/
AND NOT (t.iot_type IS NOT NULL AND c.constraint_type = 'P')
は、最初のコードセグメントに追加することで処理できます。
制約間の依存関係をカウントするには:
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;
/
これは単一のコマンドではありませんが、以下にその方法を示します。次のスクリプトは、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句をフィルターで追加します。
現在のスキーマ以外で実行するには、selectステートメントを変更して、user_constraintsではなくall_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;
/
これは、DBA / ALL / USER_CONSTRAINTSシステムビューに基づいてPL / SQLで簡単にスクリプト化できますが、さまざまな詳細は、思ったほど簡単ではありません。実行される順序に注意する必要があり、一意のインデックスの存在も考慮する必要があります。
外部キーによって参照される一意のキーまたは主キーを削除することはできず、独自の主キーを参照する他のスキーマのテーブルに外部キーが存在する可能性があるため、順序は重要です。したがって、ALTER ANY TABLE権限がないと、それらのPKとUKをドロップすることはできません。また、一意のインデックスを非一意のインデックスに切り替えることはできないため、制約を削除するためにそれを削除する必要があります(このため、ほとんどの場合、一意の制約を非実際にサポートされている「実際の」制約として実装する方が優れています-一意のインデックス)。
これは、制約を無効にするもう1つの方法です(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;
魅力のように働く
"disable"スクリプトでは、order by句は次のようになります。
ORDER BY c.constraint_type DESC, c.last_change DESC
この句の目的は、正しい順序で制約を無効にすることです。
カーソルforループあり(ユーザー= '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;
/
(無効を有効に変更すると、すべての制約を有効にすることができます)
次のクエリで返されるすべてのコマンドを実行できます。
'ALTER TABLE' || substr(c.table_name、1,35)||を選択します '制約を無効にする' || constraint_name || ' ; ' from user_constraints c --where c.table_name = 'TABLE_NAME';