ORACLE: Error on Drop an interim table after dbms_redefinition - oracle

I'm working on Oracle11g, and trying to redefine a table with dbms_redefinition. It works ok but when trying to drop the interim table it throws an ORA-02449: unique/primary keys in table referenced by foreign keys error.
I found a query to look for references right here in SO,
select table_name, constraint_name, status, owner
from all_constraints
where r_owner = 'MYSCHEMA'
and constraint_type = 'R'
and r_constraint_name in
(
select constraint_name from all_constraints
where constraint_type in ('P', 'U')
and table_name = 'INTERIM_TABLE'
and owner = 'MYSCHEMA'
)
order by table_name, constraint_name
which gives
table_name |constraint_name |status |owner
---------------------------------------------------------
anotherTable|TMP$$_anotherTable_JOB_ID0|DISABLED|MYSCHEMA
I suppose that this constraint was created during the redefinition process, that's ok, but I also expected that it must be deleted by the same process. Is this wrong? I say, is part of normal behavior that this constraint were not went deleted?
It's safe to just drop the constraint with
alter table anotherTable
drop constraint TMP$$_anotherTable_JOB_ID0
without a loss of data?
Thanks in advance.
-- EDIT --
After thinking about this, I've decided just to delete the constraint to let the interim table be droped.
I've modified the query to drop the constraints of other tables that point to the tables which I want to drop, almost automatically.
DECLARE
my_table varchar2(100);
my_constraint varchar2(100);
BEGIN
select table_name , constraint_name into my_table,my_constraint
from all_constraints
where r_owner = 'MYSCHEMA'
and constraint_type = 'R'
and r_constraint_name in
(
select constraint_name from all_constraints
where constraint_type in ('P', 'U')
and table_name = 'INTERIM_TABLE'
and owner = 'MYSCHEMA'
)
order by table_name, constraint_name;
execute immediate 'ALTER TABLE '||my_table||' DROP CONSTRAINT '|| my_constraint;
END;
/
DROP TABLE MYSCHEMA.INTERIM_TABLE;
This worked for me, but I must note that in my case that query throws just one row (only one dependant table), so this must be modified to drop many constraints by a loop or another method if you know someone.
It would be good if someone can figure out and explain why that constraint was not deleted by the process itself (or if this is a normal behavior).

It's easy enough to force this:
drop table INTERIM_TABLE cascade constraints;

It's because the original and new constraints STATUS changes while running the SYNC and FINISH redefinition procedure as below. You create the fkeys to the interim table from the child tables in a disabled mode. When we finish the redef, we disable the old fkeys and enable the news (without having to validate). Consider:
create table t NOLOGGING
as
select * from all_objects;
alter table t add constraint t_pk primary key(object_id);
create table t1( x references t );
create table t2( y references t );
insert into t1 select object_id from t where rownum <= 100;
100 rows created.
insert into t2 select object_id from t where rownum <= 100;
100 rows created.
create table t_interim similar to t table.
alter table t1 add constraint t1_new_fk foreign key(x) references t_interim disable;
alter table t2 add constraint t2_new_fk foreign key(y) references t_interim disable;
select constraint_name, status from user_constraints where constraint_type = 'R';
CONSTRAINT_NAME STATUS
------------------------------ --------
SYS_C004733 ENABLED <<<== original constraint
T1_NEW_FK DISABLED
SYS_C004734 ENABLED
T2_NEW_FK DISABLED
begin
dbms_redefinition.sync_interim_table( user, 'T', 'T_INTERIM' );
end;
/
PL/SQL procedure successfully completed.
begin
dbms_redefinition.finish_redef_table( user, 'T', 'T_INTERIM' );
end;
/
PL/SQL procedure successfully completed.
select constraint_name, status from user_constraints where constraint_type = 'R';
CONSTRAINT_NAME STATUS
------------------------------ --------
SYS_C004733 DISABLED <<< flip flopped the status
T1_NEW_FK ENABLED
SYS_C004734 DISABLED
T2_NEW_FK ENABLED
drop table t_interim cascade constraints;
select constraint_name, status from user_constraints where
constraint_type = 'R';
CONSTRAINT_NAME STATUS
------------------------------ --------
T1_NEW_FK ENABLED
T2_NEW_FK ENABLED

Related

how to delete a parent table that is also a child to it's child?

