I am using Oracle-11G database.
I am trying to create day wise partition and again sub-partition on hourly level.
Below is the script I am using
CREATE TABLE test_shipments
( order_date DATE NOT NULL
, delivery_date DATE NOT NULL
)
PARTITION BY RANGE (order_date)
INTERVAL (NUMTODSINTERVAL(1, 'day'))
SUBPARTITION BY RANGE (order_date)
( PARTITION p_2006_jul VALUES LESS THAN (TO_DATE('2006-08-01','YYYY-MM-DD'))
( SUBPARTITION p06_jul_e1 VALUES LESS THAN (TO_DATE('2006-08-01 12:00:00','YYYY-MM-DD hh24:mi:ss'))
,SUBPARTITION p06_jul_e2 VALUES LESS THAN (TO_DATE('2006-08-01 13:00:00','YYYY-MM-DD hh24:mi:ss'))
,SUBPARTITION p06_jul_e3 VALUES LESS THAN (TO_DATE('2006-08-01 14:00:00','YYYY-MM-DD hh24:mi:ss'))
)
);
I am expecting to have partition for every day and again sub-partition for every hour in that day. The above script creates partition per day only. Hourly sub-partition is not getting created. Can anyone please guide?
Why do you not create simple partition by Hourly range? Example: PARTITION BY RANGE (order_date) INTERVAL (INTERVAL '1' HOUR)
Anyway, this one works. However, you should use TIMESTAMP data type instead of DATE. For hour value you have to create a virtual column.
CREATE TABLE test_shipments (
order_date TIMESTAMP(0) NOT NULL,
order_date_hour NUMBER GENERATED ALWAYS AS (EXTRACT(HOUR FROM order_date)),
delivery_date DATE NOT NULL)
PARTITION BY RANGE (order_date)
INTERVAL (INTERVAL '1' DAY)
SUBPARTITION BY LIST (order_date_hour)
SUBPARTITION TEMPLATE
(SUBPARTITION HOUR00 VALUES (0),
SUBPARTITION HOUR01 VALUES (1),
SUBPARTITION HOUR02 VALUES (2),
SUBPARTITION HOUR03 VALUES (3),
...
SUBPARTITION HOUR22 VALUES (22),
SUBPARTITION HOUR23 VALUES (23)
)
(
PARTITION P_20150101 VALUES LESS THAN (TIMESTAMP'2015-01-01 00:00:00')
);
If you are enforced to use DATE data type you can do it like this:
CREATE TABLE test_shipments (
order_date DATE NOT NULL,
order_date_hour NUMBER GENERATED ALWAYS AS (TO_CHAR(order_date, 'HH24')),
delivery_date DATE NOT NULL)
PARTITION BY RANGE (order_date)
INTERVAL (INTERVAL '1' DAY)
SUBPARTITION BY LIST (order_date_hour)
SUBPARTITION TEMPLATE
(SUBPARTITION HOUR00 VALUES (0),
SUBPARTITION HOUR01 VALUES (1),
SUBPARTITION HOUR02 VALUES (2),
SUBPARTITION HOUR03 VALUES (3),
...
SUBPARTITION HOUR22 VALUES (22),
SUBPARTITION HOUR23 VALUES (23)
)
(
PARTITION P_20150101 VALUES LESS THAN (DATE '2015-01-01')
);
Maybe you want to group night time hours:
(
SUBPARTITION HOUR_NIGHT VALUES (0,1,2,3,4,5,6, 19,20,21,22,23),
SUBPARTITION HOUR07 VALUES (7),
SUBPARTITION HOUR08 VALUES (8),
SUBPARTITION HOUR11 VALUES (11),
...
SUBPARTITION HOUR17 VALUES (17),
SUBPARTITION HOUR18 VALUES (18)
)
Related
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 20 GB table which for some requirement, have to be range partitioned on DATE1 field and list sub-partitioned on DATE2 field.
Created a virtual column (VC) on that table to extract numeric month value from DATE2 field and use this VC as the sub-partition key.
Per requirement, we'll have 30 partitions on DATE1 and each of them will have 12 sub-partitions on VC.
The max size of any sub-partition can be up to 5 GB.
N.B. I could not implement Multi-column partitioning as our inbuilt partition manager does not support them.
Also, I could not implement a RANGE-RANGE partition-sub-partitioning as the two Date fields (DATE1 and DATE2) have no-sync in dates coming in them, causing INSERT operations to fail.
Next, I've a simple view created on top of this table. All Date fields including VC are exposed in this view. While querying SELECT * FROM vw; Plan shows PARTITION RANGE SINGLE as expected.
Now, I've a web front end through which I can click on the DATE2 to open some more details. It basically passed DATE2 as filter to query on another table and displays huge records (approx. 3 million).
The PROBLEM is, on clicking the DATE2 field, I'm not able to hit the sub-partition as its based on MONTH value (VC) and not the date.
Thus, I want a PARTITION LIST SINGLE instead of the current PARTITION LIST ALL in plan.
The QUESTION is, how to write a select query to select the SUB partition. I know I have to use the VC in the filter to achieve it, but, the irony is the web-application cannot pass VC in the backend especially when we display only DATE values (not VC).
Also, if we CANNOT hit the sub-partition, is there any way we can better the performance by using INDEXES or PARALLELISM?
Please help.
--***********************************************
--TABLE CREATION STATEMENT
--***********************************************
CREATE TABLE M_DTX
(
R_ID NUMBER(3),
R_AMT NUMBER(5),
DATE1 DATE,
DATE2 DATE,
VC NUMBER(2) GENERATE ALWAYS AS (EXTRACT(MONTH FROM DATE2))
)
PARTITION BY RANGE (DATE1)
SUBPARTITION BY LIST (VC)
SUBPARTITION TEMPLATE (
SUBPARTITION M1 VALUES (1),
SUBPARTITION M2 VALUES (2),
SUBPARTITION M3 VALUES (3),
SUBPARTITION M4 VALUES (4),
SUBPARTITION M5 VALUES (5),
SUBPARTITION M6 VALUES (6),
SUBPARTITION M7 VALUES (7),
SUBPARTITION M8 VALUES (8),
SUBPARTITION M9 VALUES (9),
SUBPARTITION M10 VALUES (10),
SUBPARTITION M11 VALUES (11),
SUBPARTITION M12 VALUES (12)
TABLESPACE M_DATA
)
(
PARTITION M_DTX_2015060100
VALUES LESS THAN (
TO_DATE(' 2015-06-01 00:00:01', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
) SEGMENT CREATION DEFERRED
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS NOLOGGING
STORAGE( INITIAL 1048576 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT
) TABLESPACE M_DATA);
--******************************************
--VIEW ON TOP OF M_DTX:
--******************************************
CREATE OR REPLACE VIEW v_dtx AS
SELECT r_id, TRUNC(date2) date2_dd, vc, SUM(r_amt) amt
FROM m_dtx WHERE date1 = TRUNC(sysdate)
GROUP BY r_id, TRUNC(date2), vc;
--******************************************
--QUERY FIRED FROM WEB-APPLICATION (AFTER CLICKING ON date2_DD):
--******************************************
SELECT * FROM m_dtx WHERE date1 = trunc(sysdate) AND date2 = ''date2_dd'';
--this is where its bypassing the sub-partition as I could not substitute month or VC ...
The only way I found to hit the subpartition is to write the query this way:
SELECT *
FROM m_dtx
WHERE date1 = trunc(sysdate)
AND date2 = ''date2_dd''
and vc = EXTRACT(MONTH FROM ''date2_dd'');
So, you don't need to get the vc from the previous screen, because you have the date2.
I've tested with:
SELECT *
FROM m_dtx
WHERE date1 = trunc(sysdate)
AND date2 = to_date('10-dec-2014','dd-mon-yyyy')
and vc = EXTRACT(MONTH FROM to_date('10-dec-2014','dd-mon-yyyy'));
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.
I want to create a table like this.
create table some_data (
id number(19,0),
group_id number(19,0),
value float,
timestamp timestamp
);
For this table i would like to have the data stored like
group_id=1
jan-2015
feb-2015
...
group_id=2
jan-2015
feb-2015
...
and so on. So I assume i have to create a partition by range for the group_id and then a subpartition also by range with the timestamp column, right?
So it should look like this:
create table some_data (
id number(19,0),
group_id number(19,0),
value float,
timestamp timestamp
)
PARTITION BY RANGE (group_id)
SUBPARTITION BY RANGE ("TIMESTAMP")
INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
(
PARTITION part_1 values LESS THAN (TO_DATE('01.02.2015','DD.MM.YYYY'))
);
Is this right? And also the question: With this partition, if a new group_id is added, will oracle create automatically a new partition for the new group_id and the new suppartitions for new data with new months?
Interval partitioning is not supported on subpartition level:
http://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_7002.htm#SQLRF54559
You can define it like this:
create table some_data (
id number(19,0),
group_id number(19,0),
value float,
timestamp timestamp -- not good naming
)
PARTITION BY RANGE ("TIMESTAMP")
INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
SUBPARTITION BY RANGE (group_id) -- it could be hash or list as well
subpartition template(
...
)
(
PARTITION part_1 values LESS THAN (TO_DATE('01.02.2015','DD.MM.YYYY'))
);
I created a table with the following partition interval:
create table
pos_data_two (
start_date TIMESTAMP,
store_id NUMBER,
inventory_id NUMBER(6),
qty_sold NUMBER(3)
)
PARTITION BY RANGE (start_date)
INTERVAL(NUMTODSINTERVAL (1, 'DAY'))
(
PARTITION pos_data_p2 VALUES LESS THAN (TO_DATE('30.10.2013', 'DD.MM.YYYY'))
);
When I insert a a row with the timestamp value
'31.10.2013 00:00:00'
The high value of the new created partition is:
TIMESTAMP' 2013-11-01 00:00:00'
Is that correct? Shouldn't it be 2013-10-31 00:00:00 ??
(Disclaimer: I'm just guessing here)
You're partitioning by days, so values for a given date fall into the same partition.
The row you're inserting has a start_date that's exactly at midnight, so Oracle has to decide whether to put it onto the previous day or onto the next day.
Apparently, Oracle is using the rule
lower_bound <= value < upper_bound
to decide which interval a value should go into, so your value
2013-10-31 00:00:00
goes into the interval
[2013-10-31 00:00:00; 2013-11-01 00:00:00 [