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

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

Related

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

insert multiple row into table using select however table has primery key in oracle SQL [duplicate]

This question already has answers here:
How to create id with AUTO_INCREMENT on Oracle?
(18 answers)
Closed 8 years ago.
I am facing issue while inserting multiple row in one go into table because column id has primary key and its created based on sequence.
for ex:
create table test (
iD number primary key,
name varchar2(10)
);
insert into test values (123, 'xxx');
insert into test values (124, 'yyy');
insert into test values (125, 'xxx');
insert into test values (126, 'xxx');
The following statement creates a constraint violoation error:
insert into test
(
select (SELECT MAX (id) + 1 FROM test) as id,
name from test
where name='xxx'
);
This query should insert 3 rows in table test (having name=xxx).
You're saying that your query inserts rows with primary key ID based on a sequence. Yet, in your insert/select there is select (SELECT MAX (id) + 1 FROM test) as id, which clearly is not based on sequence. It may be the case that you are not using the term "sequence" in the usual, Oracle way.
Anyway, there are two options for you ...
Create a sequence, e.g. seq_test_id with the starting value of select max(id) from test and use it (i.e. seq_test_id.nextval) in your query instead of the select max(id)+1 from test.
Fix the actual subselect to nvl((select max(id) from test),0)+rownum instead of (select max(id)+1 from test).
Please note, however, that the option 2 (as well as your original solution) will cause you huge troubles whenever your code runs in multiple concurrent database sessions. So, option 1 is strongly recommended.
Use
insert into test (
select (SELECT MAX (id) FROM test) + rownum as id,
name from test
where name='xxx'
);
as a workaround.
Of course, you should be using sequences for integer-primary keys.
If you want to insert an ID/Primary Key value generated by a sequence you should use the sequence instead of selecting the max(ID)+1.
Usually this is done using a trigger on your table wich is executed for each row. See sample below:
CREATE TABLE "MY_TABLE"
(
"MY_ID" NUMBER(10,0) CONSTRAINT PK_MY_TABLE PRIMARY KEY ,
"MY_COLUMN" VARCHAR2(100)
);
/
CREATE SEQUENCE "S_MY_TABLE"
MINVALUE 1 MAXVALUE 999999999999999999999999999
INCREMENT BY 1 START WITH 10 NOCACHE ORDER NOCYCLE NOPARTITION ;
/
CREATE OR REPLACE TRIGGER "T_MY_TABLE"
BEFORE INSERT
ON
MY_TABLE
REFERENCING OLD AS OLDEST NEW AS NEWEST
FOR EACH ROW
WHEN (NEWEST.MY_ID IS NULL)
DECLARE
IDNOW NUMBER;
BEGIN
SELECT S_MY_TABLE.NEXTVAL INTO IDNOW FROM DUAL;
:NEWEST.MY_ID := IDNOW;
END;
/
ALTER TRIGGER "T_MY_TABLE" ENABLE;
/
insert into MY_TABLE (MY_COLUMN) values ('DATA1');
insert into MY_TABLE (MY_COLUMN) values ('DATA2');
insert into MY_TABLE (MY_ID, MY_COLUMN) values (S_MY_TABLE.NEXTVAL, 'DATA3');
insert into MY_TABLE (MY_ID, MY_COLUMN) values (S_MY_TABLE.NEXTVAL, 'DATA4');
insert into MY_TABLE (MY_COLUMN) values ('DATA5');
/
select * from MY_TABLE;

Log all errors for a value into error log if a single row fails