I have two tables both of which reference each other primary keys as foreign keys, I want to drop both but I can't.
I tried this :
alter table my_table drop constraint cons_name;
That gave me :
ORA-02443: Cannot drop constraint - nonexistent constraint
Suppose you have the following tables (Oracle 12c) ...
create table table1 ( column1 primary key )
as
select level
from dual
connect by level <= 10 ;
create table table2 ( column1 primary key )
as
select level
from dual
connect by level <= 10 ;
alter table table1
add constraint fk1
foreign key ( column1 ) references table2( column1 ) ;
alter table table2
add constraint fk2
foreign key ( column1 ) references table1( column1 ) ;
If you want to remove the constraints, make sure that you use the correct
constraint names.
-- find the correct constraint names
select table_name, constraint_name, constraint_type
from user_constraints
where table_name in( 'TABLE1', 'TABLE2' ) ;
TABLE_NAME CONSTRAINT_NAME CONSTRAINT_TYPE
TABLE2 SYS_C0021482 P
TABLE1 SYS_C0021483 P
TABLE1 FK1 R
TABLE2 FK2 R
-- fails: constraint name correct, table name wrong
SQL> alter table table1 drop constraint SYS_C0021482;
ORA-02443: Cannot drop constraint - nonexistent constraint
-- fails: need to disable/remove the FK constraint first
SQL> alter table table1 drop constraint SYS_C0021483;
ORA-02273: this unique/primary key is referenced by some foreign keys
-- okay
SQL> alter table table1 drop constraint FK1 ;
Table TABLE1 altered.
If you just want to drop both tables, including all constraints, use ...
SQL> drop table table1 cascade constraints purge ;
Table TABLE1 dropped.
SQL> drop table table2 cascade constraints purge ;
Table TABLE2 dropped.
Check:
-- any constraints left? no.
SQL> select table_name, constraint_name, constraint_type
2 from user_constraints
3 where table_name in( 'TABLE1', 'TABLE2' ) ;
no rows selected

How to delete the primary key from without using constraint name

CREATE TABLE Persons (
ID int PRIMARY KEY,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Age int
);
How to remove the primary key as there is no constraint defined?
"How to remove PK as there is no constraint defined?"
Actually it's every bit as simple as you might hope:
SQL> create table t23 (id number primary key);
Table created.
SQL> select constraint_name, constraint_type
2 from user_constraints
3 where table_name = 'T23'
4 /
CONSTRAINT_NAME C
------------------------------ -
SYS_C0034419 P
SQL> alter table t23 drop primary key;
Table altered.
SQL> select constraint_name, constraint_type
2 from user_constraints
3 where table_name = 'T23'
4 /
no rows selected
SQL>
run this to get constraint name :
SELECT *
FROM user_cons_columns
WHERE table_name = Persons;
then run
ALTER TABLE Persons
DROP CONSTRAINT <pk constraint>;
Don't think you can do it in 1 SQL command,without knowing the constraint name, but you can know the constraint name as in this case it would be defined by system. Something which starts with SYS.....
Alternatively you can use a PLSQL block to achieve the same.
See the example below for your case.
CREATE TABLE Persons (
ID int PRIMARY KEY,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Age int
);
Find constraint name
select CONSTRAINT_NAME
From USER_CONSTRAINTS
where table_name='PERSONS'
AND CONSTRAINT_TYPE='P';
OUTPUT:= SYS_C0012152
Drop Constraint
ALTER TABLE PERSONS
DROP CONSTRAINT SYS_C0012152;
Note: The constraint name SYS_C0012152 is not enclosed in single quotes.
PLSQL Block to do the same
declare
sql_stmt varchar2(255);
cons_name varchar2(30);
begin
select CONSTRAINT_NAME
into cons_name
From USER_CONSTRAINTS
where table_name='PERSONS'
AND CONSTRAINT_TYPE='P';
sql_stmt:=' ALTER TABLE PERSONS
DROP CONSTRAINT '||cons_name;
dbms_output.put_line(sql_stmt);
execute immediate sql_stmt;
end;

How to get list of tables which have foreign keys to my table ?

