I've asked a similar question before but couldn't figure it out(Divide into hourly partitions and inset data by partitions).
I created a table with hourly partitions, and when inserting data, it correctly divides by hourly partitions:
create table SOFT_CALLS(
callid VARCHAR2(90),
start_time date not null,
start_time_h as (to_char(start_time, 'HH24')),
duration NUMBER,
first_question VARCHAR2(4000),
second_question VARCHAR2(4000),
client_id VARCHAR2(20),
contract_id VARCHAR2(20),
client_dwh_id VARCHAR2(20)
)
partition by list (start_time_h)
(
partition p_08 values ('08'),
partition p_09 values ('09'),
partition p_10 values ('10'),
partition p_11 values ('11'),
partition p_12 values ('12'),
partition p_13 values ('13'),
partition p_14 values ('14'),
partition p_15 values ('15'),
partition p_16 values ('16'),
partition p_17 values ('17'),
partition p_18 values ('18'),
partition p_19 values ('19'),
partition p_20 values ('20'),
partition p_21 values ('21'),
partition p_22 values ('22'),
partition p_23 values ('23')
);
The logic of the procedure should be as follows: so that it inserts data into the table for trunc(sysdate - 1/24, 'hh') and trunc(sysdate + 1/24, 'hh') and then transfers the same data to SAS and at the end simply drop these partitions so that the procedure does not do this for the entire trunc (sysdate) every five minutes, so resource consumption will decrease.
It is necessary that the table stores data in hourly partitions, that is, it will not truncate all the data each time and refill for the whole day, but only drop partitions for the last hour and also insert data without losing data for the hours that have already passed.
But the problem is that list partitions cannot be dropped during this period trunc(sysdate - 1/24, 'hh') and trunc(sysdate + 1/24, 'hh').
What other examples are there for dividing a table into hourly partitions and so that in the end there would be no problems dropping them over the period that I indicated? I've looked all over the internet, but I haven't been able to find any specific information.
Related
I need to partition my table by month automatically and that each partition is in the tablespace corresponding to the month. I don't need the round robin way. I want each partition to be in its tablespace. Thanks
As I already stated, you have to use round robin, because the tablespaces have to exist at desing time. Otherwise Oracle cannot create partitions automatically. Would be this:
CREATE TABLE MY_TABLE
(
START_TIME TIMESTAMP(0) NOT NULL,
more columns
)
PARTITION BY RANGE (START_TIME) INTERVAL (INTERVAL '1' MONTH)
STORE IN (
TS_JAN, TS_FEB, TS_MAR,
TS_APR, TS_MAY, TS_JUN,
TS_JUL, TS_AUG, TS_SEP,
TS_OKT, TS_NOV, TS_DEC
)
(
PARTITION P_INITIAL VALUES LESS THAN (TIMESTAMP '2021-01-01 00:00:00') TABLESPACE TS_JAN
);
Just ensure timestamp of the inital partition (e.g. 1st of January) matches the correct tablespace.
Otherwise you have to create all partitions and tablespaces manually in advance.
How can I partition a table in oracle on non-date column (Say partition on Username)?
I have table partitioning on only date columns.Say:
CREATE TABLE X
(
Username Varchar2(10 Char),
Import_date Date
)
PARTITION BY RANGE ("IMPORT_DATE") INTERVAL (NUMTODSINTERVAL(1,'DAY'))
(PARTITION "CL_REP_DEF" VALUES LESS THAN
(TO_DATE(' 2018-06-29 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
)
Though I am not sure how to partition with username here.
Oracle offers three types of partitions:
Range
Hash
List
You can use any of them.
Selection of partitioning type depends on the data stored in a table and values of partitioned column (columns). If the number of distinct values in a column (columns) is limited and known, then LIST type would be a better choice.
As to your case, I think HASH partition fits the most.
Here's an example of how you can partition your X table:
CREATE TABLE X
(
Username Varchar2(10 Char),
Import_date Date
) PARTITION BY HASH(Username) PARTITIONS 16; -- 16 is the number of partitions.
You can find more about partitioning in official Oracle documentation.
I have a table with 2017 and 2018 year data. Need to create monthly partition on that table.
So I created one non partitioned table and loaded all the data from original table. now I am converting the new table to a monthly partitioned table.
When I am altering getting error as
ORA-14300: partitioning key maps to a partition outside maximum
permitted number of partitions
My Script is
ALTER TABLE ORDERHDR_PART MODIFY
PARTITION BY RANGE (LASTUPDATE) INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
(
PARTITION ORDERHDR_PART_JAN VALUES less than (TO_DATE('01-02-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_FEB VALUES less than (TO_DATE('01-03-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_MAR VALUES less than (TO_DATE('01-04-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_APR VALUES less than (TO_DATE('01-05-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_MAY VALUES less than (TO_DATE('01-06-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_JUN VALUES less than (TO_DATE('01-07-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_JUL VALUES less than (TO_DATE('01-08-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_AUG VALUES less than (TO_DATE('01-09-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_SEP VALUES less than (TO_DATE('01-10-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_OCT VALUES less than (TO_DATE('01-11-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_NOV VALUES less than (TO_DATE('01-12-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_DEC VALUES less than (TO_DATE('01-01-2019','DD-MM-YYYY'))
)ONLINE;
I think your approach is wrong.
First create a partitioned table, e.g.
CREATE TABLE ORDERHDR_PART (....)
PARTITION BY RANGE (LASTUPDATE) INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'))
(
PARTITION ORDERHDR_INITIAL VALUES less than (DATE '2000-01-01')
);
Then transfer existing data to the new table.
Either you use a simple INSERT INTO ORDERHDR_PART SELECT * FROM ORDERHDR_2017;
Oracle will create monthly partitions automatically based on LASTUPDATE value.
With this methods you would duplicate (temporary) your data and/or you may face a performance issue.
The other method is to use Exchanging Partitions, should be like this
ALTER TABLE ORDERHDR_PART
EXCHANGE PARTITION FOR (DATE '2017-01-01')
WITH TABLE ORDERHDR_2017
INCLUDING INDEXES;
I don't know whether "PARTITION FOR (DATE '2017-01-01')" is created automatically, perhaps you have to run INSERT INTO ORDERHDR_PART (LASTUPDATE) VALUES (DATE '2017-01-01'); ROLLBACK; in order to create it first.
You will get one partition for all months, afterwards you can split the partition with Splitting into Multiple Partitions. Should be like this:
ALTER TABLE ORDERHDR_PART SPLIT PARTITION FOR (DATE '2017-01-01') INTO (
PARTITION ORDERHDR_PART_JAN VALUES less than (TO_DATE('01-02-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_FEB VALUES less than (TO_DATE('01-03-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_MAR VALUES less than (TO_DATE('01-04-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_APR VALUES less than (TO_DATE('01-05-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_MAY VALUES less than (TO_DATE('01-06-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_JUN VALUES less than (TO_DATE('01-07-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_JUL VALUES less than (TO_DATE('01-08-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_AUG VALUES less than (TO_DATE('01-09-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_SEP VALUES less than (TO_DATE('01-10-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_OCT VALUES less than (TO_DATE('01-11-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_NOV VALUES less than (TO_DATE('01-12-2018','DD-MM-YYYY')),
PARTITION ORDERHDR_PART_DEC VALUES less than (TO_DATE('01-01-2019','DD-MM-YYYY'))
);
Note, by default you cannot drop the inital partition of a RANGE partitioned table. If you face this problem execute:
ALTER TABLE ORDERHDR_PART SET INTERVAL ();
ALTER TABLE ORDERHDR_PART DROP PARTITION ORDERHDR_INITIAL;
ALTER TABLE ORDERHDR_PART SET INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'));
When I create a partitioned table by range interval and create the first partition manually as the SQL shows.
CREATE TABLE "HDEVAMP"."POS_DATA"
( "START_DATE" DATE,
"STORE_ID" NUMBER,
"INVENTORY_ID" NUMBER(6,0),
"QTY_SOLD" NUMBER(3,0)
)
PARTITION BY RANGE ("START_DATE") INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'))
(PARTITION "POS_DATA_P27" VALUES LESS THAN (TO_DATE('2018-02-01','yyyy-mm-dd')));
why the partitioned was not create automatically when I insert the data whose partition key is 20171231.
insert into pos_data values (TO_DATE('2017-12-31','YYYY-MM-DD'),1,110,12);
insert into pos_data values (TO_DATE('2018-01-31','YYYY-MM-DD'),1,110,12);
commit;
it just create one partition POS_DATA_P27 to store all above two data,not create a partition to store the data for "2017-12-31"
"TABLE_NAME","COMPOSITE","PARTITION_NAME","SUBPARTITION_COUNT","HIGH_VALUE","HIGH_VALUE_LENGTH","PARTITION_POSITION","TABLESPACE_NAME","PCT_FREE","PCT_USED","INI_TRANS","MAX_TRANS","INITIAL_EXTENT","NEXT_EXTENT","MIN_EXTENT","MAX_EXTENT","MAX_SIZE","PCT_INCREASE","FREELISTS","FREELIST_GROUPS","LOGGING","COMPRESSION","COMPRESS_FOR","NUM_ROWS","BLOCKS","EMPTY_BLOCKS","AVG_SPACE","CHAIN_CNT","AVG_ROW_LEN","SAMPLE_SIZE","LAST_ANALYZED","BUFFER_POOL","FLASH_CACHE","CELL_FLASH_CACHE","GLOBAL_STATS","USER_STATS","IS_NESTED","PARENT_TABLE_PARTITION","INTERVAL","SEGMENT_CREATED","INDEXING","INMEMORY","INMEMORY_PRIORITY","INMEMORY_DISTRIBUTE","INMEMORY_COMPRESSION","INMEMORY_DUPLICATE"
"POS_DATA","NO","POS_DATA_P27",0,"TO_DATE(' 2018-02-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')",83,1,"SYSTEM",10,40,1,255,65536,1048576,1,2147483645,2147483645,,1,1,"YES","DISABLED","",,,,,,,,,"DEFAULT","DEFAULT","DEFAULT","NO","NO","NO","","NO","YES","ON","DISABLED","","","",""
You created a partition LESS THAN 2018-02-01 00:00:00 which means: everything earlier than 2018-02-01 goes into that partition.
20171231, i.e. 2017-12-31 is obviously earlier than 2018-02-01, so what do you expect?
Oracle will create new partition for values after 2018-02-01.
I would like to run a procedure that merges table partitions that match a certain criteria.
As example - table1 is range partitions by date and has 5 partitions.
Partitions = empire1, empire2, rebels1, rebels2, yoda1.
Table DESC:
INVOICE_NO NOT NULL NUMBER
INVOICE_DATE NOT NULL DATE
COMMENTS VARCHAR2(500)
it is partitioned by INVOICE_DATE as follows
PARTITION REBELS1 VALUES LESS THAN (TO_DATE('01-JAN-2014','DD-MON-YYYY')),
PARTITION REBELS2 VALUES LESS THAN (TO_DATE('01-JAN-2015','DD-MON-YYYY')),
PARTITION EMPIRE1 VALUES LESS THAN (TO_DATE('01-JAN-2016','DD-MON-YYYY')),
PARTITION EMPIRE2 VALUES LESS THAN (TO_DATE('01-JAN-2017','DD-MON-YYYY')),
PARTITION YODA VALUES LESS THAN (TO_DATE('01-JAN-2018','DD-MON-YYYY')),
I need to grab all partitions named rebel% and yoda% and merge them into one new partition called 'jawa'.
In the end only 3 partitions would exist, empire1, empire2 and jawa.