How to change RANGE value in PARTITIONS BY Range Oracle - oracle

I have an existing table within the next script:
create table sales6
(
sales_id number,
sales_dt date
)
partition by range (sales_dt)
(
partition p0701 values less than (to_date('2007-02-01','yyyy-mm-dd'))
);
What I need is to change the partition range to add an interval like this :
interval (numtoyminterval(1,'MONTH'))
I know that the right way to do it is when you create the table, but the table already exists and there are lot of records stored.
Is there any way to achieve this in Oracle 11g? I tried to ALTER the table but is not working due to 00940. 00000 - "invalid ALTER command"
Hope you can help me.
PS: I've been reading the whole documentation of Oracle in this two links without luck:
https://docs.oracle.com/cd/E17952_01/refman-5.5-en/alter-table-partition-operations.html
https://docs.oracle.com/cd/E17952_01/refman-5.1-en/partitioning-management-range-list.html

You can change a range partitioned table to a interval partitioned table with this command :
ALTER TABLE X SET INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'));
You can change back to range partitioned table with this command :
ALTER TABLE X SET INTERVAL();
Interval partitioning is always a more preferable option to range partitioning if your partitions are always evenly created (in identical periods).
The commands are not resource intensive because you don't manipulate segments and data, you just tell Oracle to begin or stop creating new partitions if new data that is inserted in the table doesn't fit by partition key in any existing partition.

Related

Partition by range in oracle using sysdate

I want to create partitions dynamicaly that depends on sysdate, like:
create table partition_interval_demo
( id number(6)
, val varchar2(50)
, date_create date)
partition by range (sale_date) interval (interval '1' day)
( partition p1 values less than ((sysdate-90)));
but I have error like
"ORA-14019: partition bound element must be one of: string, datetime or interval literal, number, or MAXVALUE"
so what can I do here?
You can't do that. Following the documentation
Creating a Range-Partitioned Table
The PARTITION BY RANGE clause of the CREATE TABLE statement specifies
that the table or index is to be range-partitioned. The PARTITION
clauses identify the individual partition ranges, and the optional
subclauses of a PARTITION clause can specify physical and other
attributes specific to a partition segment. If not overridden at the
partition level, partitions inherit the attributes of their underlying
table.
The VALUES LESS THAN clause determines the partition bound: rows with
partitioning key values that compare less than the ordered list of
values specified by the clause are stored in the partition. Each
partition is given a name (sales_q1, sales_q2, ...), and each
partition is contained in a separate tablespace (tsa, tsb, ...).
That means that the range is determined for the key value. sysdate is a function, therefore it is not a value until it is executed. It can't be part of a range partition key value.
Keep in mind the purpose or partitioning. The idea is to split a big segment ( table ) into smaller ones ( partitions ) using a key column. In your case, you want to store in one partition the rows where the key column is less than sysdate-90, which means that today the row will go to one partition, but in one day if the condition sysdate-90 is met, the row should be moved to the other partition.
If you want to do this anyway, although I don't recommend it, you will have to develop your own maintenance process:
The table has keys for each date ( 3 months of partitions for each date)
The Partition others will get everything else, so anything that has no match with any of the existing partition keys.
Every day you will have to retrieve the records that are meeting the condition sysdate-90 and move them to the others partition.
For doing that you need to enable row movement in your table: alter table xx enable row movement
Hope it clarifies
You can use
partition p1 values less than (DATE '2021-01-01')
If your application adds data from let's say 2021-08-01, then Oracle will create single new partition for 2021-08-01, it can deal with gaps or missing days.
If you use SEGMENT CREATION DEFERRED clause (maybe meanwhile the default) then the initial partition does not even consume any space on your disk.

Is it possible to automatically create a new partition in a list partitioned table?

The code below would create a new partition if I would insert a date that does not exist in my table. Is it possible to do the same thing in a list partitioned table, where the partition is based on a VARCHAR2 column?
ALTER TABLE MY_TABLE MODIFY
PARTITION BY RANGE(DATE) INTERVAL(NUMTODSINTERVAL(1,'day'))
( partition MY_PARTITION values less than (to_date('2019-06-01', 'yyyy-mm-dd')));
Yes, it is possible starting from the Oracle 12.2.
See the details here.

Change the datatype of a column in a partitioned table with billion rows

We have a table with 120 partitions on date range which in turn is subpartitioned again on range.
Each partition has around 200 million records, the conventional way of changing the datatype will make our production unresponsive for hours.Is there any better way for changing the datatype of such a huge table?
We have already tried the following options:
Exchange partition. This does not work.
Create a new table with the same structure as the existing one and the altered column, and inserting the data using /*+ append *. It again takes hours.
Currently the column size is varchar2(30). We need to change it to:
ALTER TABLE ORDERS MODIFY (INFO VARCHAR2(50) );
Changing varchar2(30) to varchar2(50) should work instantly and should not cause any trouble.
You modify just some meta data but actual table data is not touched.

How do I alter my existing table to create a range partition in Oracle

I have existing table which has 10 years of data (I have taken dump).
I would like to Range partition the existing table on one date key column within the table.
Most of the examples I see are with CREATE TABLE..PARTITION BY RANGE... to add new partitions. But my table is existing table.
I assume I need some ALTER statement.
ALTER TABLE TABLE_NAME
PARTITION BY RANGE(CREATED_DATE)
PARTITION JAN16 VALUES LESS THAN (01-02-2016),
PARTITION FEB16 VALUES LESS THAN (01-03-2016) AND GREATER THAN(31-01-2016),//OR?
PARTITION MAR16 VALUES BETWEEN (01-03-2016) AND (31-03-2016), //OR?
Two questions..
Do I need Alter statement to add partitioning mechanism or need to work with create statement?
What is the proper syntax for keeping each partition having only ONE MONTH data.
If you are using Oracle 12c Release 2 you could use single ALTER to convert non-partitioned table to partitioned one (this is one way trip):
CREATE TABLE my_tab ( a NUMBER(38,0), b NUMBER(38,0));
ALTER TABLE MY_TAB MODIFY PARTITION BY RANGE (a) INTERVAL (1000) (
PARTITION p1 VALUES LESS THAN (1000)) ONLINE;
You could convert indexes too, adding:
update indexes (index_name [local/global]);
db<>fiddle demo
Beacuse your table non-partitioned you have two options:
Export data, drop table, create new patitioned table, import data.
Use split then exchange partition method. https://oracle-base.com/articles/misc/partitioning-an-existing-table-using-exchange-partition
Also, if you want new partition per month read about SET INTERVAL. For example:
CREATE TABLE tst
(col_date DATE)
PARTITION BY RANGE (col_date) INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'))
(PARTITION col_date_min VALUES LESS THAN (TO_DATE('2010-01-01', 'YYYY-MM-DD')));

Add sub partition on another column in oracle

I have a table which has two partitions (by range): first_half and second_half based on a column "INSERT_DAY".
I need to add subpartitions "SUCCESS" and "NONSUCCESS" based on the values of another column "STATUS" (subpartition by list) i.e. I need to transform my range partition to composite (range-list) partition.
I do not wish to drop existing tables or partitions. What is the ALTER query for this?
PS: The database is Oracle 9i
No alter query for adding subpartitions as far as i know.
To get the desired result performe the folowing steps
Create the table in the structure you want using create as select with the partitions and the sub partitions.
switch the names of the two tables.
you can also explore the use of dbms_Redefinition but if you have a luxury of a littel downtime it's not worth it.

Resources