I want to truncate table tableA, but I have to disable all foreign keys or drop them which referes to tableA before I do this. Could you tell me the way how to get name of tables which have foregin keys to tableA?
OK, so suppose I want to drop the DEPT table from the SCOTT schema. I check and find out it has a primary key named PK_DEPT. Then I run the query below (against the table ALL_CONSTRAINTS) and find the schema and table that references this table.
Just remember that all string values (table names, constraint types etc.) are always UPPER CASE in all catalog tables. This is important when you write the WHERE conditions.
select owner, table_name
from all_constraints
where constraint_type = 'R' and r_owner = 'SCOTT' and r_constraint_name = 'PK_DEPT';
OWNER TABLE_NAME
-------------------- --------------------
SCOTT EMP
1 row selected.
A general solution.
List all tables and owners that have a foreign key constraint for table :tablename that are of type P (Primary key) or U (unique constraint)
select owner, table_name, constraint_name
from all_constraints
where r_constraint_name in (select constraint_name
from all_constraints
where table_name = :tablename
and constraint_type in ('P', 'U'));

How to remove constraint based on columns from oracle database?

Is there is a way to remove a constraint (unique index) based on columns name?
What I would like to do is to remove a constraint where columna name is name, and name_type.
ALTER TABLE MY_TABLE DROP CONSTRAINT NAME_OF_CONSTRAINT;
I don't have a name so I would like to do it this way...
ALTER TABLE MY_TABLE DROP CONSTRAINT **WHERE COLUMN = col1 AND column = col2**
Any syntax to do something like this on a constraint.
I didn't think this was possible with a single statement, but it turns out it is, as shown in the examples in the documentation:
ALTER TABLE MY_TABLE DROP UNIQUE(col1, col2);
A complete example:
ALTER TABLE MY_TABLE ADD UNIQUE (col1, col2);
Table my_table altered.
SELECT CONSTRAINT_NAME, INDEX_NAME
FROM USER_CONSTRAINTS
WHERE TABLE_NAME = 'MY_TABLE';
CONSTRAINT_NAME INDEX_NAME
------------------------------ ------------------------------
SYS_C0092455 SYS_C0092455
ALTER TABLE MY_TABLE DROP UNIQUE(col1, col2);
Table my_table altered.
SELECT CONSTRAINT_NAME, INDEX_NAME
FROM USER_CONSTRAINTS
WHERE TABLE_NAME = 'MY_TABLE';
no rows selected
An alternative approach is to query the USER_CONSTRAINTS and USER_CONS_COLUMNS views to find the matching constraint name - presumably system-generated or you would already know it - and then use that name. If you need to do this as a script then you could query in a PL/SQL block, and plug the found constraint name into a dynamic ALTER TABLE statement.
Do a SELECT * FROM USER_CONS_COLUMNS or ALL_CONS_COLUMNS. This will give you the constraint name for the owner, table and column combination.
Out of the multiple rows returned for a column name, use the constraint names as necessary in the ALTER TABLE ... DROP CONSTRAINT... syntax.
Use dynamic sql to do it for all rows in a loop if you are absolutely sure that you can drop all of them.
This will give you an extra layer of protection so that you don't accidentally drop a constraint that was needed.

Oracle Forced dropping of Foreign Key during purge on Interval Partitioned Tables

