oracle foreign key returns null - oracle

currently i am facing an oracle constraints issue.
After submiting an insert my foreign key constraint(s) won't fire. What it should do is giving two tables the same ID, but unfortunately only the one table with the primary Key is giving an ID. The column with the foreign key in the second table remains null.
For Instance: Insert into table t1 (t1_id,name, dpt) values (value1 (trigger with autoincrement for id), value2, value3); The same procedure is behind table 2, table 3 ... All constraints are written correctly
Table 1 (Emp)
ID Name Department
1 Joe HR
Table 2 (Projects)
ID Project EmpID
1 new (null) -> must be 1
Thank you in advanced.
Constraint: ALTER TABLE "PROJECTS" ADD CONSTRAINT "EMP_FK" FOREIGN KEY ("EMP_ID")
REFERENCES "EMP" ("EMP_ID") ON DELETE CASCADE ENABLE
Trigger: create or replace TRIGGER Projects_TRG BEFORE
INSERT ON Projects FOR EACH ROW BEGIN :NEW.Project_ID := Projects_SEQ.NEXTVAL;
END;
How do i manage to populate the parent id from the parent table into the child table?
Please note that I used different names in my application.

It appears that you've misunderstood the purpose of a foreign key constraint. A foreign key constraint does NOT automatically propagate constraint values from the parent table to the child table. The purpose of the constraint is to ensure that the values of the key column in the child table, when populated, have matching values in the key column of the parent table. Your application is responsible for ensuring that the key column on the child table is populated with the appropriate value. The constraint doesn't do that for you. It's also perfectly legitimate to have a NULL in the key column of the child table, assuming the the column on the child table doesn't have a NOT NULL constraint on it.

Related

How to assign two foreign keys in child table ORACLE SQL?

How can I inherit from two(or more) parent classes in ORACLE SQL? I've tried something like this:
ID(13),
OTHER_ID(9),
CONSTRAINT FK_ID FOREIGN
KEY(ID) REFERENCES TABLE_ONE(ID),
CONSTRAINT FK_OTHER_GROUP FOREIGN
KEY(OTHER_ID) REFERENCES TABLE_TWO(OTHER_ID)
I've read the documentation and the code I've found is this one:
INDEX (product_category, product_id),
INDEX (customer_id),
FOREIGN KEY (product_category, product_id)
REFERENCES product(category, id)
ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY (customer_id)
REFERENCES customer(id)
It doesn't quite work for me. Is there any special way to define these indexes? I haven't met them before. The first example had a problem that data types weren't specified. But I'd like someone to explain me how could I do it the second(oracle documentation) way.
This is how I understood the problem:
there are two tables, each having primary key constraint
in my example, those are t_emp and t_dept
there's also the third table whose columns are supposed to reference primary keys from previous two tables
those are fk_th_emp and fk_th_dep foreign key constraints
If that's so, here's how to do that:
SQL> create table t_emp
2 (empno number constraint pk_temp primary key,
3 ename varchar2(20)
4 );
Table created.
SQL> create table t_dept
2 (deptno number constraint pk_dept primary key,
3 dname varchar2(20)
4 );
Table created.
SQL> create table third
2 (id number constraint pk_third primary key,
3 other_id number,
4 --
5 constraint fk_th_emp foreign key (id) references t_emp (empno),
6 constraint fk_th_dep foreign key (other_id) references t_dept (deptno)
7 );
Table created.
SQL>

How to create two indexes for the same column that is both a primary and a foreign key?

From what I have been told and read online, I need to create an index for a foreign key even if this exact column already has an index as a primary key. But how to do that? If I simply use this
create index document_fk_i on document(id);
Won't it simply create a second identical index to the first one? (the first one was created automatically by Oracle)
You can't index the same column twice. If there's an index on document.id column because it is a primary key, then you don't (and can't) create another index which would be used for that column's "foreign key constraint" role.
Master table:
SQL> create table test_a (id number primary key);
Table created.
Detail table: ID is a primary key and Oracle will create an index:
SQL> create table test_b (id number primary key);
Table created.
Create a foreign key constraint from detail to master table:
SQL> alter table test_b add constraint fk_ba foreign key (id)
2 references test_a (id);
Table altered.
Try to create additional index on detail's ID column:
SQL> create index idxb on test_b (id);
create index idxb on test_b (id)
*
ERROR at line 1:
ORA-01408: such column list already indexed
SQL>

Tried to have recursive relation