I am trying to maintain data integrity and logging errors to an error table. I've got 3 tables with unique constraints and 1 error table:
create table tbl_one (
pass_no number,
constraint tbl_one_u01 unique (pass_no) );
insert into tbl_one values(10);
insert into tbl_one values(20);
create table tbl_two (
cus_no number,
cus_name varchar2(50),
pass_no number,
constraint tbl_two_u01 unique (cus_no) );
insert into tbl_two values( 101, 'NameX',10);
insert into tbl_two values( 102, 'NameY',10);
insert into tbl_two values( 103, 'NameZ',20);
create table tbl_target (
cus_no number,
pass_no number,
constraint tbl_target_u01 unique (cus_no),
constraint tbl_target_u02 unique (pass_no));
exec dbms_errlog.create_error_log('tbl_target','tbl_target_err');
I am trying to log all ORA-00001 errors to the error table tbl_target_err like this:
begin
insert into tbl_target
select a.pass_no, b.cus_no
from tbl_one a
inner join tbl_two b on b.pass_no = a.pass_no
log errors into tbl_target_err reject limit 10;
end;
The result is:
select * from tbl_target;
-------------------
CUS_NO PASS_NO
101 10
103 20
and the error table:
CUS_NO PASS_NO
102 10
I need all the violated errors to go into the error table. If the value of pass_no 10 is violated then all 10 values should inserted into the error table; not, one into target and one to error table. I don't want to use exists statements because I won't able to log all violated values.
How could I go about doing this?
You can't use the error logging mechanism for this as it isn't designed to support it. It errors at the point it tries to create the duplicate in the table - the first value it tries to insert for pass_no 10 is valid on its own - so it would have to distinguish between data that already existed and multiple values coming from the insert, to start with. So you'd need to roll your own.
One option is to create your own table to hold the duplicates, and use an insert all to decide which values belong in each table:
create table tbl_target_dup (
cus_no number,
pass_no number
);
insert all
when cus_count = 1 and pass_count = 1 then
into tbl_target values (cus_no, pass_no)
else
into tbl_target_dup values (cus_no, pass_no)
select a.pass_no, b.cus_no,
count(*) over (partition by a.pass_no) as pass_count,
count(*) over (partition by b.cus_no) as cus_count
from tbl_one a
join tbl_two b on b.pass_no = a.pass_no;
This allows you to have more columns than those affected by the PK/UK, and insert them only into the real table if you prefer, or a subset into the 'error' table. With just those two columns in each table you get:
select * from tbl_target;
CUS_NO PASS_NO
---------- ----------
103 20
select * from tbl_target_dup;
CUS_NO PASS_NO
---------- ----------
101 10
102 10
SQL Fiddle demo.
You could do the same thing with two inserts based on the same select, one with a subquery checking that both counts are 1, other checking that at least one is not, but this might perform better.

Oracle 'INSERT ALL' ignore duplicates

