Exchanging Range-Partitions with Local Indexes - oracle

We have tables with range partitions of a month interval. The indexes on the tables including the primary key are local indexes.
However, when exchanging the partition from these tables with a table without partition, the local indexes become UNUSABLE. In the Oracle documentation, it only talks about issues with Global indexes. So we converted the global primary indexes to local by adding the partitioned key to the index.
Example queries -
CREATE TABLE sourcetable
(owner varchar2(30), OBJECT_NAME VARCHAR2(100))
PARTITION BY RANGE (owner)
(PARTITION P1 VALUES LESS THAN (MAXVALUE));
CREATE TABLE DESTTABLE
(owner varchar2(30), OBJECT_NAME VARCHAR2(100));
create index sourcetable_idx
on sourcetable ( owner )
local ;
alter table sourcetable add constraint src_pk primary key ( owner );
insert into sourcetable select U.OBJECT_ID, u.object_name from user_objects u
where rownum <11;
select index_name,partition_name,status from user_ind_partitions
where index_name IN (
select index_name from user_indexes
where table_name = 'SOURCETABLE'
);
The select gives the index status as
USABLE
ALTER TABLE sourcetable
EXCHANGE PARTITION p1 WITH TABLE desttable;
select index_name,partition_name,status from user_ind_partitions
where index_name IN (
select index_name from user_indexes
where table_name = 'SOURCETABLE'
);
The select on index status after exchanging the partition gives the index status as
UNUSABLE
We want to do online partition exchange. Is there any way we can do the exchange using statements like
UPDATE INDEXES
with the
EXCHANGE PARTITION
statement?
We tried using EXCHANGE statement with UPDATE INDEXES, but the indexes still became UNUSABLE.
ALTER TABLE sourcetable
EXCHANGE PARTITION p1 WITH TABLE desttable UPDATE INDEXES;

UPDATE INDEXES applies only for global indexes. Since you don't have any, this clause has no effect.
You must use INCLUDING INDEXES. However, for this you must create the same indexes on source and destination table. Try this one:
CREATE INDEX desttable_idx ON desttable ( OWNER );
ALTER TABLE sourcetable EXCHANGE PARTITION p1 WITH TABLE desttable INCLUDING INDEXES;

Related

Oracle how to archive reference partitioned table

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;

Automatic list partitioning

I'm using Oracle 11g.
I have large table that I want to add partitions. My partition (and subpartition) key column is of VARCHAR2 type.
I know that there is an INTERVAL RANGE PARTITION that can be auto-created but I need to do the same thing with list partition. Is there a way to do that with VARCHAR2 type (which doesn't represent any date).
Example:
create table t1 (name varchar2(30), company varchar2(10), value number);
I want that for every new name there will be a new partition. Is there a way to do that without writing specific PL/SQL code that will check if a new partition is needed and will do the creation? Maybe with some pattern or something...
Automatic list partitioning was added in 12.2. So you need to upgrade to do this.
In the meantime, you can create a catch-all, default partition. Then split new values out as needed:
create table t (
c1 int
) partition by list ( c1 ) (
partition pdef values ( default )
);
select partition_name, high_value
from user_tab_partitions
where table_name = 'T';
PARTITION_NAME HIGH_VALUE
PDEF default
insert into t values ( 1 );
insert into t values ( 2 );
alter table t
split partition pdef
values ( 1 ) into (
partition p1, partition pdef
);
alter table t
split partition pdef
values ( 2 ) into (
partition p2, partition pdef
);
select partition_name, high_value
from user_tab_partitions
where table_name = 'T';
PARTITION_NAME HIGH_VALUE
P1 1
P2 2
PDEF default
When you get to 12.2, you can switch it to auto-list. But you need to drop the default partition first!
alter table t set partitioning automatic;
ORA-14852: SET [SUB]PARTITIONING AUTOMATIC is not legal on this table.
alter table t drop partition pdef;
alter table t set partitioning automatic;
insert into t values ( 3 );
select partition_name, high_value
from user_tab_partitions
where table_name = 'T';
PARTITION_NAME HIGH_VALUE
P1 1
P2 2
SYS_P5201 3

Oracle find dependent columns of function based index

How can I create a query to return the user columns that are referenced from an Oracle function-based index?
Eg. I create an index such as:
CREATE INDEX MY_INDEX ON MY_TABLE (SQRT(MY_COL));
For non-function based indexes I just query ALL_IND_COLUMNS such as:
SELECT INDEX_NAME, COLUMN_NAME, COLUMN_POSITION
FROM ALL_IND_COLUMNS
WHERE INDEX_NAME = 'MY_INDEX'
However, this query returns COLUMN_NAME of a system generated column such as 'SYS_NC00012$' instead of the actual table column 'MY_COL' that the function-based index uses.
I know I can query DBMS_METADATA and read the returned index creation DDL
SELECT DBMS_METADATA.GET_DDL('INDEX', 'MY_INDEX') AS QUERY_STRING FROM DUAL
but this means I have to parse the function text which is not reliable for my purposes.
Therefore, can anyone please point me in the right direction as to how I can precisely determine which actual table columns a function-based index is defined upon?
SQL> Create table my_table ( my_col int);
Table Created;
SQL> CREATE INDEX MY_INDEX ON MY_TABLE (SQRT(MY_COL));
Index Created
SQL> select
2 table_name c1,
3 index_name c2,
4 column_expression c3
5 from
6 dba_ind_expressions
7 where
8 table_name='MY_TABLE';
Table Index
name Name Expression
------------------------ ------------------------- ---------------------------------------
MY_TABLE MY_INDEX SQRT("MY_COL")
you can do some trick with "COMMENT ON COLUMN" , try this
Create table my_table ( my_col int);
CREATE INDEX MY_INDEX ON MY_TABLE (SQRT(my_col));
COMMENT ON COLUMN my_table.my_col IS 'MY_INDEX:my_col'; -- add your index:col
select * from ALL_COL_COMMENTS where table_NAME ='MY_TABLE'
you can use this trick function based index.

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

How can I import a partition from one table into another in Oracle?

I would like to know if the following steps are possible and how fast this is:
Create a partition named part1 in Table A
Drop partition part1 in Table B
Import the Table A partition part1 into Table B
Can you provide me with an example if it is possible indeed? Or any resources I can look at?
Note that the tables would have the exact same structure.
You can do something similar with the ALTER TABLE ... EXCHANGE PARTITION command. This would exchange a single partition with a table that has the same structure.
A little example:
/* Partitionned Table Creation */
SQL> CREATE TABLE table_a (
2 ID NUMBER PRIMARY KEY,
3 DATA VARCHAR2(200)
4 )
5 PARTITION BY RANGE (ID) (
6 PARTITION part100 VALUES LESS THAN (100),
7 PARTITION part200 VALUES LESS THAN (200)
8 );
Table created
/* Swap table creation */
SQL> CREATE TABLE swap_table (
2 ID NUMBER PRIMARY KEY,
3 DATA VARCHAR2(200)
4 );
Table created
SQL> INSERT INTO swap_table SELECT ROWNUM, 'a' FROM dual CONNECT BY LEVEL <= 99;
99 rows inserted
SQL> select count(*) from table_a partition (part100);
COUNT(*)
----------
0
This will exchange the partition part100 with the transition table swap_table:
SQL> ALTER TABLE table_a EXCHANGE PARTITION part100 WITH TABLE swap_table;
Table altered
SQL> select count(*) from table_a partition (part100);
COUNT(*)
----------
99

Resources