Create two foreign key constraints with on update/delete cascade - sql

Example of database (SQL Server):
Table A
-colA (PK, int)
Table B
-ColB (FK, int) --> points to Table X
Table C
-ColAC (PK, FK, int not null) --> points to Table A
-ColBC (PK, FK, int not null) --> points to Table B
Table C's primary key is both ColAC and ColBC. Each column has foreign key that points to a different table. I need to have ON UPDATE/DELETE CASCADE constraints on both foreign keys for Table C. So when either Table A or B has changes then it is cascaded in Table C.
Table A and B are already in use. I can create Table C with only either one of the constraints but not both, this will return an error message. How do I create both FK constraints?
Example of SQL:
CREATE TABLE Table_C (
ColAC INT NOT NULL,
ColBC INT NOT NULL,
PRIMARY KEY (
ColAC,
ColBC
)
)
GO
ALTER TABLE Table_C WITH CHECK ADD FOREIGN KEY (ColAC)
REFERENCES Table_A (ColA)
ON UPDATE CASCADE
ON DELETE CASCADE
GO
--The second constraint will always fail (does not matter which one is first).
ALTER TABLE Table_C WITH CHECK ADD FOREIGN KEY (ColBC)
REFERENCES Table_B (ColB)
ON UPDATE CASCADE
ON DELETE CASCADE
GO
Error message:
Introducing FOREIGN KEY constraint .... on table 'Table_C' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint or index. See previous errors.

You can go for two different tables, instead of single TableC
Table C1
-ColAC (PK, FK, int not null) --> points to Table A
Table C2
-ColBC (PK, FK, int not null) --> points to Table B
Now, you can have UNION ALL between these two tables
CREATE VIEW vw_TableC
AS
SELECT ColAC, 'TableA' as parent ... FROM TableC1
UNION ALL
SELECT ColBC, 'TableB' as parent ... FROM TableC2

Related

oracle sql - on delete cascade in both directions

I have table A and table B, where the primary key of table B references the primary key of table A. If i use on delete cascade on table B how can i ensure that rows of table A are deleted when i delete a row in table B?
Edit:
Merging is unfortunately not the solution to my problem.
In my database i have three tables that are relevant for this situation.
This is what it looks like:
CREATE TABLE TABLE_A
(
TABLE_A_ID INTEGER NOT NULL,
...
PRIMARY KEY(TABLE_A_ID)
);
CREATE TABLE TABLE_B
(
TABLE_B_ID INTEGER REFERENCES TABLE_A(TABLE_A_ID) ON DELETE CASCADE,
...
PRIMARY KEY(TABLE_B_ID)
);
CREATE TABLE TABLE_C
(
TABLE_C_ID INTEGER REFERENCES TABLE_A(TABLE_A_ID) ON DELETE CASCADE,
...
PRIMARY KEY(TABLE_C_ID)
);
Although it is possible to create rows in A on its own i dont want any rows that are only in A.
Now if I delete a row in B, I want the row in A with the same ID deleted too. I dont want any ID that is only in A, or only not in A.

SQL best solution for the delete operation on multiple relationships

I would like to have a clarification on deleting the multiple relationship
I have a schema that has a table 'A' and other tables of schema, that refer to 'A' with the role (Cascade) on delete operation.
There are also tables which refer to 'A' and which also have other references to other tables of 'A', but in this case the elimination must have a null value.
CREATE TABLE A
(A_ID INTEGER PK
...
)
CREATE TABLE B
(B_ID INTEGER PK
A_ID INTEGER NOT NULL
...
FOREIGN KEY A_ID REFERENCES A(A_ID) ON DELETE CASCADE
)
CREATE TABLE C
(C_ID INTEGER PK
A_ID INTEGER NOT NULL
B_ID INTEGER
...
FOREIGN KEY A_ID REFERENCES A(A_ID) ON DELETE CASCADE
FOREIGN KEY B_ID REFERENCES B(B_ID) ON DELETE SET NULL
)
These multiple relationships cause me a problem on the role delete operation.
I would have two options:
The first, and take on the role cascade all relationship with 'A', but that means I have to create a function that when I have to delete values of table 'A', the other value reference with this table delete from the bottom up. In the future I might forget to add a new table.
The second solution and create a table of connection to their reporting obligations have null values:
CREATE TABLE C
(C_ID INTEGER PK
A_ID INTEGER NOT NULL
...
FOREIGN KEY A_ID REFERENCES A(A_ID) ON DELETE CASCADE
)
CREATE TABLE C_B
(C_ID INTEGER PK
B_ID INTEGER PK
...
FOREIGN KEY C_ID REFERENCES C(C_ID) ON DELETE CASCADE
FOREIGN KEY B_ID REFERENCES B(B_ID) ON DELETE CASCADE
)
It involves the creation of several new bridging tables.
There is a different solution to this case?
I currently use Apache Derby and JPA for persistence

