bulk collect und for loop / Constraints ab- und wieder anschalten
Manchen Operationen (wie z.B. truncate oder drop partition) können nicht mit aktiven Constraints auf die Tabelle ausgeführt werden.
Daher hat sich folgender Ablauf bewährt:
- aktive Constraints abzuschalten
- eigentliches Drop / truncate
- obige Constraints wieder einschalten
(Idealerweise "merkt" man sich die betroffenen Constraints und schaltet nicht pauschal alle Constraints wieder ein.)
Im Code kann das dann so aussehen:
Vorab - Typen definieren und Fehlerhandling vorbereiten
-- Type für Drop_Partition_FS definieren
-- Datentypen aus SYS.ALL_CONSTRAINTS
type x IS
record
(
OWNER VARCHAR2 (128 Char),
TABLE_NAME VARCHAR2 (128 Char),
CONSTRAINT_NAME VARCHAR2 (128 Char),
STATUS VARCHAR2 (8 Char)) ;
type y IS
TABLE OF x;
z y;
-- globale Variablen
part_missed EXCEPTION;
PRAGMA EXCEPTION_INIT (part_missed, -2149);
v_Sql varchar2(4000); -- SQL-String
Eigentliche Umsetzung:
-- FK-Constraints auf die Tabelle bestimmen; Status merken
select C1.OWNER
, C1.TABLE_NAME
, C1.CONSTRAINT_NAME
, C1.STATUS
bulk collect into z
from sys.ALL_CONSTRAINTS c1, sys.ALL_CONSTRAINTS c2
where c1.constraint_type = 'R'
and c2.constraint_type in ('P', 'U')
and c2.owner = 'mySchema'
and c2.table_name = p_myTbl
and c1.r_owner = c2.owner
and c1.r_constraint_Name = c2.constraint_name
order by 1,2,3;
-- aktive Constraints abschalten
for i in 1..z.count
loop
if z(i).STATUS = 'ENABLED' then
v_Sql := 'alter table '||z(i).OWNER||'.'||z(i).TABLE_NAME||' disable constraint '||z(i).CONSTRAINT_NAME ||' keep index';
log(c_Modul, v_Sql);
execute immediate v_Sql;
end if;
end loop;
-- eigentliches Partition droppen
v_Sql := 'alter table '||p_Tbl_Name||' drop partition '||p_Partition_Name;
log(c_Modul, v_Sql);
begin
execute immediate v_Sql;
exception
when part_missed then null;
when others then raise;
end;
-- vorher aktive Constraints wieder einschalten
for i in 1..z.count
loop
if z(i).STATUS = 'ENABLED' then
v_Sql := 'alter table '||z(i).OWNER||'.'||z(i).TABLE_NAME||' enable novalidate constraint '||z(i).CONSTRAINT_NAME;
log(c_Modul, v_Sql);
execute immediate v_Sql;
end if;
end loop;
Hinweis:
for i in 1..z.count
-> Falls der Select ggfs. keine (aktiven) Constraint findet führt
for i in i.first..i.last
zu einem Fehler (da i leer ist).
Daher hat sich folgender Ablauf bewährt:
- aktive Constraints abzuschalten
- eigentliches Drop / truncate
- obige Constraints wieder einschalten
(Idealerweise "merkt" man sich die betroffenen Constraints und schaltet nicht pauschal alle Constraints wieder ein.)
Im Code kann das dann so aussehen:
Vorab - Typen definieren und Fehlerhandling vorbereiten
-- Type für Drop_Partition_FS definieren
-- Datentypen aus SYS.ALL_CONSTRAINTS
type x IS
record
(
OWNER VARCHAR2 (128 Char),
TABLE_NAME VARCHAR2 (128 Char),
CONSTRAINT_NAME VARCHAR2 (128 Char),
STATUS VARCHAR2 (8 Char)) ;
type y IS
TABLE OF x;
z y;
-- globale Variablen
part_missed EXCEPTION;
PRAGMA EXCEPTION_INIT (part_missed, -2149);
v_Sql varchar2(4000); -- SQL-String
Eigentliche Umsetzung:
-- FK-Constraints auf die Tabelle bestimmen; Status merken
select C1.OWNER
, C1.TABLE_NAME
, C1.CONSTRAINT_NAME
, C1.STATUS
bulk collect into z
from sys.ALL_CONSTRAINTS c1, sys.ALL_CONSTRAINTS c2
where c1.constraint_type = 'R'
and c2.constraint_type in ('P', 'U')
and c2.owner = 'mySchema'
and c2.table_name = p_myTbl
and c1.r_owner = c2.owner
and c1.r_constraint_Name = c2.constraint_name
order by 1,2,3;
-- aktive Constraints abschalten
for i in 1..z.count
loop
if z(i).STATUS = 'ENABLED' then
v_Sql := 'alter table '||z(i).OWNER||'.'||z(i).TABLE_NAME||' disable constraint '||z(i).CONSTRAINT_NAME ||' keep index';
log(c_Modul, v_Sql);
execute immediate v_Sql;
end if;
end loop;
-- eigentliches Partition droppen
v_Sql := 'alter table '||p_Tbl_Name||' drop partition '||p_Partition_Name;
log(c_Modul, v_Sql);
begin
execute immediate v_Sql;
exception
when part_missed then null;
when others then raise;
end;
-- vorher aktive Constraints wieder einschalten
for i in 1..z.count
loop
if z(i).STATUS = 'ENABLED' then
v_Sql := 'alter table '||z(i).OWNER||'.'||z(i).TABLE_NAME||' enable novalidate constraint '||z(i).CONSTRAINT_NAME;
log(c_Modul, v_Sql);
execute immediate v_Sql;
end if;
end loop;
Hinweis:
for i in 1..z.count
-> Falls der Select ggfs. keine (aktiven) Constraint findet führt
for i in i.first..i.last
zu einem Fehler (da i leer ist).
Kommentare
Kommentar veröffentlichen