Do I need to drop a foreign key on one table to delete a row on another using oracle? - oracle

I have two tables
Parent table
(account_number varchar(15) not null,
branch_name varchar(50) not null,
balance number not null,
primary key(account_number));
Child table
account_number varchar(15) not null,
foreign key(account_number) references parent table(account_number));
I am trying this:
DELETE FROM parent table
WHERE balances > 1000;
I am deleting accounts by balances on the parent but I get an error message about the child relationship.
My assumption is a DELETE CASCADE has to be added to the foreign key in the child table. All the documentation shows how to alter the table when the constraint is named. I do not have that situation. Is there a way to do it, or do I have to specify the cascade in the delete statement I am writing?

Every constraint in Oracle has a name. If a name isn't specified when the constraint is created, Oracle will autogenerate a name for the constraint. If you don't know what the name of a constraint is, try running a SQL statement that violates the constraint and reading the constraint name from the error message:
SQL> delete from parent where account_number = 1234;
delete from parent where account_number = 1234
*
ERROR at line 1:
ORA-02292: integrity constraint (LUKE.SYS_C007357) violated - child record
found
In this case the name of the constraint is SYS_C007357.
If that doesn't work, you can query the data dictionary view user_constraints:
SQL> select constraint_name from user_constraints where table_name = 'CHILD' and constraint_type = 'R';
CONSTRAINT_NAME
------------------------------
SYS_C007357
As far as I can tell, you can't modify a foreign key constraint to enable ON DELETE CASCADE. Instead you must drop the constraint and recreate it.
I don't believe you can apply the CASCADE option to a DELETE statement either, but you can delete the child rows before deleting from the parent:
DELETE FROM child
WHERE account_number IN (SELECT account_number FROM parent WHERE balance > 1000);
DELETE FROM parent
WHERE balance > 1000;
However, I don't know how many other tables you have with foreign key constraints referencing your parent table, nor in how many places you are deleting from the parent table, so I can't say how much work it would be to use this approach.

yes you can set DELETE CASCADE
see more info here FOREIGN KEYS WITH CASCADE DELETE
CREATE TABLE table_name
(
column1 datatype null/not null,
column2 datatype null/not null,
...
CONSTRAINT fk_column
FOREIGN KEY (column1, column2, ... column_n)
REFERENCES parent_table (column1, column2, ... column_n)
ON DELETE CASCADE
);
for example
CREATE TABLE supplier
( supplier_id numeric(10) not null,
supplier_name varchar2(50) not null,
contact_name varchar2(50),
CONSTRAINT supplier_pk PRIMARY KEY (supplier_id)
);
CREATE TABLE products
( product_id numeric(10) not null,
supplier_id numeric(10) not null,
CONSTRAINT fk_supplier
FOREIGN KEY (supplier_id)
REFERENCES supplier(supplier_id)
ON DELETE CASCADE
);

Related

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.

Oracle: ORA-01408: such column list already indexed

I have created a table:
CREATE TABLE SCHEMA_NAME.TABLE_NAME
(
ID VARCHAR2(100) PRIMARY KEY NOT NULL,
A_ID VARCHAR2(100) NOT NULL,
B_ID VARCHAR2(100),
C_ID INTEGER,
CONSTRAINT FK_C_NOTE FOREIGN KEY (C_ID) REFERENCES C(ID),
CONSTRAINT FK_A_NOTE FOREIGN KEY (A_ID) REFERENCES A(ID),
CONSTRAINT FK_B_NOTE FOREIGN KEY (B_ID) REFERENCES B(ID)
);
And I have tried to apply the following indexes:
CREATE INDEX IDX_FK_A_TABLE_NAME on SCHEMA_NAME.TABLE_NAME(A_ID) tablespace TS_SCHEMA_NAME_DATA;
CREATE INDEX IDX_FK_C_TABLE_NAME on SCHEMA_NAME.TABLE_NAME(C_ID) tablespace TS_SCHEMA_NAME_DATA; --Fails
CREATE INDEX IDX_FK_B_TABLE_NAME on SCHEMA_NAME.TABLE_NAME (B_ID) tablespace TS_SCHEMA_NAME_DATA; --Fails
But when I try to create the last two indexes I get:
ORA-01408: such column list already indexed
Why is this? Are these indexes created automatically?
If I try:
SELECT INDEX_NAME FROM ALL_INDEXES WHERE TABLE_NAME = 'NOTE';
I get:
INDEX_NAME
----------
IDX_FK_A_TABLE_NAME
SYS_C0044692561
Double check you indexed columns by querying ALL_IND_COLUMN (or DBA_IND_COLUMNS if you have acess). It will show you what table columns are indexed by which index.
SELECT c.index_owner, c.index_name, c.table_owner, c.table_name, c.column_name, c.column_position
FROM all_ind_columns c
WHERE c.table_owner = 'SCHEMA_NAME'
AND c.table_name = 'NOTE'
ORDER BY c.index_owner, c.index_name, c.column_position;
On a site note, When you are creating your indexes you're not prefixing them with a schema owner (CREATE INDEX SCHEMA.IDX_FK_A_TABLE_NAME ...). That means they're being created in your current schema. On the other hand, it's probably not related to the error you are facing.