I use oracle and I try to have a recursive relation
CREATE TABLE "EVENT"
(
"EVENT_ID" NUMBER(18) NOT NULL, //primary key
"NAME" VARCHAR(20) NULL,
"RELATED_EVENT_ID" NUMBER(18) NULL //foreign key
);
Event 1 parent is Event 2....
When I try to create this table, I get this error.
ALTER TABLE "EVENT"
ADD CONSTRAINT "FK_RELATED_EVENT_ID"
FOREIGN KEY ("RELATED_EVENT_ID") REFERENCES "EVENT" ("RELATED_EVENT_ID")
Error report -
SQL Error: ORA-02270: no matching unique or primary key for this column-list
02270. 00000 - "no matching unique or primary key for this column-list"
*Cause: A REFERENCES clause in a CREATE/ALTER TABLE statement
gives a column-list for which there is no matching unique or primary
key constraint in the referenced table.
*Action: Find the correct column names using the ALL_CONS_COLUMNS
catalog view
You have two problems:
There is no primary key constraint on this table.
The foreign key constraint you defined has RELATED_EVENT_ID referencing RELATED_EVENT_ID. I suspect that was just a typo.
Change your table definition to:
CREATE TABLE EVENT
(EVENT_ID NUMBER
NOT NULL
CONSTRAINT PK_EVENT
PRIMARY KEY
USING INDEX,
NAME VARCHAR2(20),
RELATED_EVENT_ID NUMBER);
Then add the foreign key constraint as
ALTER TABLE EVENT
ADD CONSTRAINT EVENT_FK1
FOREIGN KEY (RELATED_EVENT_ID) REFERENCES EVENT(EVENT_ID);
db<>fiddle here
EDIT
Note that the better way to handle this is to use a junction table, such as:
CREATE TABLE EVENT_EVENT
(EVENT_ID1 NUMBER
CONSTRAINT EVENT_EVENT_FK1
REFERENCES EVENT(EVENT_ID),
EVENT_ID2 NUMBER
CONSTRAINT EVENT_EVENT_FK2
REFERENCES EVENT(EVENT_ID),
CONSTRAINT PK_EVENT_EVENT
PRIMARY KEY (EVENT_ID1, EVENT_ID2)
USING INDEX);
Then you can drop the RELATED_EVENT_ID column from EVENT as you no longer need it.
According to oracle document :
Foreign key specifies that the values in the column must correspond to values in a
referenced primary key or unique key column or that they are NULL.
In your case, create primary key on column (EVENT_ID) and use it in reference clause as following:
ALTER TABLE "EVENT"
ADD CONSTRAINT "FK_RELATED_EVENT_ID"
FOREIGN KEY ("RELATED_EVENT_ID")
REFERENCES "EVENT" ("EVENT_ID") -- this
Now, use EVENT2's EVENT_ID as RELATED_EVENT_ID in EVENT1 record to make EVENT2 as parent of EVENT1.
Cheers!!

How to add composite primary keys?

I have a table with three columns, [Id,QTY,Date]. out of these three, two columns [id and date], should be set as primary keys, because I need to fetch the record one by one, from this table, into a reference.
the data to be inserted into this table is
101,10,NULL
101,20,201220
101,7,201440
102,5,null
102,8,201352
date is in yyyyww format
How do I define two columns as composite primary keys when they have null values, duplicates?
alter table abc add constraint pk primary key (ID, DATE);
if I try to alter the table the error appears
Error report:
SQL Error: ORA-01449: column contains NULL values; cannot alter to NOT NULL
01449. 00000 - "column contains NULL values; cannot alter to NOT NULL"
*Cause:
*Action:
Using table level constraint, you can use this query
alter table your_table add constraint pkc_Name primary key (column1, column2)
but first you need to declare the columns NOT NULL. All parts of a primary key need to be NOT NULL.
The column name of your table is ID and it is still null and non-unique, how is it possible. If it is primary key of other table try adding a surrogate key column for this table and make it primary key.
In case of composite primary key, it should have atleast one not null value(For each row) in the combination of columns. And the combination of column must be unique at all case.
For further details check, http://docs.oracle.com/cd/B10500_01/server.920/a96524/c22integ.htm
Correction - If composite primary key is made up of 3 columns, then no column (among 3) can hold NULL value. And the combination of those 3 columns must be unique.
E.g. (1,2,2)
(1,2,1)
(2,2,1)
(1,2,2) - not valid

Oracle Foreign Key Issues with Multi-Table Inserts and Blobs

