Convert Non-partition table to partitioned table using ONLINE in Oracle PL/SQL - oracle

I got to know as we cannot convert existing non-partitioned table to partitioned table but the below link from the Oracle suggest that with the help of "ONLINE" keyword we can do it.
https://docs.oracle.com/en/database/oracle/oracle-database/12.2/vldbg/evolve-nopartition-table.html#GUID-5FDB7D59-DD05-40E4-8AB4-AF82EA0D0FE5
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;
But it's not working for me, throwing error as "Invalid Partition Name".
I don't want to use dbms_redefinition.

If you are using Oracle 12c Release 2 you could use single ALTER to convert non-partitioned table to partitioned one :
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;

On Oracle Database 12c Release 1 (12.1.0.2.0) and without using dbms_redefinition your options may be limited to creating a new partitioned table with the same structure as the original table and copying over the data, creating indexes, constraints etc.
CREATE TABLE my_tab_part -- new partitioned table
PARTITION BY RANGE (a)
INTERVAL ( 1000 )
(PARTITION p1 VALUES LESS THAN (1000))
AS
SELECT * FROM my_tab;

Related

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.

How to add interval partition to an existing table in oracle?

I have a scenario in which want to partition an existing Oracle table using interval partitioning. I don't know what is the best approach in the database to do the same.
Table size is around 11 GB. Partitioning needs to be done on Date column with the interval of 1 month.
Recreate the table:
Rename your current table to something like <your-table-name>_OLD
Create a new partitioned table with your original table name.
Insert your table data from the old table to the new table.
Drop the old table.
Precondition: you have the required space available in your database.
And don't forget to recreate all needed constraints etc.
Or use Oracle's online table redefinition mechanism: https://docs.oracle.com/en/database/oracle/oracle-database/12.2/vldbg/evolve-nopartition-table.html#GUID-6054142E-207A-4DF0-A62A-4C1A94DD36C4
If you want only partition the new data and let the old table as one partition you may usi this ismple approach withou reorganisation and required twice space.
0) This is your sample data , ID id the partition column defined up to 10.000
create table my_tab
(id number,
vc1 varchar2(100));
insert into my_tab(id,vc1)
select rownum id, 'xxx'||rownum vc1 from dual connect by level <= 10000;
commit;
1) create empty interval partitione dtable with one partition covering all your data - here ID less then 10.001
create table my_part_tab
(id number,
vc1 varchar2(100))
PARTITION BY RANGE (id)
INTERVAL (1000)
(PARTITION p1 VALUES LESS THAN (10001));
2) Define identical indexes on the partition table as on the original table
3) Exchange your table with the initial partition.
alter table my_part_tab exchange partition P1
with table my_tab
including indexes;
Now your original table is empty and all data are in the partition P1of the partitioned table.
New data (higher keys) would be stored based on the interval partition policy.

oracle how to alter table add partition by range interval

i have searched a lot but i have found nothing about how to
add a range partition to an existing table
alter table myuser.mytable
add PARTITION BY RANGE (mynumber) INTERVAL (1)
( PARTITION p1 VALUES LESS THAN (108))
that gives me ORA:14150 error, SUBPARTITON keyword is missing,
but i dont want to give subpartition
EDIT: On 19c and 12cR2 this can be done using the MODIFY Clause of ALTER TABLE
ALTER TABLE myuser.mytable MODIFY
PARTITION BY RANGE (mynumber) INTERVAL (1)
( PARTITION p1 VALUES LESS THAN (108)
PARTITION p2 VALUES LESS THAN (109))
ONLINE
UPDATE INDEXES
See this from Oracle Docs
PRIOR To 19c or 12cR2:
If your existing Table is Non-Partitioned you will have to:
CREATE a new TABLE with partition definitions. Lets call this table MYTABLE_NEW
INSERT into MYTABLE_NEW all data from MYTABLE
RENAME MYTABLE to MYTABLE_OLD
RENAME MYTABLE_NEW to MYTABLE
DROP MYTABLE_OLD
OR
dbms_redefinition can also be used
See this from AskTom
Also see this other Answer

How to store range/hash composite partitions in separate datafiles by range?

I'm creating a database which will utilize composite partitioning. I will partition one table using range partitioning (by date)
and then further subpartition it by hash (by client id). So far so good, no problem, but I also need to have those partitions
stored in separate data files each dbf holding data for a single month. I'm reading on composite partitions and what I found
is that primary range partitioning will be only a logical one and data will be stored in subpartitions instead which seems to
make my goal impossible. Am I right and should look for a different solution?
Thanks in advance.
My databases are Oracle 11g and Oracle 12
On existing table you can move partitions or subpartitions to a different tablespace, i.e. different datafile, examples:
ALTER TABLE scuba_gear MOVE SUBPARTITION bcd_types TABLESPACE tbs23;
ALTER TABLE parts MOVE PARTITION depot2 TABLESPACE ts094;
see Moving Subpartitions and Moving Table Partitions
For new tables typically you would be create them like this:
CREATE TABLE sales
( prod_id NUMBER(6)
, cust_id NUMBER
, time_id DATE
, channel_id CHAR(1)
, promo_id NUMBER(6)
, quantity_sold NUMBER(3)
, amount_sold NUMBER(10,2)
)
PARTITION BY RANGE (time_id)
INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
STORE IN (ts_1, ts_2, ts_3, ts_4, ts_5, ts_6 ,ts_7 ,ts_8, ts_9, ts_10, ts_11, ts_12)
SUBPARTITION BY HASH (cust_id) SUBPARTITIONS 4
( PARTITION before_2000 VALUES LESS THAN (TO_DATE('01-JAN-2000','dd-MON-yyyy')));
Oracle then will put the monthly partitions by "round-robin" method to these 12 tablespaces. STORE IN clause is also possible for subpartitions, see Creating a composite range-hash partitioned table

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')));

Resources