Problem with alter table big_table modify partition - oracle

I create table:
create table big_table(
bt_id number primary key,
bt_date date,
bt_value varchar2(20)
)
Then I wnat partition this table (code abbreviated):
alter table big_table modify
partition by range (bt_date)
interval(numtoyminterval(1, 'MONTH'))
subpartition by hash (bt_id)
(
partition nn_st_p1 values less than (to_date(' 2019-05-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
subpartitions 4
store in (ipr_tbl),
)online
Error message:
17:20:39 line 1: ORA-14006: invalid partition name
I can't understand what is wrong with my partition name?
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production

Try something like this
CREATE TABLE big_table
(bt_id NUMBER PRIMARY KEY
, bt_date DATE
, bt_value VARCHAR2(20)
)
PARTITION BY RANGE (bt_date) INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
SUBPARTITION BY HASH (bt_id) SUBPARTITIONS 4
(PARTITION nn_st_p1 VALUES LESS THAN (TO_DATE('01-MAY-2019','dd-MON-yyyy'))
)
PARALLEL;

Related

Alternative to VALUES LESS THAN in interval partitioing creation query

As we know that Interval partitioning is an extension of Range partitioning and it takes much of its syntax from
range partitioning.
From various sources on the net, I assume that interval partitioning creation query do have mandatory following clause:
VALUES LESS THAN (XXX)
But when we go for interval partitioning, is there any simpler way where we do not provide any VALUE LESS THAN CLAUSE.
I was searching for something similar like EQUAL TO (012019) where 012019 corresponds to the January month Interval
of 2019 year.
I have gone through following links for the help/understanding but couldn't find useful for my concern.
http://www.dba-oracle.com/t_interval_partitioning.htm
https://docs.oracle.com/database/121/VLDBG/GUID-C121EA1B-2725-4464-B2C9-EEDE0C3C95AB.htm
The code used by me is like as follows:
create table
pos_data (
start_date DATE,
store_id NUMBER,
inventory_id NUMBER(6),
qty_sold NUMBER(3)
)
PARTITION BY RANGE (start_date)
INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
(
PARTITION pos_data_p2 VALUES LESS THAN (TO_DATE('1-7-2007', 'DD-MM-YYYY')),
PARTITION pos_data_p3 VALUES LESS THAN (TO_DATE('1-8-2007', 'DD-MM-YYYY'))
);
From my search It looks like there is no other way apart from the one VALUE LESS THAN.
Please share if anyone have some understanding about someother approach for creating interval based partitioning.
Remainder: my concern is in BOLD above
I think what you are looking for is the partition extended name
PARTITION FOR(DATE'2019-01-01')
Actually the LESS THAN definition plays in interval partitioning close to zero role.
You use it only once while creating the table to define some lower bound of the data.
Here is an example to define a table containing data starting from the year 2019
create table pos_data (
start_date DATE,
store_id NUMBER
)
SEGMENT CREATION DEFERRED
PARTITION BY RANGE (start_date)
INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
(
PARTITION pos_data_init VALUES LESS THAN (TO_DATE('1-1-2019', 'DD-MM-YYYY'))
);
Note that the first partition is not an interval partition (INTERVAL = NO) and doesn't physically exists due to SEGMENT CREATION DEFERRED. It will also never contain any data, as you start with 2019 content.
select PARTITION_POSITION,PARTITION_NAME,INTERVAL,MIN_EXTENT, HIGH_VALUE
from user_tab_partitions where table_name = 'POS_DATA'
order by PARTITION_POSITION;
PARTITION_POSITION PARTITION_NAME INTERVAL MIN_EXTENT HIGH_VALUE
------------------ -------------- -------- ---------- -------------------------------
1 POS_DATA_INIT NO TO_DATE(' 2019-01-01 00:00:00',
New partitions are created on the fly e.g. while inserting new data, you don't need to specify LESS THAN
insert into pos_data(start_date,store_id) values(DATE'2019-01-01',1);
PARTITION_POSITION PARTITION_NAME INTERVAL MIN_EXTENT HIGH_VALUE
------------------ -------------- -------- ---------- -------------------------------
1 POS_DATA_INIT NO TO_DATE(' 2019-01-01 00:00:00',
2 SYS_P16713 YES 1 TO_DATE(' 2019-02-01 00:00:00',
While accessing the table you use the partition_extended_name, you may choose any date within the month to reference the partition.
select * from pos_data
partition for (date'2019-01-15');
Same syntax may be used for partition maintainance
alter table pos_data move partition for (date'2019-01-30') compress;

Change the range of existing partition

I have a table with two partitions:
create table MY
(
id NUMBER not null,
dat DATE
)
partition by range (dat)
(
partition PART_ARCHIVE values less than (TO_DATE(' 2015-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
tablespace ARCHIVE,
partition PART_ACTUAL values less than (MAXVALUE) tablespace ACTUAL
);
Can I change the PART_ARCHIVE partition date interval without recreating table?
I need to set that:
partition PART_ARCHIVE values less than (TO_DATE(' 2017-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
I don't know whether you can do it in a single command but this one should work:
ALTER TABLE MY SPLIT PARTITION PART_ACTUAL INTO
(PARTITION PART_2017 VALUES LESS THAN (DATE '2017-01-01'),
PARTITION PART_ACTUAL);
ALTER TABLE MY MERGE PARTITIONS PART_2017, PART_ARCHIVE INTO PART_ARCHIVE;

Oracle interval partitions are not created automatically with alter sub-partition template

I am using oracle 12c Interval partitioning. I have created the range partition with 1 month interval and list sub-partition using a unique identifier (lets say LOGIN_INTFID).
In table DDL I have added the list of sub-partitions that were known to me at the time of table creation. Here is extract of table DDL:
CREATE TABLE TEST
(
UNIQUE_ID NUMBER(9) NOT NULL,
LOGIN_INTFID VARCHAR2(20) NOT NULL,
LOGIN_SEQNO NUMBER(15) NOT NULL,
LOGIN_DATE DATE DEFAULT SYSDATE NOT NULL
)
PARTITION BY RANGE (LOGIN_DATE)
INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
SUBPARTITION BY LIST (LOGIN_INTFID) SUBPARTITION TEMPLATE (
SUBPARTITION SP1 VALUES ('ABC'),
SUBPARTITION SP2 VALUES ('DEF'),
)
(PARTITION TEST_Y2018M7D1 VALUES LESS
THAN (TO_DATE('2018-07-01 23:59:59', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')))
;
With this, new partition and sub partitions are created successfully. Later on, I had added one more sub-partition using the following alter command:
ALTER TABLE TEST modify partition SYS_P7068 add subpartition SP3 values ('XYZ');
I have also altered table TEST with the intention that next time when a new partition gets created, this new sub-partition is included in the table automatically:
ALTER TABLE TEST SET SUBPARTITION TEMPLATE (SUBPARTITION SP3 VALUES('XYZ'));
However, this last part is not working as expected. New partitions are not getting created when I am trying to insert data containing XYZ sub partition value. New partitions are getting created only when sub-partition values ABC/DEF are inserted.
What am I doing wrong?
You can't add a new subpartition to a template.
As the documetation states:
You can modify a subpartition template of a composite partitioned table by replacing it with a new subpartition template.
You have to define a new template consisting of the old and new subpartitions.
This will be valid for the partitions not yet created, for existing partition you have to add the subpartitions manually.
Example - after creation of your table you get one partition with two subpartitions
select PARTITION_NAME, SUBPARTITION_NAME,HIGH_VALUE
from user_tab_subpartitions where table_name = 'TEST';
PARTITION_NAME SUBPARTITION_NAME HIGH_VALUE
-------------- ----------------- ----------
TEST_Y2018 TEST_Y2018M7D1_ 'ABC'
TEST_Y2018 TEST_Y2018M7D1_ 'DEF'
Inserting a row adds an other partition with the same two subpartitions:
insert into test (UNIQUE_ID,LOGIN_INTFID,LOGIN_SEQNO,LOGIN_DATE)
values(1,'ABC',1,DATE'2018-08-02');
PARTITION_NAME SUBPARTITION_NAME HIGH_VALUE
-------------- -------------------- ----------
TEST_Y2018 TEST_Y2018M7D1_SP1 'ABC'
TEST_Y2018 TEST_Y2018M7D1_SP2 'DEF'
SYS_P14654 SYS_SUBP14652 'ABC'
SYS_P14654 SYS_SUBP14653 'DEF'
Now you change the subpartition template - by defining all the new subspartitions
ALTER TABLE TEST SET SUBPARTITION TEMPLATE (
SUBPARTITION SP1 VALUES ('ABC'),
SUBPARTITION SP2 VALUES ('DEF'),
SUBPARTITION SP3 VALUES('XYZ'));
and adds an other row
insert into test (UNIQUE_ID,LOGIN_INTFID,LOGIN_SEQNO,LOGIN_DATE)
values(1,'ABC',1,DATE'2018-09-02');
The new partition has now as expected three subpartitions
PARTITION_NAME SUBPARTITION_NAME HIGH_VALUE
-------------- -------------------- ----------
TEST_Y2018 TEST_Y2018M7D1_SP1 'ABC'
TEST_Y2018 TEST_Y2018M7D1_SP2 'DEF'
SYS_P14654 SYS_SUBP14652 'ABC'
SYS_P14654 SYS_SUBP14653 'DEF'
SYS_P14658 SYS_SUBP14655 'ABC'
SYS_P14658 SYS_SUBP14656 'DEF'
SYS_P14658 SYS_SUBP14657 'XYZ'

Oracle - Error on EXCHANGE PARTITION with List-Range partitioning

I'm trying to use EXCHANGE PARTITION on following example schema:
CREATE TABLE TEMP_TABLE_00(
CONTACT_ID NUMBER,
SECONDARY_CONTACT_FLAG NUMBER,
SOURCE_SYSTEM VARCHAR2(10 CHAR),
START_DATE DATE,
ACTIVE NUMBER,
SECONDARY_CONTACT_FLAGS NUMBER GENERATED ALWAYS AS (ACTIVE || SECONDARY_CONTACT_FLAG) VIRTUAL,
CONSTRAINT pk_temp_table_00 PRIMARY KEY (CONTACT_ID))
PARTITION BY LIST (SECONDARY_CONTACT_FLAGS)
SUBPARTITION BY RANGE (START_DATE)
( PARTITION p_ac_00 VALUES ('00')
( SUBPARTITION sp_ac_00_before_2014 VALUES LESS THAN (TO_DATE ('01.01.2014', 'DD.MM.YYYY')),
SUBPARTITION sp_ac_00_201401 VALUES LESS THAN (TO_DATE ('01.02.2014', 'DD.MM.YYYY'))
)
)
ENABLE ROW MOVEMENT;
create table TARGET_TABLE(
CONTACT_ID NUMBER,
SECONDARY_CONTACT_FLAG NUMBER,
SOURCE_SYSTEM VARCHAR2(10 CHAR),
START_DATE DATE,
ACTIVE NUMBER,
SECONDARY_CONTACT_FLAGS NUMBER GENERATED ALWAYS AS (ACTIVE || SECONDARY_CONTACT_FLAG) VIRTUAL,
CONSTRAINT pk_target_table PRIMARY KEY (CONTACT_ID))
PARTITION BY LIST (secondary_contact_flags)
SUBPARTITION BY RANGE (START_DATE)
( PARTITION p_ac_00 VALUES ('00')
( SUBPARTITION sp_ac_00_before_2014 VALUES LESS THAN (TO_DATE ('01.01.2014', 'DD.MM.YYYY')),
SUBPARTITION sp_ac_00_201401 VALUES LESS THAN (TO_DATE ('01.02.2014', 'DD.MM.YYYY'))
),
PARTITION p_ac_10 VALUES ('10')
( SUBPARTITION sp_ac_10_before_2014 VALUES LESS THAN (TO_DATE ('01.01.2014', 'DD.MM.YYYY')),
SUBPARTITION sp_ac_10_201401 VALUES LESS THAN (TO_DATE ('01.02.2014', 'DD.MM.YYYY'))
),
PARTITION p_ac_01 VALUES ('01')
( SUBPARTITION sp_ac_01_before_2014 VALUES LESS THAN (TO_DATE ('01.01.2014', 'DD.MM.YYYY')),
SUBPARTITION sp_ac_01_201401 VALUES LESS THAN (TO_DATE ('01.02.2014', 'DD.MM.YYYY'))
),
PARTITION p_ac_11 VALUES ('11')
( SUBPARTITION sp_ac_11_before_2014 VALUES LESS THAN (TO_DATE ('01.01.2014', 'DD.MM.YYYY')),
SUBPARTITION sp_ac_11_201401 VALUES LESS THAN (TO_DATE ('01.02.2014', 'DD.MM.YYYY'))
)
)
ENABLE ROW MOVEMENT;
INSERT INTO DM_KSCTSC.TEMP_TABLE_00 (CONTACT_ID, SECONDARY_CONTACT_FLAG, SOURCE_SYSTEM, START_DATE, ACTIVE) VALUES (1, 0, 'ABC', TO_DATE('20140101', 'YYYYMMDD'), 0);
commit;
When trying to exchange partitions:
alter table target_table exchange partition p_ac_00 with table TEMP_TABLE_00 without validation;
even though the structure of the partitions are identical, Oracle returns an
ORA-14292: Partitioning type of table must match subpartitioning type
of composite partition
Is there another solution than exchanging every subpartition seperately?
To be able to exchange partition between a partition table (PT) and a non-partitioned table (TMP) the TMP table must have the same structure as the partition of PT.
I.e. if the PT is partitioned, the TMP is non-partitioned.
If the PT is composit partitioned, the TMP is partitioned in the same way as the subpartition of PT.
In your case is the problem in the TMP table (TEMP_TABLE_00), it must be partitioned by RANGE (same as the subpartition of TARGET_TABLE)
CREATE TABLE TEMP_TABLE_00(
CONTACT_ID NUMBER,
SECONDARY_CONTACT_FLAG NUMBER,
SOURCE_SYSTEM VARCHAR2(10 CHAR),
START_DATE DATE,
ACTIVE NUMBER,
SECONDARY_CONTACT_FLAGS NUMBER GENERATED ALWAYS AS (ACTIVE || SECONDARY_CONTACT_FLAG) VIRTUAL,
CONSTRAINT pk_temp_table_00 PRIMARY KEY (CONTACT_ID))
PARTITION BY RANGE (START_DATE)
( PARTITION sp_ac_00_before_2014 VALUES LESS THAN (TO_DATE ('01.01.2014', 'DD.MM.YYYY')),
PARTITION sp_ac_00_201401 VALUES LESS THAN (TO_DATE ('01.02.2014', 'DD.MM.YYYY'))
)
ENABLE ROW MOVEMENT;
In this setup the exchange partition works.

Tablespaces with interval partitioning

Is there any way to specify different tablespaces for each partition if I use interval partitioning?
My table is (it is just example, I have more columns in the table):
create table MY_TABLE
(
id NUMBER(20) not null,
type VARCHAR2(1 char) not null,
session_id NUMBER(12) not null,
date_of_beginning DATE not null,
account_number NUMBER not null
)
PCTFREE 1
PARTITION BY RANGE (date_of_beginning)
INTERVAL(NUMTOYMINTERVAL(1, ''MONTH''))
SUBPARTITION BY HASH(account_number) subpartitions 50
(
PARTITION p_1 VALUES LESS THAN (TO_DATE(''01.06.2015'', ''dd.mm.yyyy''))
)';
I want each partition to be stored in separate tablespase. Any ideas how can I achieve it? Maybe some trigger?
For other tables like this one, we have a job, which creates tablespace and partition in the beginning of the month. But this one creates partitions automatically because of intervals.

Resources