How to delete rows with bi-directional dependencies? - oracle

I'm using Oracle 10g Express and trying to delete records from tables with bi-directional constraints. I'm trying to un-thread hundreds of tables and dependencies generated via Hibernate (which can't be changed at this point), but here is an extremely simplified example:
create table TableA (id number(19,0) not null, ..., rTableA_id number(19,0), primary key (id));
create table TableB (id number(19,0) not null, ..., rTableB_id number(19,0), primary key (id));
alter table TableA add constraint FKA1 foreign key (rTableA_id) references TableB;
alter table TableB add constraint FKB1 foreign key (rTableB_id) references TableA;
Trying to delete entries from either table returns the following:
EDIT: This happens in my case with foreign keys prefixed with SYS_
ORA-02292: integrity constraint (XXX.FKA1) violated - child record found
I've also tried to disable constraints but all attempts are futile:
ORA-02297: cannot disable constraint (XXX.FKA1) - dependencies exist

I have to wonder how your data got in this state in the first place, since your foreign keys are not null. If both tables were empty to start with, you'd never be able to insert a row into either table.
Ignoring that for a moment, recreating your scenario, I have no problem disabling the constraints:
CREATE TABLE tablea(id NUMBER(19, 0) NOT NULL,
rtablea_id NUMBER(19, 0) NOT NULL,
PRIMARY KEY(id))
/
CREATE TABLE tableb(id NUMBER(19, 0) NOT NULL,
rtableb_id NUMBER(19, 0) NOT NULL,
PRIMARY KEY(id))
/
INSERT INTO tablea
VALUES (1, 2)
/
INSERT INTO tableb
VALUES (2, 1)
/
ALTER TABLE tablea ADD CONSTRAINT fka1
FOREIGN KEY (rtablea_id)
REFERENCES tableb
/
ALTER TABLE tableb ADD CONSTRAINT fkb1
FOREIGN KEY (rtableb_id)
REFERENCES tablea
/
ALTER TABLE tablea MODIFY CONSTRAINT fka1 DISABLE
/
ALTER TABLE tableb MODIFY CONSTRAINT fkb1 DISABLE
/
delete tablea
/
delete tableb
/
commit
/
Result:
Table created.
Table created.
1 row created.
1 row created.
Table altered.
Table altered.
Table altered.
Table altered.
1 row deleted.
1 row deleted.
Commit complete.
I'm not sure how you'd get a ORA-02297 error when attempting to disable a foreign key. That error is typically seen when disabling a primary or unique key that a foreign key relies upon.
I suspect what you really want to do is set the constraints to initially deferred. This would allow you to perform inserts and deletes to each table individually, as long as the corresponding row was updated or deleted before the transaction is commited:
CREATE TABLE tablea(id NUMBER(19, 0) NOT NULL,
rtablea_id NUMBER(19, 0) NOT NULL,
PRIMARY KEY(id))
/
CREATE TABLE tableb(id NUMBER(19, 0) NOT NULL,
rtableb_id NUMBER(19, 0) NOT NULL,
PRIMARY KEY(id))
/
ALTER TABLE tablea ADD CONSTRAINT fka1
FOREIGN KEY (rtablea_id)
REFERENCES tableb
INITIALLY DEFERRED
/
ALTER TABLE tableb ADD CONSTRAINT fkb1
FOREIGN KEY (rtableb_id)
REFERENCES tablea
INITIALLY DEFERRED
/
INSERT INTO tablea
VALUES (1, 2)
/
INSERT INTO tableb
VALUES (2, 1)
/
INSERT INTO tableb
VALUES (3, 1)
/
COMMIT
/
DELETE tableb
WHERE id = 2
/
UPDATE tablea
SET rtablea_id = 3
WHERE id = 1
/
COMMIT
/
Result:
Table created.
Table created.
Table altered.
Table altered.
1 row created.
1 row created.
1 row created.
Commit complete.
1 row deleted.
1 row updated.
Commit complete.

Are you sure that Hibernate cannot be told to create the constraints as deferrable? If the DDL doesn't use the DEFERRABLE keyword, the constraints will be non-deferrable by default. That is going to mean that you won't be able to delete the data. If you have a schema with circular references, you would always want to declare your foreign key constraints to be deferrable.
You could drop the constraints, delete the data, and then re-create the constraints (either using Hibernate's DDL or by adding the INITIALLY DEFERRED DEFERRABLE clause at the end). But that would be a major pain if you delete data from either table with any sort of frequency. You'll also tend to have problems inserting new data if the new A row wants to reference the new B row you're creating.

I was unable to add INITIALLY DEFERRED because the databases (as well as the underlying Hibernate scripts) already exist. For new systems, this would have been an option, however, there are many tools (of which I only know several) which rely on the Database in its current form and I was too afraid of any unintended side-effects by adding this parameter to 700 tables.
Therefore, I used the following solution:
alter table TableA MODIFY CONSTRAINT FKA1 DISABLE;
alter table TableB MODIFY CONSTRAINT FKB1 DISABLE;
delete from TableA where id = 1;
delete from TableB where id = 2;
alter table TableA MODIFY CONSTRAINT FKA1 ENABLE;
alter table TableB MODIFY CONSTRAINT FKB1 ENABLE;

Related

Why do some users and not others get ORA-01400: cannot insert NULL into primary key

EDIT: I have replaced the generic SQL with the actual SQL.
I know how to fix it. I am just wondering why it worked on some developer machines and not others.
CREATE TABLE OUTPUTDEFNACTIVATION ("OUTPUTDEFNACTIVATIONID" NUMBER, "OUTPUTDEFNTYPE" NUMBER(1,0) NOT NULL, "OUTPUTDEFNID" NUMBER NOT NULL, "PROJECTVIEWID" NUMBER, "SYSTEMUSERID" NUMBER, "VISIBLE" NUMBER(3,0));
ALTER TABLE OUTPUTDEFNACTIVATION ADD CONSTRAINT OUTPUTDEFNACTIVATION_P PRIMARY KEY (OUTPUTDEFNACTIVATIONID) ENABLE;
ALTER TABLE OUTPUTDEFNACTIVATION ADD CONSTRAINT OUTPUTDEFNACTIVATION_PROJECT FOREIGN KEY (PROJECTVIEWID) REFERENCES PROJECTVIEW (PROJECTVIEWID) ON DELETE CASCADE ENABLE;
ALTER TABLE OUTPUTDEFNACTIVATION ADD CONSTRAINT OUTPUTDEFNACTIVATION_USER FOREIGN KEY (SYSTEMUSERID) REFERENCES SYSTEMUSER (SYSTEMUSERID) ON DELETE CASCADE ENABLE;
ALTER TABLE OUTPUTDEFNACTIVATION ADD CONSTRAINT UNIQUE_OUTPUTDEFNACTIVATION UNIQUE (OUTPUTDEFNTYPE, OUTPUTDEFNID, SYSTEMUSERID, PROJECTVIEWID);
CREATE SEQUENCE "OUTPUTDEFNACTIVATION_SEQ" MINVALUE 1 MAXVALUE 1.00000000000000E+27 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE;
INSERT INTO OUTPUTDEFNACTIVATION (OUTPUTDEFNTYPE, OUTPUTDEFNID, SYSTEMUSERID, PROJECTVIEWID, VISIBLE)
SELECT 0, KPIDEFNID, SYSTEMUSERID, PROJECTVIEWID, VISIBLE FROM KPIDEFN, SYSTEMUSER, PROJECTVIEW, DUAL WHERE ACTIVE = 1 AND SYSTEMUSERID <> 1 AND STATUSID IN (1,4);
My fix is
INSERT INTO OUTPUTDEFNACTIVATION (OUTPUTDEFNACTIVATIONID, OUTPUTDEFNTYPE, OUTPUTDEFNID, SYSTEMUSERID, PROJECTVIEWID, VISIBLE)
SELECT OUTPUTDEFNACTIVATION_SEQ.NEXTVAL, 0, KPIDEFNID, SYSTEMUSERID, PROJECTVIEWID, VISIBLE FROM KPIDEFN, SYSTEMUSER, PROJECTVIEW, DUAL WHERE ACTIVE = 1 AND SYSTEMUSERID <> 1 AND STATUSID IN (1,4);
But why wasn't it necessary on all developer machines? They all have their own schema, but my script created this table for them all.
ORA-01400: cannot insert NULL into ("DEVF22FMT"."OUTPUTDEFNACTIVATION"."OUTPUTDEFNACTIVATIONID")
The same table behaves the same way, so - if all of them (developers) used the same INSERT statement, connected to the same database (user), they'd get the same result - either success or a failure.
However, if they have their own schemas, then it depends on the way they created target tables.
Behaviour you described could be result of
identity column (12c onwards)
database trigger
which then "automatically", in the background, populate that NOT NULL column.

How do I create a foreign key on two columns that are under the primary key constraint?

CREATE TABLE "RESEARCH_DEP"."RESEARCH_TV_COMPANY"
( "CID" NUMBER(38,0) NOT NULL ENABLE,
"SOURCE_ID" NUMBER(2,0),
CONSTRAINT "PK_RESEARCH_TV_COMPANY_1" PRIMARY KEY ("CID", "SOURCE_ID")
USING INDEX (CREATE UNIQUE INDEX "RESEARCH_DEP"."IDX_TV_COMPANY_CID_SOURCE_ID" ON "RESEARCH_DEP"."RESEARCH_TV_COMPANY" ("CID", "SOURCE_ID")
CREATE TABLE "RESEARCH_DEP"."RESEARCH_METRICS_PHARMA_AUD"
( "ID" NUMBER GENERATED ALWAYS AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE NOT NULL ENABLE,
"SOURCE_ID" NUMBER(2,0) NOT NULL ENABLE,
"MEDIA_COMPANY_ID" NUMBER(*,0) NOT NULL ENABLE
)
NEED
ALTER TABLE RESEARCH_DEP.RESEARCH_METRICS_PHARMA_AUD
ADD CONSTRAINT fk_METRICS_PHARMA_AUD_TV_COMPANY_ID
FOREIGN KEY (MEDIA_COMPANY_ID,SOURCE_ID) REFERENCES RESEARCH_DEP.RESEARCH_TV_COMPANY(CID,SOURCE_ID);
ORA-02298: parent keys not found
DO I NEED TO CREATE A COMPOSITION COLUMN: CID,SOURCE_ID?
OR
create sequence of values two column oracle CID,SOURCE_ID ?
Your code is more or less OK:
SQL> create table research_tv_company
2 (cid number,
3 source_id number,
4 --
5 constraint pk_rtc primary key (cid, source_id)
6 );
Table created.
SQL> create table research_metrics_pharma_aud
2 (id number,
3 source_id number,
4 media_company_id number
5 );
Table created.
SQL> alter table research_metrics_pharma_aud
2 add constraint fk_rmpa_rtc
3 foreign key (media_company_id, source_id)
4 references research_tv_company (cid, source_id);
Table altered.
SQL>
Note that I
removed double quotes
removed NOT NULL for primary key columns (they can't be NULL anyway)
don't have any indexes created so Oracle will - along with table creation - create a primary key constraint AND unique index to support it
as I'm on 11gXE and it doesn't support identity columns, I removed that
from the second table; I'd have to enforce it via a trigger. You don't have to do anything about it, just saying (so that you wouldn't wonder where did it go?)
Error you got:
ORA-02298: parent keys not found
means that there are combinations of (media_company_id, source_id) in the second table that do not exist as pairs of (cid, source_id) in the first table. To illustrate it:
Drop the foreign key constraint first (otherwise, I wouldn't be able to do that):
SQL> alter table research_metrics_pharma_aud drop constraint fk_rmpa_rtc;
Table altered.
Insert a row into the first (master) table:
SQL> insert into research_tv_company (cid, source_id) values (1, 1);
1 row created.
Insert two rows into the second (detail) table; the first combination is valid, the second is not as (2, 2) don't exist in research_tv_company:
SQL> insert into research_metrics_pharma_aud (id, source_id, media_company_id) values (1, 1, 1);
1 row created.
SQL> insert into research_metrics_pharma_aud (id, source_id, media_company_id) values (2, 2, 2);
1 row created.
SQL>
If we try to create a foreign key constraint:
SQL> alter table research_metrics_pharma_aud
2 add constraint fk_rmpa_rtc
3 foreign key (media_company_id, source_id)
4 references research_tv_company (cid, source_id);
add constraint fk_rmpa_rtc
*
ERROR at line 2:
ORA-02298: cannot validate (SCOTT.FK_RMPA_RTC) - parent keys not found
SQL>
See? The same error you got.
What can you do?
insert missing primary key values into the master table, or
delete detail rows that violate the constraint, or
create the constraint, but instruct Oracle not to check whether existing rows are valid or not:
SQL> alter table research_metrics_pharma_aud
2 add constraint fk_rmpa_rtc
3 foreign key (media_company_id, source_id)
4 references research_tv_company (cid, source_id)
5 enable novalidate;
Table altered.
SQL>
The enable novalidate means that foreign key constraint will be enabled for any new or modified rows, but existing rows won't be checked. If that option suits you, use it. However, I believe that one of the first two option is better, with the first one - adding missing primary keys - being the best.

In oracle on delete set null is not working

I have created two tables:
Create Table Dept
(Department_id number Constraint Depart_id_pk Primary Key
,Department_name varchar2(20));
Create table Emp
(Emp_id number Constraint Empl_id_pk Primary Key
,First_name varchar2(10)
,salary number
,Department_id number
,Constraint depart_id_fk Foreign Key (department_id)
References Dept (Department_id) on delete set null);
Then I have inserted some records in dept and Emp table. But when I try to drop dept table, instead of setting null in Emp.department_id column it shows error like this:
SQL> Drop Table Dept;
Drop Table Dept
*
ERROR at line 1:
ORA-02449: unique/primary keys in table referenced by foreign keys
The foreign key's clause say "on delete set null". Delete is a DML operation, and had you attempted to delete rows from the dept table, the corresponding emp rows would have been updated with a null dept_id.
But this isn't the case - you tried to drop the entire table, a DDL operation. This isn't allowed, because you'd be leaving behind constraints on the emp table that reference a table that no longer exists. If you want to drop these constraints too, you can use a cascade constraints clause:
DROP TABLE dept CASCADE CONSTRAINTS

Oracle foreign key constraints - check constraint syntax?

I have a child table in oracle that has two foreign key columns, relating to two different parent tables. I want to create a constraint that says the child must have at least one of those parents - e.g.
ALTER TABLE table_name
ADD CONSTRAINT constraint_name
FOREIGN KEY (column1)
REFERENCES parent_table (column1)
OR
FOREIGN KEY (column2)
REFERENCES parent_table_2 (column1)
This won't work with a foreign key constraint because that can only relate to one parent table - is it possible to do this with a check constraint instead?
Foreign key constraints ensure the referential integrity, not mandatory values.
I think you have to have to separate FK contraints and additional check constraint like this:
alter table table_name
add constraint c_check_cols
check(column1 is not null or column2 is not null);
You can do it with constraints:
ALTER TABLE table_name
ADD CONSTRAINT constraint_name_1
FOREIGN KEY (column1)
REFERENCES parent_table (column1);
ALTER TABLE table_name
ADD CONSTRAINT constraint_name_2
FOREIGN KEY (column2)
REFERENCES parent_table_2 (column1);
ALTER TABLE table_name
ADD CONSTRAINT constraint_name_3
check (COALESCE(column1, column2) IS NOT NULL);
Of course for column1 and column2 column you must permit NULL values.

"SET FOREIGN_KEY_CHECKS = 0;" Oracle Equivalent

Is there some equivalent to the Mysql specific instruction that disable the check of the foreign keys constraints ?
SET FOREIGN_KEY_CHECKS = 0;
There is no command in Oracle that will disable all constraints at once.
However it seems you want to disable constraints in the context of dropping tables. In that case you can use the CASCADE CONSTRAINTS clause to drop the referencing constraints from other tables along with the table being dropped.
Here's an example:
SQL> CREATE TABLE t1 (ID NUMBER PRIMARY KEY);
Table created
SQL> CREATE TABLE t2 (ID NUMBER REFERENCES t1);
Table created
SQL> INSERT INTO t1 VALUES (1);
1 row inserted
SQL> INSERT INTO t2 VALUES (1);
1 row inserted
SQL> -- this fails because of the foreign key
SQL> DROP TABLE t1;
ORA-02449: unique/primary keys in table referenced by foreign keys
SQL> DROP TABLE t1 CASCADE CONSTRAINTS;
Table dropped
SET FOREIGN_KEY_CHECKS = 0; is session based. In an Oracle context I can only imagine you needing to do this when you have circular references.
You've commented that this is what you want to do:
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE table1;
DROP TABLE table2;
SET FOREIGN_KEY_CHECKS = 1;
I'm assuming that this means that TABLE1 has a foreign key referencing TABLE2 and TABLE2 has a foreign key referencing TABLE1.
If this is the case then Moudiz's answer is correct. You want to disable the foreign keys before dropping the table:
alter table table1 disable constraint <constraint_name>;
alter table table2 disable constraint <constraint_name>;
drop table table1;
drop table table2;
There's no point disabling all foreign keys for the length of the session, you're only interested in two of them, both of which will be dropped with the table.
You don't want to ever disable all foreign keys.
The only other context I can think of this in is if you want to insert something into your circular reference, in which case you would declare the constraint as DEFERRABLE. This means that the constraint check is done at the end of the transaction rather than on DML being performed, see the documentation.
If your references aren't circular then simply drop the tables in the other order.
IF Your asking for a query to disable a foreign key then try this :
ALTER TABLE mytable
disable CONSTRAINT fk_mytable;

Resources