I am trying to move data from parent table which is interval partitioned, and a child table partitioned by reference, into corresponding archive table structure.
And to my suprise this seemingly simple task is beyond my reach...
I have read about moving partitioned table to archive but it do not tell how to move tables with foregin keys.
I also read about moving reference partitioned tables, but this solution does not work for me, giving this error after first statement:
ORA-02266: unique/primary keys in table referenced by enabled foreign keys
So, I have tried my own approach. It gives me even worse error:
ORA-00600: internal error code, arguments: [kkpamRefGet: index], [], [], [], [], [], [], [], [], [], [], []
You can reproduce my latest attempt like this:
/*
DROP TABLE CHILD_TABLE
/
DROP TABLE CHILD_TABLE_ARCHIVE
/
DROP TABLE CHILD_TABLE_TMP
/
DROP TABLE PARENT_TABLE
/
DROP TABLE PARENT_TABLE_ARCHIVE
/
DROP TABLE PARENT_TABLE_TMP
/
*/
-- SAMPLE STRUCTURE
CREATE TABLE PARENT_TABLE
(
PARTITION_DATE DATE NOT NULL,
PK NUMBER NOT NULL
)
PARTITION BY RANGE (PARTITION_DATE)
INTERVAL( NUMTOYMINTERVAL(1, 'YEAR'))
(
PARTITION PARTITION_1 VALUES LESS THAN (TIMESTAMP' 2017-01-01 00:00:00'),
PARTITION PARTITION_2 VALUES LESS THAN (TIMESTAMP' 2018-01-01 00:00:00')
)
/
ALTER TABLE PARENT_TABLE ADD (CONSTRAINT PK_PARENT_TABLE PRIMARY KEY (PK) ENABLE VALIDATE)
/
CREATE TABLE CHILD_TABLE
(
PK NUMBER NOT NULL,
FK_PARENT NUMBER NOT NULL,
CONSTRAINT FK_CHILD_TABLE
FOREIGN KEY (FK_PARENT)
REFERENCES PARENT_TABLE (PK)
ON DELETE CASCADE
ENABLE VALIDATE
)
PARTITION BY REFERENCE (FK_CHILD_TABLE)
/
CREATE TABLE PARENT_TABLE_ARCHIVE
(
PARTITION_DATE DATE NOT NULL,
PK NUMBER NOT NULL
)
PARTITION BY RANGE (PARTITION_DATE)
INTERVAL( NUMTOYMINTERVAL(1, 'YEAR'))
(
PARTITION PARTITION_1 VALUES LESS THAN (TIMESTAMP' 2017-01-01 00:00:00'),
PARTITION PARTITION_2 VALUES LESS THAN (TIMESTAMP' 2018-01-01 00:00:00')
)
/
ALTER TABLE PARENT_TABLE_ARCHIVE ADD (CONSTRAINT PK_PARENT_TABLE_ARCHIVE PRIMARY KEY (PK) ENABLE VALIDATE)
/
CREATE TABLE CHILD_TABLE_ARCHIVE
(
PK NUMBER NOT NULL,
FK_PARENT NUMBER NOT NULL,
CONSTRAINT FK_CHILD_TABLE_ARCHIVE
FOREIGN KEY (FK_PARENT)
REFERENCES PARENT_TABLE_ARCHIVE (PK)
ON DELETE CASCADE
ENABLE VALIDATE
)
PARTITION BY REFERENCE (FK_CHILD_TABLE_ARCHIVE)
/
CREATE TABLE PARENT_TABLE_TMP AS SELECT * FROM PARENT_TABLE WHERE 1 = 2
/
CREATE TABLE CHILD_TABLE_TMP AS SELECT * FROM CHILD_TABLE WHERE 1 = 2
/
-- SAMPLE DATA
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2017-01-01','YYYY-MM-DD'),1)
/
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2018-01-01','YYYY-MM-DD'),2)
/
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2019-01-01','YYYY-MM-DD'),3)
/
INSERT INTO CHILD_TABLE VALUES (1,1)
/
INSERT INTO CHILD_TABLE VALUES (2,2)
/
INSERT INTO CHILD_TABLE VALUES (3,3)
/
-- My last attempt to do this
ALTER TABLE CHILD_TABLE
EXCHANGE PARTITION PARTITION_2
WITH TABLE CHILD_TABLE_TMP
/
ALTER TABLE PARENT_TABLE
EXCHANGE PARTITION FOR (TO_DATE('2017-01-01','YYYY-MM-DD'))
WITH TABLE PARENT_TABLE_TMP
/
--Without this constraint I am geting: ORA-14130: UNIQUE constraints mismatch in ALTER TABLE EXCHANGE PARTITION
ALTER TABLE PARENT_TABLE_TMP ADD (CONSTRAINT PK_PARENT_TABLE_TMP PRIMARY KEY (PK) ENABLE VALIDATE)
/
ALTER TABLE PARENT_TABLE_ARCHIVE
EXCHANGE PARTITION FOR (TO_DATE('2017-01-01','YYYY-MM-DD'))
WITH TABLE PARENT_TABLE_TMP
/
--Without this constraint I am geting: ORA-14128: FOREIGN KEY constraint mismatch in ALTER TABLE EXCHANGE PARTITION
ALTER TABLE CHILD_TABLE_TMP ADD
CONSTRAINT FK_CHILD_TABLE_TMP
FOREIGN KEY (FK_PARENT)
REFERENCES PARENT_TABLE_ARCHIVE (PK)
ON DELETE CASCADE
ENABLE VALIDATE
/
-- And here is something starange...
ALTER TABLE CHILD_TABLE_ARCHIVE
EXCHANGE PARTITION PARTITION_2
WITH TABLE CHILD_TABLE_TMP
/
Currently, I am out of ideas how should I do this, and I am starting to wonder should I even try to move this structure to archive... It is partitioned by dates, so can I just let it grow?
I would appreciate any help in this matter. :)
UPDATE:
Just as Francisco suggested, CASCADE option helped with my sample code. Below is my sample code in working condition.
But, in my real life scenario there is more than one child to parent table. And so, when I try to use CASCADe option I get ORA-14706. The proposed solution is not to use CASCADE option...
So I still can not archive my tables, and still really need help.
DROP TABLE CHILD_TABLE
/
DROP TABLE CHILD_TABLE_ARCHIVE
/
DROP TABLE CHILD_TABLE_TMP
/
DROP TABLE PARENT_TABLE
/
DROP TABLE PARENT_TABLE_ARCHIVE
/
DROP TABLE PARENT_TABLE_TMP
/
-- SAMPLE STRUCTURE
CREATE TABLE PARENT_TABLE
(
PARTITION_DATE DATE NOT NULL,
PK NUMBER NOT NULL
)
PARTITION BY RANGE (PARTITION_DATE)
INTERVAL( NUMTOYMINTERVAL(1, 'YEAR'))
(
PARTITION PARTITION_1 VALUES LESS THAN (TIMESTAMP' 2017-01-01 00:00:00'),
PARTITION PARTITION_2 VALUES LESS THAN (TIMESTAMP' 2018-01-01 00:00:00')
)
/
ALTER TABLE PARENT_TABLE ADD (CONSTRAINT PK_PARENT_TABLE PRIMARY KEY (PK) ENABLE VALIDATE)
/
CREATE TABLE CHILD_TABLE
(
PK NUMBER NOT NULL,
FK_PARENT NUMBER NOT NULL,
CONSTRAINT FK_CHILD_TABLE
FOREIGN KEY (FK_PARENT)
REFERENCES PARENT_TABLE (PK)
ON DELETE CASCADE
ENABLE VALIDATE
)
PARTITION BY REFERENCE (FK_CHILD_TABLE)
/
CREATE TABLE PARENT_TABLE_ARCHIVE
(
PARTITION_DATE DATE NOT NULL,
PK NUMBER NOT NULL
)
PARTITION BY RANGE (PARTITION_DATE)
INTERVAL( NUMTOYMINTERVAL(1, 'YEAR'))
(
PARTITION PARTITION_1 VALUES LESS THAN (TIMESTAMP' 2017-01-01 00:00:00'),
PARTITION PARTITION_2 VALUES LESS THAN (TIMESTAMP' 2018-01-01 00:00:00')
)
/
ALTER TABLE PARENT_TABLE_ARCHIVE ADD (CONSTRAINT PK_PARENT_TABLE_ARCHIVE PRIMARY KEY (PK) ENABLE VALIDATE)
/
CREATE TABLE CHILD_TABLE_ARCHIVE
(
PK NUMBER NOT NULL,
FK_PARENT NUMBER NOT NULL,
CONSTRAINT FK_CHILD_TABLE_ARCHIVE
FOREIGN KEY (FK_PARENT)
REFERENCES PARENT_TABLE_ARCHIVE (PK)
ON DELETE CASCADE
ENABLE VALIDATE
)
PARTITION BY REFERENCE (FK_CHILD_TABLE_ARCHIVE)
/
CREATE TABLE PARENT_TABLE_TMP AS SELECT * FROM PARENT_TABLE WHERE 1 = 2
/
CREATE TABLE CHILD_TABLE_TMP AS SELECT * FROM CHILD_TABLE WHERE 1 = 2
/
ALTER TABLE PARENT_TABLE_TMP ADD (CONSTRAINT PK_PARENT_TABLE_TMP PRIMARY KEY (PK) ENABLE VALIDATE)
/
ALTER TABLE CHILD_TABLE_TMP ADD
CONSTRAINT FK_CHILD_TABLE_TMP
FOREIGN KEY (FK_PARENT)
REFERENCES PARENT_TABLE_TMP (PK)
ENABLE VALIDATE
/
-- SAMPLE DATA
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2017-01-01','YYYY-MM-DD'),1)
/
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2018-01-01','YYYY-MM-DD'),2)
/
INSERT INTO PARENT_TABLE VALUES (TO_DATE('2019-01-01','YYYY-MM-DD'),3)
/
INSERT INTO CHILD_TABLE VALUES (1,1)
/
INSERT INTO CHILD_TABLE VALUES (2,2)
/
INSERT INTO CHILD_TABLE VALUES (3,3)
/
ALTER TABLE PARENT_TABLE
EXCHANGE PARTITION FOR (TO_DATE('2017-01-01','YYYY-MM-DD'))
WITH TABLE PARENT_TABLE_TMP
CASCADE UPDATE INDEXES
/
ALTER TABLE PARENT_TABLE_ARCHIVE
EXCHANGE PARTITION FOR (TO_DATE('2017-01-01','YYYY-MM-DD'))
WITH TABLE PARENT_TABLE_TMP
CASCADE UPDATE INDEXES
/
-----creating reference partitioning on existing tables having parent child relationship
----------------------------------------consider the following parent and child table---------------------------------------------------
--create the parent table:
create table t1(
id int,
action_date varchar(8),
constraint t1_pk primary key (id)
);
--create the child table table:
create table t2(
id int,
id_t1,
constraint t2_pk primary key (id),
constraint t2_fk1 foreign key (id_t1) references t1(id)
);
---insert sample data into parent
insert into t1 values(1,'20170801');
insert into t1 values(2,'20170901');
insert into t1 values(3,'20171001');
---insert sample data into child
insert into t2 values(1,1);
insert into t2 values(2,1);
insert into t2 values(3,1);
insert into t2 values(4,2);
insert into t2 values(5,1);
insert into t2 values(6,2);
insert into t2 values(7,3);
---------------------------------------------------------creating intermediate table for partitioning-----------------------------------------------------------------
-----------------parent table-------------------------
create table t1_part(
id int,
action_date varchar(8),
constraint t1_part_pk primary key (id)
) PARTITION BY RANGE (action_date)
(
PARTITION t1_part_old VALUES LESS THAN ('20171101'),
PARTITION t1_part_201711 VALUES LESS THAN ('20171201'),
PARTITION t1_part_201712 VALUES LESS THAN ('20180101'),
PARTITION t1_part_def VALUES LESS THAN ('99999999')
);
-------------------dropping constraints-----------------
ALTER TABLE t2 DROP constraint t2_fk1;
ALTER TABLE t1 DROP constraint t1_pk;
ALTER TABLE t1_part DROP constraint t1_part_pk;
desc t1;
desc t1_part;
-------------------------switch parent data to partitioned table from unpartitionedtable-------------------------------
ALTER TABLE t1_part EXCHANGE PARTITION t1_part_old WITH TABLE t1 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t1_part EXCHANGE PARTITION t1_part_201711 WITH TABLE t1 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t1_part EXCHANGE PARTITION t1_part_201712 WITH TABLE t1 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t1_part EXCHANGE PARTITION t1_part_def WITH TABLE t1 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
--------------------------------update stats----------------------------------
EXEC DBMS_STATS.gather_table_stats('SYSTEM', 'T1', cascade => TRUE);
ALTER TABLE t1_part add constraint t1_part_pk primary key (id);
--select * from t1_part;
drop table t1;
RENAME t1_part TO t1;
ALTER TABLE t1 RENAME CONSTRAINT t1_part_pk TO t1_pk;
ALTER TABLE t2 add constraint t2_fk1 foreign key (id_t1) references t1(id);
--------------------------------update stats----------------------------------
EXEC DBMS_STATS.gather_table_stats('SYSTEM', 'T1', cascade => TRUE);
----------------------create partitioned child table---------------------------------------------
create table t2_part(
id int,
id_t1 not null,
constraint t2_part_pk primary key (id),
constraint t2_part_fk1 foreign key (id_t1) references t1(id)
) partition by reference (t2_part_fk1);
alter table t2 modify (id_t1 int not null);
desc t2;
desc t2_part
-------------------------switch child data to partitioned table from unpartitionedtable-------------------------------
ALTER TABLE t2_part EXCHANGE PARTITION t1_part_old WITH TABLE t2 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t2_part EXCHANGE PARTITION t1_part_201711 WITH TABLE t2 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t2_part EXCHANGE PARTITION t1_part_201712 WITH TABLE t2 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
ALTER TABLE t2_part EXCHANGE PARTITION t1_part_def WITH TABLE t2 WITHOUT VALIDATION UPDATE GLOBAL INDEXES;
--select * from t2_part;
drop table t2;
RENAME t2_part TO t2;
ALTER TABLE t2 RENAME CONSTRAINT t2_part_pk TO t2_pk;
ALTER TABLE t2 RENAME CONSTRAINT t2_part_fk1 TO t2_fk1;
--------------------------------update stats----------------------------------
EXEC DBMS_STATS.gather_table_stats('SYSTEM', 'T2', cascade => TRUE);
-----------------------------------check partition info---------------------------------------------
select table_name, partition_name, high_value
from user_tab_partitions
where table_name in ('T1','T2');
desc t1;
desc t2;
-----------------add new parent partition, child partiion will automatically get created thorugh reference paritioning through foreign key t2_part_fk1
ALTER TABLE T1 SPLIT PARTITION t1_part_old AT ('20170701') INTO (PARTITION t1_part_old, PARTITION t1_part_201707) UPDATE GLOBAL INDEXES;
ALTER TABLE T1 SPLIT PARTITION t1_part_201707 AT ('20170801') INTO (PARTITION t1_part_201707, PARTITION t1_part_201708) UPDATE GLOBAL INDEXES;
ALTER TABLE T1 SPLIT PARTITION t1_part_201708 AT ('20170901') INTO (PARTITION t1_part_201708, PARTITION t1_part_201709) UPDATE GLOBAL INDEXES;
ALTER TABLE T1 SPLIT PARTITION t1_part_201709 AT ('20171001') INTO (PARTITION t1_part_201709, PARTITION t1_part_201710) UPDATE GLOBAL INDEXES;
EXEC DBMS_STATS.gather_table_stats('SYSTEM', 'T1', cascade => TRUE);
--------------------validating the partitioned data--------------------
select count(*) from T1 partition (T1_PART_OLD);
select * from T1 partition (T1_PART_201708);
select count(*) from T1 partition (T1_PART_201709);
select count(*) from T1 partition (T1_PART_201710);
select count(*) from T1 partition (T1_PART_201711);
select * from T2;
select * from T1;
select count(*) from T2 partition (T1_PART_OLD);
select * from T2 partition (T1_PART_201708);
select count(*) from T2 partition (T1_PART_201709);
select count(*) from T2 partition (T1_PART_201710);
select count(*) from T2 partition (T1_PART_201711);
-------truncate the partition T1_PART_201708 (refering the parent partition) and validate the data
alter table t2 truncate partition T1_PART_201708;
select * from t2; ----------------- data from 20170801 to 20170831 will be truncated from child
-------truncate the parent record
alter table t1 drop partition T1_PART_201708;
select * from t1;
Related
Example Oracle SQL Code:
create table t1 (
t1a integer,
t1b varchar2(30)
);
alter table t1 add constraint t1_pk primary key (t1a);
insert into t1 values (1, 'A');
insert into t1 values (2, 'B');
create table t11 (
t11a integer,
t1a integer,
t11b varchar2(30)
);
alter table t11 add constraint t11_pk primary key (t11a);
alter table t11 add constraint t11_t1_fk foreign key (t1a) references t1(t1a);
insert into t11 values (10, 1, 'A1');
insert into t11 values (11, 2, 'B1');
create table t12 (
t12a integer,
t1a integer,
t12b varchar2(30)
);
alter table t12 add constraint t12_pk primary key (t12a);
alter table t12 add constraint t12_t1_fk foreign key (t1a) references t1(t1a);
insert into t12 values (20, 1, 'A2');
insert into t12 values (21, 2, 'B2');
create table t1112 (
t11a integer,
t12a integer
);
alter table t1112 add constraint t1112_pk primary key (t11a, t12a);
alter table t1112 add constraint t1112_t11_fk foreign key (t11a) references t11(t11a);
alter table t1112 add constraint t1112_t12_fk foreign key (t12a) references t12(t12a);
create or replace trigger t1112_trg before insert or update on t1112 for each row
declare
t11a_v integer;
t12a_v integer;
begin
select t11.t1a into t11a_v from t11 where t11.t11a = :new.t11a;
select t12.t1a into t12a_v from t12 where t12.t12a = :new.t12a;
if (t11a_v != t12a_v) then
raise_application_error(-20000, 'Mismatch');
end if;
end;
/
Top level table: t1.
t11 and t12 have a foreign key reference to t1.
t1112 is an intersection table between t1 and t2.
I want to ensure that any rows written into t1112 have a combination of t11 and t12 such that they both point to the same row in t1.
I have tried to implement it with a trigger in the example. Is there a way to do this via referential integrity constraints?
The easiest way is to create additional unique constraints on tables t11 and t12:
ALTER TABLE t11 ADD CONSTRAINT t11_un UNIQUE ( t11a, t1a );
ALTER TABLE t12 ADD CONSTRAINT t12_un UNIQUE ( t12a, t1a );
Add column t1a to table T1112
ALTER TABLE t1112 ADD (t1a integer);
Drop and recreate your foreign key constraints on t1112:
ALTER TABLE T1112 DROP CONSTRAINT T1112_T11_FK;
ALTER TABLE T1112 ADD CONSTRAINT T1112_T11_FK FOREIGN KEY (t11a, t1a ) REFERENCES T11 (t11a, t1a);
ALTER TABLE T1112 DROP CONSTRAINT T1112_T12_FK;
ALTER TABLE T1112 ADD CONSTRAINT T1112_T12_FK FOREIGN KEY (t12a, t1a ) REFERENCES T12 (t12a, t1a);
Such that they now use the two unique constraints instead of the primary keys. The shared column t1a in the join table will ensure that the keys from t11 and t12 join back to t1.
Use a materialized view:
CREATE MATERIALIZED VIEW t11_t12_mv
BUILD IMMEDIATE
AS SELECT t11a, t12a
FROM t11 INNER JOIN t12 ON t11.t1a = t12.t1a;
ALTER TABLE t11_t12_mv ADD CONSTRAINT t11a_t12a__pk PRIMARY KEY ( t11a, t12a );
create table t1112 (
t11a integer,
t12a integer,
CONSTRAINT t1112_pk PRIMARY KEY (t11a, t12a),
CONSTRAINT t1112_fk FOREIGN KEY (t11a, t12a) REFERENCES t11_t12_mv ( t11a, t12a )
);
Then:
INSERT INTO t1112 VALUES ( 10, 20 );
INSERT INTO t1112 VALUES ( 11, 21 );
Works. However:
INSERT INTO t1112 VALUES ( 10, 21 );
Raises the exception:
ORA-02291: integrity constraint (USER_4_F249D.T1112_FK) violated - parent key not found
sqlfiddle here
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
I haven't tried this yet, it's part of a 90+ tables schema that I'm rebuilding and I was wondering if the logic was right. I have two tables which contain data and a third one that joins PKs from them:
CREATE TABLE TABLE1
(
USER_ID NUMBER(9),
DEPARTMENT_ID NUMBER(9),
DESK_ID NUMBER(9),
FULLNAME VARCHAR2(12),
CONSTRAINT PK_TABLE1 PRIMARY KEY (USER_ID, DEPARTMENT_ID, DESK_ID)
);
CREATE TABLE TABLE2
(
USER_ID NUMBER(9),
BUILDING_ID NUMBER(9),
PARKING_ID NUMBER(9),
LICENSE_PLATE VARCHAR2(10),
CONSTRAINT PK_TABLE2 PRIMARY KEY (USER_ID, BUILDING_ID, PARKING_ID)
);
CREATE TABLE TABLE3
(
USER_ID NUMBER(9),
DEPARTMENT_ID NUMBER(9),
DESK_ID NUMBER(9),
BUILDING_ID NUMBER(9),
PARKING_ID NUMBER(9),
CONSTRAINT PK_TABLE3 PRIMARY KEY (USER_ID, DEPARTMENT_ID, DESK_ID, BUILDING_ID, PARKING_ID),
CONSTRAINT FK_TABLE3_T1 FOREIGN KEY (USER_ID, DEPARTMENT_ID, DESK_ID) REFERENCES TABLE1(USER_ID, DEPARTMENT_ID, DESK_ID),
CONSTRAINT FK_TABLE3_T2 FOREIGN KEY (USER_ID, BUILDING_ID, PARKING_ID) REFERENCES TABLE2(USER_ID, BUILDING_ID, PARKING_ID)
);
Is it right? Can the same column TABLE3.USER_ID be part of two FKs?
Thanks
Yes you can, even with the same column list.
Try this:
CREATE TABLE T1
(C1 NUMBER PRIMARY KEY);
CREATE TABLE T2
(C1 NUMBER PRIMARY KEY);
CREATE TABLE T3
(C1 NUMBER PRIMARY KEY);
Populate T1 and T2 with some values:
INSERT INTO T1 VALUES(1);
INSERT INTO T1 VALUES(2);
INSERT INTO T2 VALUES(1);
INSERT INTO T2 VALUES(3);
Create two identical constraints from T3 to T1 and T2:
ALTER TABLE T3
ADD CONSTRAINT FK1 FOREIGN KEY (C1) REFERENCES T1(C1);
ALTER TABLE T3
ADD CONSTRAINT FK2 FOREIGN KEY (C1) REFERENCES T2(C1);
And now...
INSERT INTO T3 VALUES(1); -- Succeeds (1 is in both T1 and T2)
INSERT INTO T3 VALUES(2); -- Fails (2 is only in T1 and violates FK2)
Clean your environment:
DROP TABLE T3 PURGE;
DROP TABLE T1 PURGE;
DROP TABLE T2 PURGE;
I hope this helps you...
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
I have two tables A and B .i want to copy or show the primary key column value from table A in the foreign key column in table B respectively .is there any method kindly help me.
Regards,
You can populate your primary key value while populating table B or by using a trigger when you are populating table A.
CREATE TABLE t1 (id1 NUMBER, dt DATE);
ALTER TABLE t1 ADD (
CONSTRAINT t1_pk
PRIMARY KEY
(id1));
CREATE TABLE t2 (id2 NUMBER, id1 NUMBER, dt2 DATE);
ALTER TABLE t2 ADD (
CONSTRAINT t2_pk
PRIMARY KEY
(id2));
ALTER TABLE t2
ADD CONSTRAINT t2_r01
FOREIGN KEY (id2)
REFERENCES t1 (id1);
First Approach, by this way you could populate second table when you are inserting values.
INSERT INTO t1
VALUES (1, SYSDATE
);
INSERT INTO t2
VALUES (1, 1, SYSDATE
);
With trigger, so when values are inserted into first table second tables values are populated using a trigger. So primary key value of first table is being inserted into foreign key of table 2.
CREATE OR REPLACE TRIGGER my_trigger
AFTER INSERT
ON t1
FOR EACH ROW
BEGIN
INSERT INTO t2
VALUES (1, :new.id1, SYSDATE
);
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (TO_CHAR (SQLERRM (-20299)));
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (TO_CHAR (SQLERRM (-20298)));
END;