Table partition on non date column - oracle

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.

Related

partition in oracle

CREATE TABLE temp_stud as select * from STUD_MAST
PARTITION BY RANGE(ADM_DT)
(
PARTITION temp_stud1 VALUES LESS THAN(TO_DATE('02/01/2000','MM/DD/YYYY')),
PARTITION temp_stud2 VALUES LESS THAN(TO_DATE('03/01/2000','MM/DD/YYYY')),
PARTITION temp_stud3 VALUES LESS THAN(TO_DATE('04/01/2000','MM/DD/YYYY')),
PARTITION temp_stud4 VALUES LESS THAN(TO_DATE('05/01/2000','MM/DD/YYYY'))
);
I am getting a missing left parenthesis error for above table creation can anyone tell me what is the issue in above creation
Note: ADM_DT is a date column with data type char(8) and storing format YYMMDD
Please use below SQL. The Creation of Partition has be part of Create table.
CREATE TABLE temp_stud
PARTITION BY RANGE(ADM_DT)
(
PARTITION temp_stud1 VALUES LESS THAN(TO_DATE('02/01/2000','MM/DD/YYYY')),
PARTITION temp_stud2 VALUES LESS THAN(TO_DATE('03/01/2000','MM/DD/YYYY')),
PARTITION temp_stud3 VALUES LESS THAN(TO_DATE('04/01/2000','MM/DD/YYYY')),
PARTITION temp_stud4 VALUES LESS THAN(TO_DATE('05/01/2000','MM/DD/YYYY'))
)
as select * from STUD_MAST;

Automatic Oracle partitioning by month in the tablespace corresponding to the month

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.

Can I create a growing Interval partitioned table with a default/maxvalue partition?

Summary of the question: To Create table with partitions which are range partitioned. However records which do not know the range value should reside in a different (default) partition and be moved to the correct partition when the value is filled. The default partition would never be dropped while the other partitions would be dropped after a defined retention period via an script.
The whole story:
I have a table where the records have to be placed in a partition based on a date field. This is a growing table and after some time the data from these partitions can be purged. I used to create table with something like the snippet below.
This works fine because we knew the value of the date column based on which we partition (RDATE). However in our new project we do not know this when a record is inserted. The value would eventually be filled in during the course of the application processing.
My initial thought was to create MAXPARTITION (MAXVALUE) which would be a catch-all partition for records which do not have the date filled and enable ROW MOVEMENTS so that when the date is filled it moves into an appropriate partition. However I think it is not possible to have both MAXVALUE partition and interval partitioning together. Is that right?
Also Is there a better way to do this?
PARTITION BY RANGE ("RDATE") INTERVAL (NUMTODSINTERVAL (1,'DAY'))
SUBPARTITION BY HASH ("RKEY")
SUBPARTITION TEMPLATE (
SUBPARTITION "SP01",
SUBPARTITION "SP02",
SUBPARTITION "SP03",
SUBPARTITION "SP04",
SUBPARTITION "SP05",
SUBPARTITION "SP06",
SUBPARTITION "SP07",
SUBPARTITION "SP08",
SUBPARTITION "SP09",
SUBPARTITION "SP10",
SUBPARTITION "SP11",
SUBPARTITION "SP12",
SUBPARTITION "SP13",
SUBPARTITION "SP14",
SUBPARTITION "SP15",
SUBPARTITION "SP16" )
(PARTITION "INITIALPARTITION" VALUES LESS THAN (TO_DATE(' 2016-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
I expect a table with default and range partitions and records to move to the range partitions from the default when a column is filled.
The column you use as partition key cannot be NULL but you can use a workaround like this:
CREATE TABLE ... (
...
RDATE DATE,
PARTITION_KEY DATE GENERATED ALWAYS AS (COALESCE(RDATE, DATE '1969-12-31'))
)
PARTITION BY RANGE (PARTITION_KEY) INTERVAL (NUMTODSINTERVAL (1,'DAY'))
...
(PARTITION INITIAL_PARTITION VALUES LESS THAN (DATE '1970-01-01'))
ENABLE ROW MOVEMENT;
If you insert a record with RDATE = NULL then it will be inserted into partition INITIAL_PARTITION. For the initial data (e.g. 1970-01-01) you must select a values whicc will never fall into the "real" date values. You could also use a date in far future, e.g.
CREATE TABLE ... (
...
RDATE DATE,
PARTITION_KEY DATE GENERATED ALWAYS AS (COALESCE(RDATE, DATE '2999-12-31'))
)
PARTITION BY RANGE (PARTITION_KEY) INTERVAL (NUMTODSINTERVAL (1,'DAY'))
...
(PARTITION INITIAL_PARTITION VALUES LESS THAN (DATE '2019-04-01'))
ENABLE ROW MOVEMENT;
-- Create DEFAULT_PARTITION
INSERT INTO ... (RDATE) VALUES (NULL);
ROLLBACK;
ALTER TABLE ... RENAME PARTITION FOR (TIMESTAMP '2999-12-31 00:00:00') TO DEFAULT_PARTITION;

How to create monthly partition in oracle?

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 insert data to a interval partitioned table why the partition can't created

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.

Resources