parent keys not found Oracle 10g - oracle

I have two tables :
SQL> desc SEGMENT
Name Null? Type
----------------------------------------- -------- ----------------------------
INDIP NOT NULL VARCHAR2(11)
NOMSEGMENT NOT NULL VARCHAR2(20)
ETAGE
SQL> desc POSTE
Name Null? Type
----------------------------------------- -------- ----------------------------
NPOSTE NOT NULL VARCHAR2(7)
NOMPOSTE NOT NULL VARCHAR2(20)
INDIP VARCHAR2(11)
AD VARCHAR2(3)
TYPEPOSTE VARCHAR2(9)
NSALLE VARCHAR2(7)
I want to add a constraint as the following :
ALTER TABLE "POSTE" ADD CONSTRAINT "FK_POSTE_SEGMENT" FOREIGN KEY ("INDIP") REFERENCES "SEGMENT" ("INDIP") ENABLE;
But I got this error message :
ERROR at line 1: ORA-02298: cannot validate (AIMAD.FK_POSTE_SEGMENT) -
parent keys not found
How can I solve this

You should check what POSTE table does not contain values in INDIP column what don't exist in INDIP column of SEGMENT table.
Like
SQL> create table t (x int primary key);
SQL> insert into t values(1);
SQL> create table t_c (x int);
SQL> insert into t_c values(1);
SQL> insert into t_c values(2);
SQL> commit;
SQL> alter table t_c add constraint t_c_x foreign key(x)
2 references t(x);
alter table t_c add constraint t_c_x foreign key(x)
*
ORA-02298: cannot validate (SCOTT.T_C_X) - parent key not found
SQL> select * from t_c where not exists (select *
2 from t where t.x = t_c.x);
X
-----------------------
2
Also Oracle provides the ability to create constraint in NOVALIDATE status, this prevents Oracle from checking data during contraint creation:
SQL> alter table t_c add constraint t_c_x foreign key(x)
2 references t(x) enable novalidate;
Table altered.
but this can have undesirable side effects because data in both tables are not consistent.

Related

Oracle - Foreign Key references different tables different schemas

I have problem with Enforcing Referential Integrity to a new table.
There are different tables in different schemas, each one has its primary key:
schema1.table1
schema2.table2
schema3.table3
I want to create a new table, which among other information and its primary id, has a column "reference_schema" and a column "reference_id".
I want the column "referencing id" to reference the id on the relevant table, that is of the "reference_schema"="schema1" to reference the primary key schema1.table1.id.
The primary keys on the 3 tables, aren't unique in a UNION.
I have tried synthesizing a primary key in a UNION ALL view, but Oracle does not enforce view constraints.
It is not the different schema that causes problems, but the fact that you can't create a foreign key constraint which would reference two (or more) different tables.
I mean, you can do it, using out-of-line constraint syntax, but that just won't work. Why? Because - if that value doesn't exist in all referenced tables, constraint will be violated.
create table new_table
(id number constraint pk_newtab primary key,
ref_schema varchar2(30),
ref_id number,
--
constraint fk_newtab_s1 foreign key (ref_id) references schema1.table1 (id),
constraint fk_newtab_s2 foreign key (ref_id) references schema2.table2 (id)
);
A simple example is Scott's sample schema (there is department number 10, but no employee has that EMPNO):
SQL> create table test
2 (id number,
3 constraint fk1 foreign key (id) references scott.dept (deptno),
4 constraint fk2 foreign key (id) references scott.emp (empno)
5 );
Table created.
SQL> insert into test (id) values (10);
insert into test (id) values (10)
*
ERROR at line 1:
ORA-02291: integrity constraint (SCOTT.FK2) violated - parent key not found
SQL>
So, what can you do? Use a trigger. Something like this:
SQL> create or replace trigger trg_test
2 before insert or update on test
3 for each row
4 declare
5 l_cnt number;
6 begin
7 select deptno into l_cnt
8 from dept
9 where deptno = :new.id;
10
11 exception
12 when no_data_found then
13 begin
14 select empno into l_cnt
15 from emp
16 where empno = :new.id;
17
18 exception
19 when no_data_found then
20 raise_application_error(-20000, 'Foreign key does not exist in any referenced table');
21 end;
22 end;
23 /
Trigger created.
Testing:
SQL> insert into test (id) values (10); --> this is ACCOUNTING
1 row created.
SQL> insert into test (id) values (7369); --> this is SMITH
1 row created.
SQL> insert into test (id) values (99); --> this doesn't exist in any table
insert into test (id) values (99)
*
ERROR at line 1:
ORA-20000: Foreign key does not exist in any referenced table
ORA-06512: at "SCOTT.TRG_TEST", line 17
ORA-04088: error during execution of trigger 'SCOTT.TRG_TEST'
SQL>
From Oracle 12, you can use virtual columns and put the constraints on the virtual column.
For example, if you have the tables:
CREATE TABLE table1 (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY
);
CREATE TABLE table2 (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY
);
CREATE TABLE table3 (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY
);
Then you can create your table as:
CREATE TABLE new_table(
id NUMBER
GENERATED ALWAYS AS IDENTITY
PRIMARY KEY,
reference_table VARCHAR2(30)
CHECK (reference_table IN ('table1', 'table2', 'table3')),
reference_id NUMBER
NOT NULL,
t1_id NUMBER
INVISIBLE
AS (
CASE reference_table WHEN 'table1' THEN reference_id END
)
REFERENCES table1(id),
t2_id NUMBER
INVISIBLE
AS (
CASE reference_table WHEN 'table2' THEN reference_id END
)
REFERENCES table2(id),
t3_id NUMBER
INVISIBLE
AS (
CASE reference_table WHEN 'table3' THEN reference_id END
)
REFERENCES table3(id)
);
Note: If you want to change from different tables in the same schema to the same table in different schemas then just update the foreign key constraint to point to the correct location.
db<>fiddle here