We have a single table that we want to break up into a tree of tables based upon a particular source column. I wanted to try using a multi-column insert, but it seems that if I insert a blob into a sub table, I wind up with a foreign key constraint violation.
I don't think this violates the rules about multi-table inserts but I could be wrong...
I am hoping that someone could point me to some more in-depth resources around what is actually going on here, so that I can feel confident that whatever solution will work as part of a liquibase changeset on Oracle databases 9i -> 11g.
Hopefully Simplified Scenario
CREATE TABLE source (
pk NUMBER NOT NULL PRIMARY KEY,
type VARCHAR2(20) NOT NULL,
content VARCHAR2(20) NOT NULL
);
INSERT INTO source (pk,type,content) values (1,'two','n/a');
INSERT INTO source (pk,type,content) values (2,'one','Content');
CREATE TABLE dest (
pk NUMBER NOT NULL PRIMARY KEY,
type VARCHAR2(20) NOT NULL
);
CREATE TABLE dest_one (
pkfk NUMBER NOT NULL PRIMARY KEY,
data BLOB NOT NULL,
CONSTRAINT XFK1DEST_ONE FOREIGN KEY (pkfk) REFERENCES dest (pk)
);
CREATE TABLE dest_two (
pkfk NUMBER NOT NULL PRIMARY KEY,
CONSTRAINT XFK1DEST_TWO FOREIGN KEY (pkfk) REFERENCES dest (pk)
);
Source contains our original data. dest will be our parent table, with children dest_one and dest_two (which will contain information on things of type 'one' or 'two' respectively). Things of type one have content, but things of type two do not.
The Failed Attempt
INSERT ALL
WHEN 1=1 THEN INTO dest (pk,type) VALUES (pk,type)
WHEN type='one' THEN INTO dest_one (pkfk,data) VALUES (pk,content)
WHEN type='two' THEN INTO dest_two (pkfk) VALUES (pk)
SELECT pk,type,utl_raw.cast_to_raw(content) as content from source where type in ('one','two');
As previously mentioned, I wound up with a foreign key constraint violation here. To further illustrate that the blob was the issue I tried two seperate similar queries (below) realizing the one without the blob insert worked, but with the blob insert failed.
INSERT ALL
WHEN 1=1 THEN INTO dest (pk,type) VALUES (pk,type)
WHEN type='two' THEN INTO dest_two (pkfk) VALUES (pk)
SELECT pk,type,utl_raw.cast_to_raw(content) as content from source where type = 'two';
/* Successful */
INSERT ALL
WHEN 1=1 THEN INTO dest (pk,type) VALUES (pk,type)
WHEN type='one' THEN INTO dest_one (pkfk,data) VALUES (pk,content)
SELECT pk,type,utl_raw.cast_to_raw(content) as content from source where type = 'one';
/* ORA-02291: integrity constraint violated, no parent key */
Solution 1 - Traditional Inserts
INSERT INTO dest (pk,type) SELECT pk,type from source where type in ('one','two');
INSERT INTO dest_two (pkfk) SELECT pk from source where type = 'two';
INSERT INTO dest_one (pkfk,data) SELECT pk,utl_raw.cast_to_raw(content) from source where type = 'one';
One option I am considering is going back to multiple seperate insert statements, but unlike how I have stated them here, I'm concerned that I'll have to make sure I write my sub-table inserts to only attempt to insert those rows present in parent dest table... I need to do more research on how Liquibase handles multiple sql statements in the same changeset.
Solution 2 - Temporarily disabling foreign key constraints
ALTER TABLE dest_one DISABLE CONSTRAINT XFK1DEST_ONE;
INSERT ALL
WHEN 1=1 THEN INTO dest (pk,type) VALUES (pk,type)
WHEN type='one' THEN INTO dest_one (pkfk,data) VALUES (pk,content)
WHEN type='two' THEN INTO dest_two (pkfk) VALUES (pk)
SELECT pk,type,utl_raw.cast_to_raw(content) as content from source where type in ('one','two');
ALTER TABLE dest_one ENABLE CONSTRAINT XFK1DEST_ONE;
This is the solution I'm leaning toward. While disabling the foreign key on my blob table seems to make it work in my test environment (10g - 10.2.0.1.0), I'm not sure if I should also be disabling the foreign key on the non-blob table as well (due to how 9i, 11g, or other versions of 10g may behave). Any resources here too would be appreciated.
Thanks a bunch!
Another solution would be to defer the constraint evaluation until COMMIT. I suspect (but am not sure) that the multi-table insert is inserting rows in an order other than the one you expect and want. Recreate your constraints as follows:
ALTER TABLE DEST_ONE DROP CONSTRAINT XFK1DEST_ONE;
ALTER TABLE DEST_ONE
ADD CONSTRAINT XFK1DEST_ONE
FOREIGN KEY (pkfk) REFERENCES dest (pk)
INITIALLY DEFERRED DEFERRABLE;
ALTER TABLE DEST_TWO DROP CONSTRAINT XFK1DEST_TWO;
ALTER TABLE DEST_TWO
ADD CONSTRAINT XFK1DEST_TWO
FOREIGN KEY (pkfk) REFERENCES dest (pk)
INITIALLY DEFERRED DEFERRABLE;
This re-creates the constraints so that they can be deferred, and are deferred from the time they're created. Then try your original INSERT again.
Share and enjoy.

Resources