I have a database table with a unique constraint on it (unique (DADSNBR, DAROLEID) pair). I am going to be inserting multiple values into this table simultaneously, so I'd like to get it done using one query - I'm assuming this would be the faster way. My query is thus:
INSERT ALL
INTO ACCESS (DADSNBR, DAROLEID) VALUES (68, 1)
INTO ACCESS (DADSNBR, DAROLEID) VALUES (68, 2)
INTO ACCESS (DADSNBR, DAROLEID) VALUES (68, 3)
INTO ACCESS (DADSNBR, DAROLEID) VALUES (68, 4)
SELECT 1 FROM DUAL
Since there are some entries within the statement that are duplicates of those already in the database, the whole insert fails and none of the rows are inserted.
Is there a way to ignore the cases where the unique constraint fails, and just insert the ones that are unique, without having to split it up into individual INSERT statements?
Edit: I realised I probably don't want to do this anyway, but I'm still curious as to whether it's possible or not.
In Oracle, statements either succeed completely or fail completely (they are atomic). However, you can add clauses in certain cases to log exceptions instead of raising errors:
using BULK COLLECT - SAVE EXCEPTIONS, as demonstrated in this thread on askTom,
or using DBMS_ERRLOG (available since 10g I think).
The second method is all automatic, here's a demo (using 11gR2):
SQL> CREATE TABLE test (pk1 NUMBER,
2 pk2 NUMBER,
3 CONSTRAINT pk_test PRIMARY KEY (pk1, pk2));
Table created.
SQL> /* Statement fails because of duplicate */
SQL> INSERT into test (SELECT 1, 1 FROM dual CONNECT BY LEVEL <= 2);
ERROR at line 1:
ORA-00001: unique constraint (VNZ.PK_TEST) violated
SQL> BEGIN dbms_errlog.create_error_log('TEST'); END;
2 /
PL/SQL procedure successfully completed.
SQL> /* Statement succeeds and the error will be logged */
SQL> INSERT into test (SELECT 1, 1 FROM dual CONNECT BY LEVEL <= 2)
2 LOG ERRORS REJECT LIMIT UNLIMITED;
1 row(s) inserted.
SQL> select ORA_ERR_MESG$, pk1, pk2 from err$_test;
ORA_ERR_MESG$ PK1 PK2
--------------------------------------------------- --- ---
ORA-00001: unique constraint (VNZ.PK_TEST) violated 1 1
You can use the LOG ERROR clause with INSERT ALL (thanks #Alex Poole), but you have to add the clause after each table:
SQL> INSERT ALL
2 INTO test VALUES (1, 1) LOG ERRORS REJECT LIMIT UNLIMITED
3 INTO test VALUES (1, 1) LOG ERRORS REJECT LIMIT UNLIMITED
4 (SELECT * FROM dual);
0 row(s) inserted.
Use the MERGE statement to handle this situation:
merge into "ACCESS" a
using
(
select 68 as DADSNBR,1 as DAROLEID from dual union all
select 68,2 from dual union all
select 68,3 from dual union all
select 68,4 from dual
) t
on (t.DADSNBR = a.DADSNBR and t.DAROLEID = a.DAROLEID)
when not matched then
insert (DADSNBR, DAROLEID)
values (t.DADSNBR, t.DAROLEID);

Oracle unique constraint with where clause

I have an Oracle database table that I want to apply a unique constraint on. The issue is that I only want to apply the constraint if a column in that table is null,
ie. if a row does not have a deleted_date column, then apply the constraint, otherwise ignore it. This will allow for soft deleting records and ignoring constraints on them.
Any thoughts on how to do this?
Cheers,
Mark
Just create a multi column constraint - the column you want to be unique plus the deletion date. All not deleted rows will have a unique value and the deletion date null. All deleted rows will be unique because of the deletion date (assuming it is a time stamp and the resolution is good enough to separate all deletions). If deleted rows cannot be separated by the deletion date, one could think about creating a new column and adding it to the constraint to uniquify the deletion date - but this would be quite an inelegant solution.
And if the resolution is not good enough, then you can create a unique function based index.
An example:
SQL> create table t (id,col,deleted_date)
2 as
3 select 1, 99, null from dual union all
4 select 2, 99, date '2009-06-22' from dual
5 /
Tabel is aangemaakt.
SQL> alter table t add constraint t_pk primary key (id)
2 /
Tabel is gewijzigd.
SQL> alter table t add constraint t_uk1 unique (col,deleted_date)
2 /
Tabel is gewijzigd.
This is the solution described by Daniel. If there is ever a possibility that two rows are deleted at the exact same time (I'm using only the date part here), this solution is not good enough:
SQL> insert into t values (3, 99, date '2009-06-22')
2 /
insert into t values (3, 99, date '2009-06-22')
*
FOUT in regel 1:
.ORA-00001: unique constraint (RWK.T_UK1) violated
In that case use a unique function based index:
SQL> alter table t drop constraint t_uk1
2 /
Tabel is gewijzigd.
SQL> create unique index i1 on t (nvl2(deleted_date,null,col))
2 /
Index is aangemaakt.
SQL> insert into t values (3, 99, date '2009-06-22')
2 /
1 rij is aangemaakt.
Regards,
Rob.

Resources