How to change column identify from sequence to GENERATED ALWAYS with data

as my title, I want to change my identity column by sequence to GENERATED ALWAYS.
For ex, I have a table like this:
CREATE SEQUENCE DPT.Deposit_SEQ
START WITH 1
INCREMENT BY 10
NOCACHE
NOCYCLE;
CREATE TABLE DPT.TEST(
Id NUMBER(10)DEFAULT DPT.Deposit_SEQ.nextval NOT NULL
,Code VARCHAR2(20),
CONSTRAINT PK_TEST PRIMARY KEY (ID)
);
Insert into DPT.TEST (ID, CODE) values (1,'ABC');
COMMIT;
Now, I want to change from sequence to GENERATED ALWAYS like this:
Id NUMBER(10) GENERATED ALWAYS AS IDENTITY START WITH 6
INCREMENT BY 10
NOCACHE
NOCYCLE;
I tried by create one more column and drop old column but failed. How can I do that?
Thanks!
"But failed" is not an Oracle error and is difficult to debug.
Anyway, it works for me:
Create table and a sequence, insert some rows:
SQL> CREATE SEQUENCE Deposit_SEQ START WITH 1 INCREMENT BY 10 NOCACHE NOCYCLE;
Sequence created.
SQL> CREATE TABLE TEST
2 (
3 Id NUMBER (10) DEFAULT Deposit_SEQ.NEXTVAL NOT NULL,
4 Code VARCHAR2 (20),
5 CONSTRAINT PK_TEST PRIMARY KEY (ID)
6 );
Table created.
SQL>
SQL> INSERT INTO TEST (ID, CODE)
2 VALUES (1, 'ABC');
1 row created.
SQL> INSERT INTO TEST (ID, CODE)
2 VALUES (3, 'DEF');
1 row created.
SQL> SELECT * FROM test;
ID CODE
---------- --------------------
1 ABC
3 DEF
Drop current primary key column (ID) and add a new, identity column:
SQL> ALTER TABLE test
2 DROP COLUMN id;
Table altered.
SQL> ALTER TABLE test
2 ADD id NUMBER GENERATED ALWAYS AS IDENTITY START WITH 6;
Table altered.
SQL> SELECT * FROM test;
CODE ID
-------------------- ----------
ABC 6
DEF 7
SQL> ALTER TABLE test ADD CONSTRAINT pk_test PRIMARY KEY (id);
Table altered.
SQL>
As you can see, no problem.

How add autoincrement to existing table in Oracle