Employee/History - Part of composite key as foreign key

I've got 2 entities:
1) EMPLOYEES (Parent)
CREATE TABLE EMPLOYEES (
employee_id NUMBER (3) NOT NULL,
first_name VARCHAR (20) NOT NULL,
last_name VARCHAR (20) NOT NULL,
job_title VARCHAR (20) NOT NULL,
employee_type VARCHAR (1) NOT NULL,
salary NUMBER (5),
hourly_pay NUMBER (5,2),
bonus_pay NUMBER (5,2),
CONSTRAINT employee_pk PRIMARY KEY(employee_id));
2) EMPLOYEE_HISTORY (Child)
CREATE TABLE EMPLOYEE_HISTORY (
start_date DATE NOT NULL,
employee_id NUMBER (3) NOT NULL,
end_date DATE,
job_title VARCHAR (10) NOT NULL,
hourly_rate NUMBER (5,2) NOT NULL,
CONSTRAINT employee_history_pk PRIMARY KEY(start_date, employee_id));
I'm trying to create:
ALTER TABLE employee_history
ADD CONSTRAINT employee_history_fk
FOREIGN KEY (employee_id)
REFERENCES employee_history(employee_id);
When I do this, I get an error
ORA-02270: no matching unique or primary key for this column-list
My guess is that I cannot create the constraint on just employee_id because I have a composite key in my child table. I understand when an employee gets put into the database, the parent table is filled out and the "start date" should be filled out along with everything else. However, I do not understand how this would work if I had start_date in my parent table as well. I would be able to create my constraint, yes, but how will I be able to keep a record of changes in start_date if my start_date was inputted at the time of when the employee was entered into the database.I thought about using job_title as a primary key instead of start_date because it's present in both tables, but what happens when an employee gets promoted and demoted again? Won't a duplicate value constraint come up when the same employee_id and job_title is getting inserted?
Your references clause needs to reference the parent table. Not the child table
ALTER TABLE employee_history
ADD CONSTRAINT employee_history_fk
FOREIGN KEY (employee_id)
REFERENCES employee(employee_id); -- employee not employee_history
The SQL you posted is trying to create a self-referential foreign key where employee_history is both the parent and the child. That doesn't make sense in this case.

reference a compound key in Oracle

I want to add a foreign key which reference the column in itself
FOREIGN KEY ACCREDITATION_BODY_ID NOT NULL REFERENCES
ACCREDITATION_BODY_LOOK_UP(ACCREDITATION_BODY_ID),
and the SQL in the table is:
CREATE TABLE "COURSE_ACCREDITED"
("COURSE_ID" VARCHAR2(50) NOT NULL ENABLE,
"ACCREDITATION_BODY_ID" VARCHAR2(50) NOT NULL ENABLE,
"DATE_OBTAINED" VARCHAR2(50),
PRIMARY KEY ("COURSE_ID", "ACCREDITATION_BODY_ID", "DATE_OBTAINED") ENABLE)
When I add this foreign key, it appears ORA-02270: no matching unique or primary key for this column-list
What is the problem?
Does ACCREDITATION_BODY_LOOK_UP have primary key (or unique key)?
select constraint_name, constraint_type
from user_constraints
where table_name = 'ACCREDITATION_BODY_LOOK_UP'
and constraint_type in ('P', 'U');
If yes, what are its columns? You need to reference all those columns in the same order when you add a foreign key to a dependent table.
select column_name, position
from user_cons_columns
where table_name = 'ACCREDITATION_BODY_LOOK_UP'
and constraint_name = '<< constraint from previous query >>';
If no, then you need to create a primary key on that table before you can reference it in a foreign key.
alter table ACCREDITATION_BODY_LOOK_UP
add constraint ACCR_BODY_LKUP_PK primary key (ACCREDITATION_BODY_ID);
This means that the child table has values which are not found in the parent table.
You just need to delete these orphaned values or define the foreign key with "novalidate" which skips checking the integrity between the child and parent tables.
CORRECTION: THIS ADDRESS A DIFFERENT PK/FK ERROR
ORA-02270 is because you're trying to create a foreign key and the key is not referencing a primary key or column with a unique constraint.

how to modify a constraint in sql plus?

I have created a table as follows:
create table emp( emp_id number(5) primary key
, emp_name varchar(20) not null
, dob date );
After the table has been created how would I change the constraint not null to unique or any other constraint in SQL*Plus?
You don't change a constraint from one type to another. You can add a unique constraint to the table
ALTER TABLE emp
ADD ( COSTRAINT uk_emp_name UNIQUE( emp_name ) );
That is independent of whether emp_name is allowed to have NULL values.
Just use ALTER TABLE command. For details look here: http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_3001.htm#i2103817
We cant be able to modify the already added constraint. Just we have to drop the constraint and add the new one with the same name, but add it with the necessary changes.
ALTER TABLE table_name drop constraint contraint_name;
alter table tablename add constraint containt_name CHECK (column_name IN (changes in the contraint)) ENABLE;

Resources