SQL: composite primary key, constraint on cascade

I have 3 tables: A, B, C.
The table A contains the attributes: a (primary key)
The table B contains the attributes: a, c (both of them compose a composite primary key)
The table C contains the attributes: c (primary key)
How should I set a constraint to remove the elements of B on cascade, when I remove an entry in A? (using Oracle DBMS).
I have tried this:
ALTER TABLE A ADD CONSTRAINT constraint FOREIGN KEY (a) REFERENCES B (a) ON DELETE CASCADE
But next error is thrown:
ORA-02270: no matching unique or primary key for this column-list
Thanks
Edited:
I´ve added two foreign keys to the table B:
ALTER TABLE B ADD CONSTRAINT FOREIGN KEY (a) REFERENCES A (a) ON DELETE CASCADE
ALTER TABLE B ADD CONSTRAINT FOREIGN KEY (c) REFERENCES C (c) ON DELETE CASCADE
Then, I will remove elements in table B, and the entries in A and C are also removed.
To meet this requirement:
Then, I will remove elements in table B, and the entries in A and C are also removed.
You need to make the B table a parent table for tables A and C by a adding foreign key constraint, that references B table to A and C tables.
Note that the number of referencing columns have to match the number of referenced columns:
create table A(
tab_id number primary key
);
create table B(
col1 number,
col2 number,
constraint PK_Key primary key(col1, col2)
);
create table C(
tab_id number primary key
);
alter table A add ( col1 number
, col2 number
, constraint fk_AB foreign key(col1, col2)
references B(col1, col2) on delete cascade);
alter table C add ( col1 number
, col2 number
, constraint fk_CB foreign key(col1, col2)
references B(col1, col2) on delete cascade);
This is a bit of a guess, but I am assuming table B is a child of of both A and C (perhaps B is a bridging (or cross-reference) table between A and C, where A and C share a many to many relationship).
Table A \*---1 Table B 1---\* Table C (* = many, 1 = one)
I also notice that the FK you are introducing in an identifying FK (by virtue of B(a) being a part of B's primary key).
That makes Table A the parent in this relationship, and B the child. In my experience, any FKs need to be added to the child side of the relationship (in this case, table B).
I'm no Oracle expert, but does this not make more sense?...
ALTER TABLE B ADD CONSTRAINT constraint FOREIGN KEY (a) REFERENCES A (a) ON DELETE CASCADE
This should remove all B rows referring to the PK of any A rows you choose to remove. BUT, I'm not an Oracle expert, so take only at face value until someone with Oracle smarts can confirm (or bomb) my explanation.

Foreign Key for either-or column?

Is it possible to have a foreign key that requires either column A or column B to have a value, but not both. And the foreign key for column A matches Table 1 and the foreign key for column B matches Table 2?
A check constraint can handle this. If this is SQL Server, something like this will work:
create table A (Id int not null primary key)
go
create table B (Id int not null primary key)
go
create table C (Id int not null primary key, A_Id int null, B_Id int null)
go
alter table C add constraint FK_C_A
foreign key (A_Id) references A (Id)
go
alter table C add constraint FK_C_B
foreign key (B_Id) references B (Id)
go
alter table C add constraint CK_C_OneIsNotNull
check (A_Id is not null or B_Id is not null)
go
alter table C add constraint CK_C_OneIsNull
check (A_Id is null or B_Id is null)
go
It depends on which database you're working with. If you want a table Foo that has FK relationships to Table1 and to Table2 but only one at a time, then you'll need to set up either some sort of trigger (my links assume SQL Server, but the ideas's the same) or Constraint to enforce your rule that only one column have a value.
it is not necessary that a column have values in it at that time of applying foreign key,but the column name would be same and the data types as well.

Check if data exists in another table on insert?

Table A
(
Table_A_ID int
)
Table B
(
Table_B_ID int
Value int
)
Say I want to insert data into Table B, where 'Value' would be the same as a Table_A_ID.
How would I make a constraint or check that the data actually exists in the table on insertion?
You probably need to enforce data integrity not only on INSERT into Table B, but also on UPDATE and DELETE in both tables.
Anyway options are:
FOREIGN KEY CONSTRAINT on Table B
TRIGGERs on both tables
As a last resort if for some reason 1 and 2 is not an option STORED PROCEDUREs for all insert, delete update operations for both tables
The preferred way to go in most cases is FOREIGN KEY CONSTRAINT.
Yap, I agree with #peterm.
Cause, if your both Table_A_ID and Table_B_Id are primary keys for both tables, then you don't even need two tables to store the value. Since, your two tables are seems to be on 'one-to-one' relationship. It's one of the database integrity issues.
I think you didn't do proper normalisation for this database.
Just suggesting a good idea!
I found this example which demonstrates how to setup a foreign key constraint.
Create employee table
CREATE TABLE employee (
id smallint(5) unsigned NOT NULL,
firstname varchar(30),
lastname varchar(30),
birthdate date,
PRIMARY KEY (id),
KEY idx_lastname (lastname)
) ENGINE=InnoDB;
Create borrowed table
CREATE TABLE borrowed (
ref int(10) unsigned NOT NULL auto_increment,
employeeid smallint(5) unsigned NOT NULL,
book varchar(50),
PRIMARY KEY (ref)
) ENGINE=InnoDB;
Add a constraint to borrowed table
ALTER TABLE borrowed
ADD CONSTRAINT FK_borrowed
FOREIGN KEY (employeeid) REFERENCES employee(id)
ON UPDATE CASCADE
ON DELETE CASCADE;
NOTE: This tells MySQL that we want to alter the borrowed table by adding a constraint called ‘FK_borrowed’. The employeeid column will reference the id column in the employee table – in other words, an employee must exist before they can borrow a book.
The final two lines are perhaps the most interesting. They state that if an employee ID is updated or an employee is deleted, the changes should be applied to the borrowed table.
NOTE: See the above URL for more details, this is just an excerpt from that article!
Create a foreign key constraint on the column 'Value' on table B that references the 'Table_A_ID' column.
Doing this will only allow values that exist in table A to be added into the 'Value' field of table B.
To accomplish this you first need to make Table_A_ID column the primary key for table A, or it at least has to have some sort of unique constraint applied to it to be a foreign key candidate.
BEGIN TRANSACTION -- REMOVE TRANSACTION AND ROLLBACK AFTER DONE TESTING
--PUT A PRIMARY KEY ON TABLE A
CREATE TABLE A
( Table_A_ID int CONSTRAINT PK_A_Table_A_ID PRIMARY KEY)
--ON VALUE ADD A FOREIGN KEY CONSTRAINT THAT REFERENCEs TABLE A
CREATE TABLE B
( Table_B_ID int,
[Value] int CONSTRAINT FK_B_Value_A REFERENCES A(Table_A_ID)
)
-- TEST VALID INSERT
INSERT A (Table_A_ID) VALUES (1)
INSERT B (Table_B_ID, [Value]) VALUES (1,1)
--NOT ALLOW TO INSERT A VALUE THAT DOES NOT EXIST IN A
--THIS WILL THROW A FOREIGN KEY CONSTRAINT ERROR
INSERT B (Table_B_ID, [Value]) VALUES (1,2) -- 2 DNE in table A
ROLLBACK
Note: there is no magic to 'FK_B_Value_A' or 'PK_A_Table_A_ID' it simply a naming convention and be called anything. The syntax on the foreign key and primary key lines work like this:
column-definition CONSTRAINT give-the-constraint-a-name REFERENCES table-name ( table-column )
column-definition CONSTRAINT give-the-constraint-a-name PRIMARY KEY