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;
Related
I have a table which is partitioned as below and has millions of rows of data. Table size is 120 GB.
PARTITION BY RANGE (Read_time) INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
Now I want to change to this partitioning strategy with existing data and future data. Table is inserted daily by job.
PARTITION BY RANGE (Read_time) INTERVAL(NUMTODSINTERVAL(1, 'DAY'))
I have 12 month partition (Oct'18 to Nov'19). I want partition to be converted to daywise.
For example: For Jul'19 partition, it should to be splitted to
01 Jul'19,
02 Jul'19
.......
31 Jul'19.
Data should also be moved to new partition
I tried split partition. New partition got created day wise , but rows didn't move to new partition.
To change for monthly interval to daily is a simple as
ALTER TABLE test SET INTERVAL (NUMTODSINTERVAL(1,'DAY'));
see the documentation for further details
Lets illustrate in on a small example
create table test
(dt date)
PARTITION BY RANGE (dt)
INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
(
PARTITION part_01 values LESS THAN (TO_DATE('01-01-2019','DD-MM-YYYY'))
);
insert into test (dt)
select date'2019-01-01' + rownum dt from dual
connect by level <= 100;
The table in montly intrval partitioned and contains 100 days of data - yielding in one initial partition and 4 new montly partition.
PARTITION_NAME HIGH_VALUE
------------------------------ --------------------------------------------------------------------------------
PART_01 TO_DATE(' 2019-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93334 TO_DATE(' 2019-02-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93335 TO_DATE(' 2019-03-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93336 TO_DATE(' 2019-04-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93337 TO_DATE(' 2019-05-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
Now we switch to daily partitioning
ALTER TABLE test SET INTERVAL (NUMTODSINTERVAL(1,'DAY'));
This makes nothing with existing data (so it is instant operation), also the new data for the current month will go in the current (month) partition.
The data loaded for the new month will be partitioned on daily basis.
Lets insert few new days
insert into test (dt)
select date'2019-01-01' + 100 +rownum dt from dual
connect by level <= 22;
PARTITION_NAME HIGH_VALUE
------------------------------ --------------------------------------------------------------------------------
PART_01 TO_DATE(' 2019-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93334 TO_DATE(' 2019-02-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93335 TO_DATE(' 2019-03-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93336 TO_DATE(' 2019-04-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93337 TO_DATE(' 2019-05-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93338 TO_DATE(' 2019-05-02 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93339 TO_DATE(' 2019-05-03 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93340 TO_DATE(' 2019-05-04 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
As expected starting with May the data are daily partitioned.
If you need also to re-partitioned your historical data, this will require reorganisation (data movement - will take some time for 120GB) using split partition.
alter table test
SPLIT PARTITION FOR(TO_DATE('2019-02-01','yyyy-mm-dd'))
AT (TO_DATE('2019-02-27','yyyy-mm-dd'));
alter table test
SPLIT PARTITION FOR(TO_DATE('2019-02-01','yyyy-mm-dd'))
AT (TO_DATE('2019-02-26','yyyy-mm-dd'));
This splits the last day in a new partition, you'll have to do it for each day in each monthly partition.
After this step also the history data is partitioned per day:
select * from test partition for ( DATE'2019-02-26');
DT
-------------------
26.02.2019 00:00:00
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;
I have a table which is partitioned as below and has millions of rows of data. Table size is 120 GB.
PARTITION BY RANGE (Read_time) INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
Now I want to change to this partitioning strategy with existing data and future data. Table is inserted daily by job.
PARTITION BY RANGE (Read_time) INTERVAL(NUMTODSINTERVAL(1, 'DAY'))
I have 12 month partition (Oct'18 to Nov'19). I want partition to be converted to daywise.
For example: For Jul'19 partition, it should to be splitted to
01 Jul'19,
02 Jul'19
.......
31 Jul'19.
Data should also be moved to new partition
I tried split partition. New partition got created day wise , but rows didn't move to new partition.
To change for monthly interval to daily is a simple as
ALTER TABLE test SET INTERVAL (NUMTODSINTERVAL(1,'DAY'));
see the documentation for further details
Lets illustrate in on a small example
create table test
(dt date)
PARTITION BY RANGE (dt)
INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
(
PARTITION part_01 values LESS THAN (TO_DATE('01-01-2019','DD-MM-YYYY'))
);
insert into test (dt)
select date'2019-01-01' + rownum dt from dual
connect by level <= 100;
The table in montly intrval partitioned and contains 100 days of data - yielding in one initial partition and 4 new montly partition.
PARTITION_NAME HIGH_VALUE
------------------------------ --------------------------------------------------------------------------------
PART_01 TO_DATE(' 2019-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93334 TO_DATE(' 2019-02-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93335 TO_DATE(' 2019-03-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93336 TO_DATE(' 2019-04-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93337 TO_DATE(' 2019-05-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
Now we switch to daily partitioning
ALTER TABLE test SET INTERVAL (NUMTODSINTERVAL(1,'DAY'));
This makes nothing with existing data (so it is instant operation), also the new data for the current month will go in the current (month) partition.
The data loaded for the new month will be partitioned on daily basis.
Lets insert few new days
insert into test (dt)
select date'2019-01-01' + 100 +rownum dt from dual
connect by level <= 22;
PARTITION_NAME HIGH_VALUE
------------------------------ --------------------------------------------------------------------------------
PART_01 TO_DATE(' 2019-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93334 TO_DATE(' 2019-02-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93335 TO_DATE(' 2019-03-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93336 TO_DATE(' 2019-04-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93337 TO_DATE(' 2019-05-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93338 TO_DATE(' 2019-05-02 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93339 TO_DATE(' 2019-05-03 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SYS_P93340 TO_DATE(' 2019-05-04 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
As expected starting with May the data are daily partitioned.
If you need also to re-partitioned your historical data, this will require reorganisation (data movement - will take some time for 120GB) using split partition.
alter table test
SPLIT PARTITION FOR(TO_DATE('2019-02-01','yyyy-mm-dd'))
AT (TO_DATE('2019-02-27','yyyy-mm-dd'));
alter table test
SPLIT PARTITION FOR(TO_DATE('2019-02-01','yyyy-mm-dd'))
AT (TO_DATE('2019-02-26','yyyy-mm-dd'));
This splits the last day in a new partition, you'll have to do it for each day in each monthly partition.
After this step also the history data is partitioned per day:
select * from test partition for ( DATE'2019-02-26');
DT
-------------------
26.02.2019 00:00:00
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;
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.