Is there any ways to add autoincrement to primary key in already existing table in Oracle 12c. May be with ALTER TABLE function or smth, I mean without triggers and sequences.
As far as I can tell, you can not "modify" existing primary key column into a "real" identity column.
If you want to do that, you'll have to drop the current primary key column and then alter table and add a new identity column.
Workaround is to use a sequence (or a trigger), but - you said you don't want to do that. Anyway, if you decide to use it:
SQL> create table test
2 (id number constraint pk_test primary key,
3 name varchar2(10));
Table created.
SQL> insert into test values (1, 'LF');
1 row created.
SQL> create sequence seq_test start with 2;
Sequence created.
SQL> alter table test modify id default seq_test.nextval;
Table altered.
SQL> insert into test (name) values ('BF');
1 row created.
SQL> select * from test;
ID NAME
---------- ----------
1 LF
2 BF
SQL>
Or, with dropping current primary key column (note that it won't work easy if there are foreign keys involved):
SQL> alter table test drop column id;
Table altered.
SQL> alter table test add id number generated always as identity;
Table altered.
SQL> select * From test;
NAME ID
---------- ----------
LF 1
BF 2
SQL> insert into test (name) values ('test');
1 row created.
SQL> select * From test;
NAME ID
---------- ----------
LF 1
BF 2
test 3
SQL>

How to delete the primary key from without using constraint name

CREATE TABLE Persons (
ID int PRIMARY KEY,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Age int
);
How to remove the primary key as there is no constraint defined?
"How to remove PK as there is no constraint defined?"
Actually it's every bit as simple as you might hope:
SQL> create table t23 (id number primary key);
Table created.
SQL> select constraint_name, constraint_type
2 from user_constraints
3 where table_name = 'T23'
4 /
CONSTRAINT_NAME C
------------------------------ -
SYS_C0034419 P
SQL> alter table t23 drop primary key;
Table altered.
SQL> select constraint_name, constraint_type
2 from user_constraints
3 where table_name = 'T23'
4 /
no rows selected
SQL>
run this to get constraint name :
SELECT *
FROM user_cons_columns
WHERE table_name = Persons;
then run
ALTER TABLE Persons
DROP CONSTRAINT <pk constraint>;
Don't think you can do it in 1 SQL command,without knowing the constraint name, but you can know the constraint name as in this case it would be defined by system. Something which starts with SYS.....
Alternatively you can use a PLSQL block to achieve the same.
See the example below for your case.
CREATE TABLE Persons (
ID int PRIMARY KEY,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Age int
);
Find constraint name
select CONSTRAINT_NAME
From USER_CONSTRAINTS
where table_name='PERSONS'
AND CONSTRAINT_TYPE='P';
OUTPUT:= SYS_C0012152
Drop Constraint
ALTER TABLE PERSONS
DROP CONSTRAINT SYS_C0012152;
Note: The constraint name SYS_C0012152 is not enclosed in single quotes.
PLSQL Block to do the same
declare
sql_stmt varchar2(255);
cons_name varchar2(30);
begin
select CONSTRAINT_NAME
into cons_name
From USER_CONSTRAINTS
where table_name='PERSONS'
AND CONSTRAINT_TYPE='P';
sql_stmt:=' ALTER TABLE PERSONS
DROP CONSTRAINT '||cons_name;
dbms_output.put_line(sql_stmt);
execute immediate sql_stmt;
end;

Unique constraint on multiple columns

I am using an oracle table and have created a unique constraint over four columns. Can these columns within the constraint have NULL in them?
you can have NULLs in your columns unless the columns are specified NOT NULL. You will be able to store only one instance of NULLs however (no two sets of same columns will be allowed unless all columns are NULL) :
SQL> CREATE TABLE t (id1 NUMBER, id2 NUMBER);
Table created
SQL> ALTER TABLE t ADD CONSTRAINT u_t UNIQUE (id1, id2);
Table altered
SQL> INSERT INTO t VALUES (1, NULL);
1 row inserted
SQL> INSERT INTO t VALUES (1, NULL);
INSERT INTO t VALUES (1, NULL)
ORA-00001: unique constraint (VNZ.U_T) violated
SQL> /* you can insert two sets of NULL, NULL however */
SQL> INSERT INTO t VALUES (NULL, NULL);
1 row inserted
SQL> INSERT INTO t VALUES (NULL, NULL);
1 row inserted
Yes, Oracle allows UNIQUE constraints to contain columns with NULL contents, but PRIMARY KEY constraints cannot contain columns containing NULL values. (Edited: was "... nullable columns...", but my example below shows that not to be true. Columns in a PK can be defined as nullable, but cannot contain NULL.)
You cannot have a UNIQUE constraint and a PRIMARY KEY constraint with the same columns.
SQL> create table stest (col1 integer not null, col2 integer null);
Table created.
SQL> alter table stest add constraint stest_uq unique (col1, col2);
Table altered.
SQL> insert into stest values (1, 3);
1 row created.
SQL> insert into stest values (1, null);
1 row created.
SQL> insert into stest values (1, null);
insert into stest values (1, null)
*
ERROR at line 1:
ORA-00001: unique constraint (SUSAN_INT.STEST_UQ) violated
SQL> insert into stest values (2, null);
1 row created.
SQL> commit;
Commit complete.
SQL> select * from stest;
COL1 COL2
---------- ----------
1 3
1
2
SQL> alter table stest add constraint stest_pk PRIMARY KEY (col1, col2);
alter table stest add constraint stest_pk PRIMARY KEY (col1, col2)
*
ERROR at line 1:
ORA-01449: column contains NULL values; cannot alter to NOT NULL
SQL> truncate table stest;
Table truncated.
SQL> alter table stest add constraint stest_pk PRIMARY KEY (col1, col2);
alter table stest add constraint stest_pk PRIMARY KEY (col1, col2)
*
ERROR at line 1:
ORA-02261: such unique or primary key already exists in the table
SQL> alter table stest drop constraint stest_uq;
Table altered.
SQL> alter table stest add constraint stest_pk PRIMARY KEY (col1, col2);
Table altered.
Two nulls are considered not equal in Oracle, so these columns can have nulls in them.

Resources