We have several tables which are interval partitioned by day. While working on a purge job to drop a day of partitioning, our DBA has informed us that we will have to drop all foreign keys to any table, before performing the purge. This seems like an unnecessary step, and thus, I am turning to the wisdom of stackoverflow.
parentTable childTable
ID (PK) ID (PK)(FK)
date (PK) date (PK)(FK)
otherKey(PK)
parentTable childTable
ID date ID date otherKey
1 10/23 1 10/23 a
2 10/23 2 10/23 a
3 10/23 3 10/23 a
1 10/24 1 10/24 a
2 10/24 2 10/24 a
2 10/24 b
The question is, if we were to drop the 10/23 partition from childTable (first), then parentTable, would we have to drop/disable the Foreign Key constraint before the purge, and create it again afterwards? Is there a data situation where this would have to occur (maybe not as shown in my example above).
Seems that the DBA was right, test case scenario:
CREATE TABLE parent_tab (
id NUMBER PRIMARY KEY,
start_date DATE
)
PARTITION BY RANGE (start_date)
INTERVAL(NUMTODSINTERVAL(1, 'DAY'))
(
PARTITION pos_data_p2 VALUES LESS THAN (TO_DATE('01-01-2013', 'DD-MM-YYYY'))
);
INSERT INTO parent_tab VALUES (1, DATE '2012-01-01');
INSERT INTO parent_tab VALUES (2, DATE '2013-01-02');
INSERT INTO parent_tab VALUES (3, DATE '2013-01-03');
CREATE TABLE child_tab (
start_date DATE,
parent_tab_id NUMBER REFERENCES parent_tab(id)
)
PARTITION BY RANGE (start_date)
INTERVAL(NUMTODSINTERVAL(1, 'DAY'))
(
PARTITION pos_data_p2 VALUES LESS THAN (TO_DATE('01-01-2013', 'DD-MM-YYYY'))
);
INSERT INTO child_tab VALUES (DATE '2012-01-01', 1);
INSERT INTO child_tab VALUES (DATE '2013-01-02', 2);
INSERT INTO child_tab VALUES (DATE '2013-01-03', 3);
COMMIT;
SELECT table_name, partition_name FROM user_tab_partitions WHERE table_name IN ('PARENT_TAB', 'CHILD_TAB');
TABLE_NAME PARTITION_NAME
------------------------------ ------------------------------
CHILD_TAB POS_DATA_P2
CHILD_TAB SYS_P69
CHILD_TAB SYS_P70
PARENT_TAB POS_DATA_P2
PARENT_TAB SYS_P67
PARENT_TAB SYS_P68
ALTER TABLE child_tab DROP PARTITION SYS_P69;
> table CHILD_TAB altered.
ALTER TABLE parent_tab DROP PARTITION SYS_P67;
ALTER TABLE parent_tab DROP PARTITION SYS_P67
Error report:
SQL Error: ORA-02266 - "unique/primary keys in table referenced by enabled foreign keys"
*Cause: An attempt was made to truncate a table with unique or
primary keys referenced by foreign keys enabled in another table.
Other operations not allowed are dropping/truncating a partition of a
partitioned table or an ALTER TABLE EXCHANGE PARTITION.
*Action: Before performing the above operations the table, disable the
foreign key constraints in other tables. You can see what
constraints are referencing a table by issuing the following
command:
SELECT * FROM USER_CONSTRAINTS WHERE TABLE_NAME = "tabnam";
Edit
As the author pointed out, disabling the constraint works:
SELECT table_name, constraint_name, constraint_type FROM user_constraints WHERE table_name = 'CHILD_TAB';
TABLE_NAME CONSTRAINT_NAME CONSTRAINT_TYPE
------------------------------ ------------------------------ ---------------
CHILD_TAB SYS_C0033723 R
ALTER TABLE child_tab DISABLE CONSTRAINT SYS_C0033723;
ALTER TABLE parent_tab DROP PARTITION SYS_P67;
> table PARENT_TAB altered.
ALTER TABLE child_tab ENABLE CONSTRAINT SYS_C0033723;
Some day i will learn to manage there my code, So..
CREATE OR REPLACE PROCEDURE manage_constraints (i_status IN varchar2)
IS
CURSOR ref_cons
IS
SELECT constraint_name, table_name, status
FROM user_constraints
WHERE constraint_type in ( 'R') ; -- YOu can disable more constraints type
v_status VARCHAR2 (10);
v_sql VARCHAR2 (300);
BEGIN
FOR e_cons IN ref_cons
LOOP
v_sql :=
'ALTER TABLE '
|| e_cons.table_name
|| ' '
|| i_status
|| ' CONSTRAINT '
|| e_cons.constraint_name;
--DBMS_OUTPUT.put_line (v_sql);
EXECUTE IMMEDIATE v_sql;
END LOOP;
EXCEPTION
WHEN OTHERS
THEN
RAISE;
END;
--exec manage_constraints('DISABLE');
--exec manage_constraints('ENABLE');
There you can just DISABLE all you constraints and later ENABLE them.
select * from user_constraints
check constraint types... hope this helps.
Not a direct answer, but it sounds like what you really want here is reference partitioning, which would:
cascade partition maintenance operations
Allow more simple queries
Provide metadata that the two tables' partitions are logically associated
Possibly add a small overhead on the inserts into the child tables.
http://docs.oracle.com/cd/B28359_01/server.111/b32024/partition.htm#CACIHDII

Resources