ORA-00926: missing VALUES keyword in create table - oracle

Hi I have following script to create table with partition and sub partition with Range and list:
CREATE TABLE C##API_USER.METERENERGY
(
METERID NUMBER NOT NULL
, ENERGY_ACTIVE_EXPORT FLOAT(63)
, ENERGY_ACTIVE_IMPORT FLOAT(63)
, ENERGY_REACTIVE_EXPORT FLOAT(63)
, ENERGY_REACTIVE_IMPORT FLOAT(63)
, COL_G_DATE NUMBER(10)
)
LOGGING
TABLESPACE HEDC_TABLE_SPACE
PARTITION BY RANGE (COL_G_DATE)
SUBPARTITION BY LIST (METERID)
(
PARTITION C##API_USER.COL_G_DATE_1483228800 VALUES LESS THAN (1483228800‬) TABLESPACE HEDC_TABLE_SPACE
, PARTITION C##API_USER.COL_G_DATE_1485820800 VALUES LESS THAN (1485820800) TABLESPACE HEDC_TABLE_SPACE
, PARTITION C##API_USER.COL_G_DATE_1488412800 VALUES LESS THAN (1488412800) TABLESPACE HEDC_TABLE_SPACE
);
CREATE INDEX C##API_USER.METERENERGY_INDEX1 ON C##API_USER.METERENERGY (COL_G_DATE DESC, METERID ASC);
but oracle databse show error Report :
Error starting at line : 1 in command -
Error report -
ORA-00926: missing VALUES keyword
00926. 00000 - "missing VALUES keyword"
*Cause:
*Action:
so What I missing?(I'm using Oracle 19c with oracle sql Developer)
and if could you help me to find another answer Thanks:
(Oracle Database create automatic partition by range (long))

Subpartitions are missing.
This is just an example; you'd use smart values.
SQL> CREATE TABLE meterenergy
2 (
3 meterid NUMBER NOT NULL,
4 energy_active_export FLOAT (63),
5 energy_active_import FLOAT (63),
6 energy_reactive_export FLOAT (63),
7 energy_reactive_import FLOAT (63),
8 col_g_date NUMBER (10)
9 )
10 PARTITION BY RANGE (col_g_date)
11 SUBPARTITION BY LIST (meterid)
12 (PARTITION col_g_date_1483228800 VALUES LESS THAN (1483228800)
13 (SUBPARTITION sub1 VALUES (1),
14 SUBPARTITION sub2 VALUES (2)
15 ),
16 PARTITION col_g_date_1485820800 VALUES LESS THAN (1485820800)
17 (SUBPARTITION sub3 VALUES (3),
18 SUBPARTITION sub4 VALUES (4)
19 )
20 );
Table created.
SQL>

Related

Repartitioning a table on a different column

We need to change the structure of our DB by re-partitioning a parent table and adding partitions to the child tables. The partitions will be based on range of a date-time field (which is the time of insertion).
The goal is to implement the changes with as little downtime as possible. So we have though on doing it on 2 phases: do the main load while the application is running and load the delta after the application has been shutdown.
I would like to know if the following steps are correct for the plan I mentioned, focusing on the part of re-partitioning the parent table. I have based on this example from Oracle: https://docs.oracle.com/database/121/SUTIL/GUID-56D8448A-0106-4B8C-85E0-11CFED8C71B1.htm
1. create a directory for the export/import of dumps
-- user: SYS
CREATE OR REPLACE DIRECTORY dumps AS '/data/tmp';
GRANT READ, WRITE ON DIRECTORY dumps TO APP_USR;
2. export the table while the application is running
# nohup expdp APP_USR/pwd parfile=export.par &
directory=dumps
dumpfile=parent_table.dmp
parallel=8
logfile=export.log
tables=parent_table
query=parent_table:"WHERE VERSION_TSP <= sysdate"
3. create a duplicate of the table with the new partitioning
CREATE TABLE "PARENT_TABLE_REPARTITIONED"
(
-- same fields as original
CONSTRAINT PK_TABLE_ PRIMARY KEY (foo, boo) -- with different name than original
)
PARALLEL 8
PARTITION BY RANGE (VERSION_TSP)
INTERVAL (NUMTOYMINTERVAL(1, 'MONTH'))
(
PARTITION PARENT_TABLE_PARTITION_ -- with different name than original (should I?)
VALUES LESS THAN (TO_DATE('2007-07-01', 'YYYY-MM-DD')) COMPRESS FOR OLTP
)
ENABLE ROW MOVEMENT
;
-- with new local indexes (named differently)
CREATE INDEX IDX_VERSION_TSP_ ON PARENT_TABLE_REPARTITIONED (VERSION_TSP) LOCAL;
4. populate the re-partitioned table while the application is running
# nohup impdp APP_USR/pwd parfile=import.par &
directory=dumps
dumpfile=parent_table.dmp
parallel=8
logfile=import.log
remap_table=PARENT_TABLE:PARENT_TABLE_REPARTITIONED
table_exists_action=APPEND
5. Application shutdown (and backup the DB)
6. populate the delta
-- execute with nohup
declare
startDate DATE;
begin
select max(version_tsp) into startDate from PARENT_TABLE_REPARTITIONED;
insert into PARENT_TABLE_REPARTITIONED select /*+ parallel(8) */ s.* from PARENT_TABLE s where s.VERSION_TSP > startDate;
commit;
end;
7. switch tables
drop table parent_table cascade constraints;
rename parent_table_repartitioned to parent_table;
8. deploy the new version of the application
Is ok to export ALL from the table or should I export DATA_ONLY?
But most importantly, are those steps a valid approach?
Are you on 12.2 or higher? It could be as easy as:
SQL> create table t
2 partition by range ( created )
3 (
4 partition p1 values less than ( date '2020-01-01' ),
5 partition p2 values less than ( date '2021-01-01' ),
6 partition p3 values less than ( date '2022-01-01' ),
7 partition p4 values less than ( date '2023-01-01' )
8 )
9 as select * from dba_objects
10 where created is not null
11 and last_ddl_time is not null;
Table created.
SQL>
SQL> create index t_ix on t ( owner ) local;
Index created.
SQL>
SQL>
SQL> alter table t modify
2 partition by range ( last_ddl_time )
3 (
4 partition p1 values less than ( date '2020-01-01' ),
5 partition p2 values less than ( date '2021-01-01' ),
6 partition p3 values less than ( date '2022-01-01' ),
7 partition p4 values less than ( date '2023-01-01' )
8 ) online ;
Table altered.

ORA-30657 when creating an interval (or auto list) external partition table

When trying to create an Interval (or auto list) external partitioned table with DBMS_CLOUD, I am getting ORA-30657: operation not supported on external organized table.
What am I missing?
SQL> BEGIN
2 DBMS_CLOUD.CREATE_EXTERNAL_PART_TABLE(
3 table_name =>'PETX',
4 credential_name =>'MY_CRED',
5 format => json_object('delimiter' value '#'),
6 column_list => 'deptno number,dname char(14),loc char(13)',
7 partitioning_clause => 'partition by range (deptno) interval (15)
8 (
9 partition xp1 values less than (15) location(''https://swiftobjectstorage.XXXX/xp1_15.txt'') ,
10 partition xp2 values less than (30) location (''https://swiftobjectstorage.XXXX/xp2_30.txt'')
11 )'
12 );
13 END;
14 /
Error starting at line : 5 in command -
BEGIN
DBMS_CLOUD.CREATE_EXTERNAL_PART_TABLE(
table_name =>'PETX',
credential_name =>'MY_CRED',
format => json_object('delimiter' value '#'),
column_list => 'deptno number,dname char(14),loc char(13)',
partitioning_clause => 'partition by range (deptno) interval (15)
(
partition xp1 values less than (15) location(''https://swiftobjectstorage.XXXX/xp1_15.txt'') ,
partition xp2 values less than (30) location (''https://swiftobjectstorage.XXXX/xp2_30.txt'')
)'
);
END;
Error report -
ORA-20000: ORA-30657: operation not supported on external organized table
ORA-06512: at "C##CLOUD$SERVICE.DBMS_CLOUD", line 1289
ORA-06512: at "C##CLOUD$SERVICE.DBMS_CLOUD", line 4115
Interval and auto-list partitioning is functionality that creates new partitions as-needed, based on new data inserted into the database where the partition key(s) of the new data do not map to any existing partition. With external tables the database does not control the data (or insertion of it), thus the concept of auto-generation of a partition at insertion is not applying to external tables.
Adding a new partition to a partitioned external table is equivalent to having new data files that the table has to point at. You have to tell the database about this, which you are doing by adding a new partition to a table (manually or programmatically).
Short example of how to make the above-example work and how to add a new partition (pointing to additional data files):
SQL>
SQL> BEGIN
2 DBMS_CLOUD.CREATE_EXTERNAL_PART_TABLE(
3 table_name =>'PETX',
4 credential_name =>'MY_CRED',
5 format => json_object('delimiter' value '#'),
6 column_list => 'deptno number,dname char(14),loc char(13)',
7 partitioning_clause => 'partition by range (deptno)
8 (
9 partition xp1 values less than (15) location(''https://swiftobjectstorage.XXXX/xp1_15.txt'') ,
10 partition xp2 values less than (30) location (''https://swiftobjectstorage.XXXX/xp2_30.txt'')
11 )'
12 );
13 END;
14 /
PL/SQL procedure successfully completed.
SQL>
SQL> alter table petx add partition xp3 values less than (50) location ('https://swiftobjectstorage.XXXX/xp3_45.txt');
Table PETX altered.
SQL> select count(*) from petx partition (xp3);
COUNT(*)
----------
49999999
PS: The exact same behavior applies to standard Oracle Database.

SQL Error: ORA-14006: invalid partition name

I am trying to partition an existing table in Oracle 12C R1 using below SQL statement.
ALTER TABLE TABLE_NAME MODIFY
PARTITION BY RANGE (DATE_COLUMN_NAME)
INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
(
PARTITION part_01 VALUES LESS THAN (TO_DATE('01-SEP-2017', 'DD-MON-RRRR'))
) ONLINE;
Getting error:
Error report -
SQL Error: ORA-14006: invalid partition name
14006. 00000 - "invalid partition name"
*Cause: a partition name of the form <identifier> is
expected but not present.
*Action: enter an appropriate partition name.
Partition needs to be done on the basis of data datatype column with the interval of one month.
Min value of Date time column in the Table is 01-SEP-2017.
You can't partition an existing table like that. That statement is modifying the partition that hasn't been created yet. I don't know the automatic way to do this operation and I am not sure that you can do it.
Although I have done this thing many times but with manual steps. Do the following if you can't find an automated solution:
Create a partitioned table named table_name_part with your clauses and all your preferences.
Insert into this partitioned table all rows from original table. Pay attention to compression. If you have some compression on table (Basic or HCC) you have to use + APPEND hint.
Create on partitioned table your constrains and indexes from the original table.
Rename the tables and drop the original table. Do not drop it until you make some counts on them.
I saw that your table has the option to auto-create partition if it does not exists. (NUMTOYMINTERVAL(1,'MONTH')) So you have to create your table with first partition only. I assume that you have here a lot of read-only data, so you won't have any problem with consistency instead of last month. Probably there is some read-write data so there you have to be more careful with the moment when you want to insert data in new table and switch tables.
Hope to help you. As far as I know there might be a package named DBMS_REDEFINITION that can help you with an automated version of my steps. If you need more details or need some help on my method, please don't hesitate.
UPDATE:
From Oracle 12c R2 you can convert a table from an unpartitioned to a partitioned one with your method. Find a link below. Now this is a challenge for me and I am trying to convert, but I think there is no way to make this conversion online in 12c R1.
In previous releases you could partition a non-partitioned table using
EXCHANGE PARTITION or DBMS_REDEFINITION in an "almost online" manner,
but both methods require multiple steps. Oracle Database 12c Release 2
makes it easier than ever to convert a non-partitioned table to a
partitioned table, requiring only a single command and no downtime.
https://oracle-base.com/articles/12c/online-conversion-of-a-non-partitioned-table-to-a-partitioned-table-12cr2
Solution
I found a solution for you. Here you will have all of my steps that I run to convert table online. :)
1. Create regular table and populate it.
CREATE TABLE SCOTT.tab_unpartitioned
(
id NUMBER,
description VARCHAR2 ( 50 ),
created_date DATE
);
INSERT INTO tab_unpartitioned
SELECT LEVEL,
'Description for ' || LEVEL,
ADD_MONTHS ( TO_DATE ( '01-JAN-2017', 'DD-MON-YYYY' ),
-TRUNC ( DBMS_RANDOM.VALUE ( 1, 4 ) - 1 ) * 12 )
FROM DUAL
CONNECT BY LEVEL <= 10000;
COMMIT;
2. Create partitioned table with same structure.
--If you are on 11g create table with CREATE TABLE command but with different name. ex: tab_partitioned
CREATE TABLE SCOTT.tab_partitioned
(
id NUMBER,
description VARCHAR2 ( 50 ),
created_date DATE
)
PARTITION BY RANGE (created_date)
INTERVAL( NUMTOYMINTERVAL(1,'YEAR'))
(PARTITION part_2015 VALUES LESS THAN (TO_DATE ( '01-JAN-2016', 'DD-MON-YYYY' )),
PARTITION part_2016 VALUES LESS THAN (TO_DATE ( '01-JAN-2017', 'DD-MON-YYYY' )),
PARTITION part_2017 VALUES LESS THAN (TO_DATE ( '01-JAN-2018', 'DD-MON-YYYY' )));
--this is an alter command that works only in 12c.
ALTER TABLE tab_partitioned
MODIFY
PARTITION BY RANGE (created_date)
(PARTITION part_2015 VALUES LESS THAN (TO_DATE ( '01-JAN-2016', 'DD-MON-YYYY' )),
PARTITION part_2016 VALUES LESS THAN (TO_DATE ( '01-JAN-2017', 'DD-MON-YYYY' )),
PARTITION part_2017 VALUES LESS THAN (TO_DATE ( '01-JAN-2018', 'DD-MON-YYYY' )));
3. Check if the table can be converted. This procedure should run without any error.
Prerequisites: table should have an UNIQUE INDEX and a Primary Key constraint.
EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE('SCOTT','TAB_UNPARTITIONED');
4. Run the following steps like I have done.
EXEC DBMS_REDEFINITION.START_REDEF_TABLE('SCOTT','TAB_UNPARTITIONED','TAB_PARTITIONED');
var num_errors varchar2(2000);
EXEC DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS('SCOTT','TAB_UNPARTITIONED','TAB_PARTITIONED', 1,TRUE,TRUE,TRUE,FALSE,:NUM_ERRORS,FALSE);
SQL> PRINT NUM_ERRORS -- Should return 0
EXEC DBMS_REDEFINITION.SYNC_INTERIM_TABLE('SCOTT','TAB_UNPARTITIONED','TAB_PARTITIONED');
EXEC DBMS_REDEFINITION.FINISH_REDEF_TABLE('SCOTT','TAB_UNPARTITIONED','TAB_PARTITIONED');
At the end of the script you will see that the original table is partitioned.
Try Oracle Live SQL I used to use Oracle 11g EE and got the same error message. So I tried Oracle live SQL and it perfectly worked. It has very simple and easy to understand interface,
For example, I'm creating a sales table and inserting some dummy data and partition it using range partitioning method,
CREATE TABLE sales
(product VARCHAR(300),
country VARCHAR(100),
sales_year DATE);
INSERT INTO sales (product, country, sales_year )
VALUES ('Computer','Kazakhstan',TO_DATE('01/02/2018','DD/MM/YYYY'));
INSERT INTO sales (product, country, sales_year )
VALUES ('Mobile Phone','China',TO_DATE('23/12/2019','DD/MM/YYYY'));
INSERT INTO sales (product, country, sales_year )
VALUES ('Camara','USA',TO_DATE('20/11/2020','DD/MM/YYYY'));
INSERT INTO sales (product, country, sales_year )
VALUES ('Watch','Bangladesh',TO_DATE('19/03/2020','DD/MM/YYYY'));
INSERT INTO sales (product, country, sales_year )
VALUES ('Cake','Sri Lanka',TO_DATE('13/04/2021','DD/MM/YYYY'));
ALTER TABLE sales MODIFY
PARTITION BY RANGE(sales_year)
INTERVAL(INTERVAL '1' YEAR)
(
PARTITION sales_2018 VALUES LESS THAN(TO_DATE('01/01/2019','DD/MM/YYYY')),
PARTITION sales_2019 VALUES LESS THAN(TO_DATE('01/01/2020','DD/MM/YYYY')),
PARTITION sales_2020 VALUES LESS THAN(TO_DATE('01/01/2021','DD/MM/YYYY')),
PARTITION sales_2021 VALUES LESS THAN(TO_DATE('01/01/2022','DD/MM/YYYY'))
)ONLINE;
Finally, I can write SELECT query for partitions to confirm that the partitions are created successfully.
SELECT *
FROM sales PARTITION (sales_2020);
And it gives the expected output,

ORACLE - Partitioning with changing values

Assuming following table:
create table INVOICE(
INVOICE_ID NUMBER
,INVOICE_SK NUMBER
,INVOICE_AMOUNT NUMBER
,INVOICE_TEXT VARCHAR2(4000 Char)
,B2B_FLAG NUMBER -- 0 or 1
,ACTIVE NUMBER(1) -- 0 or 1
)
PARTITION BY LIST (ACTIVE)
SUBPARTITION BY LIST (B2B_FLAG)
( PARTITION p_active_1 values (1)
( SUBPARTITION sp_b2b_flag_11 VALUES (1)
, SUBPARTITION sp_b2b_flag_10 VALUES (0)
)
,
PARTITION p_active_0 values (0)
( SUBPARTITION sp_b2b_flag_01 VALUES (1)
, SUBPARTITION sp_b2b_flag_00 VALUES (0)
)
)
For perfomance reasons the table should get a "Composite List-List" partitioning, see http://docs.oracle.com/cd/E18283_01/server.112/e16541/part_admin001.htm#i1006565.
The problematic point is, that the ACTIVE-Flag will change requently for a huge amount of records and sometimes also the B2B_FLAG. Will Oracle automatically recognize the records, for which the partitioning value has changed and move them to the appropriate partion or do I have to call some kind of maintenance function, in order to reorganize the partitions?
You need to enable row movement on the table or the update statement will fail with ORA-14402: updating partition key column would cause a partition change.
See the following testcase:
create table T_TESTPART
(
pk number(10),
part_key number(10)
)
partition by list (part_key) (
partition p01 values (1),
partition p02 values (2),
partition pdef values (default)
);
alter table T_TESTPART
add constraint pk_pk primary key (PK);
Now insert a row and try to update the partitioning value:
insert into t_testpart values (1,1);
update t_testpart set part_key = 2 where pk = 1;
You will now get the Error mentioned above.
If you enable row movement, the same statement will work and oracle will move the row to the other partition:
alter table t_testpart enable row movement;
update t_testpart set part_key = 2 where pk = 1;
I did not do any performance tests, but Oracle will probably delete the row from the first partition and insert it to the second partition. Consider this when using it in large scale.
In my own databases, I usually only use partitioning on columns that do not change.
Further reading:
http://www.dba-oracle.com/t_callan_oracle_row_movement.htm

Oracle Partition - Error ORA14400 - inserted partition key does not map to any partition

I'm trying to insert information in a partition table, but I don't know what I'm doing wrong!
Show me this error: ORA-14400: inserted partition key does not map to any partition"
The table dba_tab_partitions shows this informations below:
1 PDIA_98_20091023 0
2 PDIA_98_20091022 0
3 PDIA_98_20091021 0
4 PDIA_98_20091020 0
5 PDIA_98_20091019 0
Please help me rs
select partition_name,column_name,high_value,partition_position
from ALL_TAB_PARTITIONS a , ALL_PART_KEY_COLUMNS b
where table_name='YOUR_TABLE' and a.table_name = b.name;
This query lists the column name used as key and the allowed values. make sure, you insert the allowed values(high_value). Else, if default partition is defined, it would go there.
EDIT:
I presume, your TABLE DDL would be like this.
CREATE TABLE HE0_DT_INF_INTERFAZ_MES
(
COD_PAIS NUMBER,
FEC_DATA NUMBER,
INTERFAZ VARCHAR2(100)
)
partition BY RANGE(COD_PAIS, FEC_DATA)
(
PARTITION PDIA_98_20091023 VALUES LESS THAN (98,20091024)
);
Which means I had created a partition with multiple columns which holds value less than the composite range (98,20091024);
That is first COD_PAIS <= 98 and Also FEC_DATA < 20091024
Combinations And Result:
98, 20091024 FAIL
98, 20091023 PASS
99, ******** FAIL
97, ******** PASS
< 98, ******** PASS
So the below INSERT fails with ORA-14400; because (98,20091024) in INSERT is EQUAL to the one in DDL but NOT less than it.
SQL> INSERT INTO HE0_DT_INF_INTERFAZ_MES(COD_PAIS, FEC_DATA, INTERFAZ)
VALUES(98, 20091024, 'CTA'); 2
INSERT INTO HE0_DT_INF_INTERFAZ_MES(COD_PAIS, FEC_DATA, INTERFAZ)
*
ERROR at line 1:
ORA-14400: inserted partition key does not map to any partition
But, we I attempt (97,20091024), it goes through
SQL> INSERT INTO HE0_DT_INF_INTERFAZ_MES(COD_PAIS, FEC_DATA, INTERFAZ)
2 VALUES(97, 20091024, 'CTA');
1 row created.
For this issue need to add the partition for date column values, If last partition 20201231245959, then inserting the 20210110245959 values, this issue will occurs.
For that need to add the 2021 partition into that table
ALTER TABLE TABLE_NAME ADD PARTITION PARTITION_NAME VALUES LESS THAN (TO_DATE('2021-12-31 24:59:59', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')) NOCOMPRESS

Resources