SQL Server Foreign Key cause cycles or multiple cascade paths - sql-server

I'm having problems adding a cascade delete onto a foreign key in SQL Server. Table A has three columns. Column 1 and 2 in Table A are foreign key look ups to the same column in Table B. I want a delete of a row in Table B to cascade a delete on a row on Table A based on these foreign keys.
The other column in Table A has a foreign key lookup to table C. If a row in table C is deleted then I want the corresponding cell to be set to null in Table A.
When I add in these constraints I am thrown the error:
Introducing FOREIGN KEY constraint 'FK_RDU_TODELIVERABLEUNITREF' on table 'RelatedDeliverableUnit' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
I am a little stuck with this, Oracle seems perfectly happy with this logic. I am adding in these constraints using Liquibase. I think the error is down to my logic and not syntax but for completeness here is the liquidbase script that manages the foreign keys:
<addForeignKeyConstraint constraintName="FK_RDU_FROMDELIVERABLEUNITREF" baseTableName="relatedDeliverableUnit"
baseColumnNames="FROMDELIVERABLEUNITREF" referencedTableName="DELIVERABLEUNIT" referencedColumnNames="DELIVERABLEUNITREF" onDelete="CASCADE"/>
<addForeignKeyConstraint constraintName="FK_RDU_TODELIVERABLEUNITREF" baseTableName="relatedDeliverableUnit"
baseColumnNames="TODELIVERABLEUNITREF" referencedTableName="DELIVERABLEUNIT" referencedColumnNames="DELIVERABLEUNITREF" onDelete="CASCADE"/>
<addForeignKeyConstraint constraintName="FK_RDU_RELATIONSHIPREF"
baseTableName="relatedDeliverableUnit" baseColumnNames="RELATIONSHIPREF" referencedTableName="RELATIONSHIPTYPES" referencedColumnNames="RELATIONSHIPREF" onDelete="SET NULL"/>
Thanks in advance for any help

I can't find corresponding documentation for later versions, but the SQL Server 2000 BOL addresses this issue:
The series of cascading referential actions triggered by a single DELETE or UPDATE must form a tree containing no circular references. No table can appear more than once in the list of all cascading referential actions that result from the DELETE or UPDATE. The tree of cascading referential actions must not have more than one path to any given table. Any branch of the tree is terminated when it encounters a table for which NO ACTION has been specified or is the default.
And later versions haven't changed this. You're falling foul of this:
The tree of cascading referential actions must not have more than one path to any given table
The only way I know of to accomplish this is to implement one of the cascades between B and A using an INSTEAD OF trigger, rather than using ON DELETE....
The relation between tables A and C shouldn't be impacted by any of this.
(2008 BOL)

Related

Trigger/Constraints for deleting table hierarchy

I have the following table structure which stores some results of my application. Each hierarchy level has a data row attached which again consists of multiple values. A data row is exclusively assigned to a single table of the hierarchy tables, not many in parallel. My goal is to delete the Parent including all hierarchy levels, the data and values.
My first attempt was to add ON DELETE CASCADE constraints everywhere but ON DELETE CASCADE does not work with a diamond structure. It results in:
Introducing FOREIGN KEY constraint 'FK_Data_Hierarchy2' on table 'Data' may cause cycles or cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other KEY constraints.
Then my second attempt was to remove the cascade constraint on the Data table and add a INSTEAD OF DELETE trigger to Hierarchy 1-3 which deletes the Data entries before the own rows. But also there the SQL Server complains that you cannot add such a trigger due to the ON DELETE CASCADE which is there for the hierarchy nesting.
Cannot create INSTEAD OF DELETE or INSTEAD OF UPDATE TRIGGER 'TR_Hierarchy1_Delete' on table 'dbo.Hierarchy'. This is because the table has a FOREIGN KEY with cascading DELETE or UPDATE.
My last plan would be to remove all ON DELETE CASCADE constraints and delete the whole tree manually in a trigger. But this is quite a challenge do it in an optimized fashion.
What is really the best solution for this job? Iterating over the rows using cursors? (possibly slow due to iteration)
Use combined joins to select the affected rows for every individual table? (possibly slow due to redundant joining the whole hierarchy)
Or does somebody know a trick how to delete over multiple tables using a result set?

Generate custom EF6 code first migration SQL after foreign key constraints

I'm adding custom SQL to an EF6 code first migration. The SQL adds delete triggers to various tables. It's generating correct syntax and getting output as expected.
But the location of the output is giving me trouble. Code first migrations put all the foreign key constraints at the bottom of the generated SQL. When creating the constraints for a join table (used in a many-to-many association), the ON DELETE CASCADE clause is added. All fine and dandy, except when I've added a delete trigger to one of the tables participating in that relationship -- cascade delete isn't allowed coming from a table with a delete trigger on it.
Ideally, I'd like to do one of two things -- either move my SQL to the bottom of the script (where I can yank the cascade deletes off the constraints after they're added) or somehow tell EF not to cascade delete certain particular join tables, while leaving the default behavior in place for the more common case where the cascade deletes are the correct thing to do.
Anyone have a clue as to how this can be done?
Thanks.

Can SQL Server tell you what paths it has found when it can't create a foreign key?

I'm trying to introduce a foreign key with ON DELETE SET NULL into a database with a complex schema.
The script I'm using has this command (names changed):
ALTER TABLE a
ADD CONSTRAINT FK_a_b
FOREIGN KEY (b_id)
REFERENCES b (b_id)
ON DELETE SET NULL;
When I run this script I get the following error message:
Introducing FOREIGN KEY constraint 'FK_a_b' on table 'b' may cause
cycles or multiple cascade paths.
I can't see what the multiple paths are, is there some way I can get SQL Server to list them?
You can check dependencies as outlined here:
https://msdn.microsoft.com/en-us/library/ms190624.aspx
When you use the T-SQL as shown, you get only one level, but if you use SSMS, it will cascade down multiple levels.
There's no built-in functionality just for that purpose. I suppose that with recursive CTE you could write a query on sys.foreign_keys and couple of other system views, that would list cascade paths.
But simplest solution is to do that with Database Diagrams. Start by adding the table that's not letting you add the constraint, then right click and select "Add Related Tables". Then select all the tables and add related tables again, and so on. To keep the diagram clean, in the process unselect or remove tables that you know are not part of the problem.
After you're done, you'll be able to see cycles/multi cascades: they will be chains of 1-N (direcion matters) or 1-1 relations starting and ending on the same table, or leading from one table to another through different paths.
You could use code similar to below to exlude tables that don't have any FK constraints with update/delete actions other than NO_ACTION (0). Building on that you could also exlude tables with only one FK constraint of this type.
select
object_name(parent_object_id),
*
from sys.foreign_keys fk
where 1=2
or delete_referential_action <> 0
or update_referential_action <> 0
I know it may be time-consuming especially for big databases, and you have to know your db well, but that's my best shot for now :).

How can we make foreign key among tables after inserting data in those tables?

I have created tables in sql server. And i have also inserted data/rows in that tables.
Now i want to make relationship among them means i want to create foreign key constraints among them, is it possible ?
Whenever i try to create relationship among table a problem is occured. "Saving changes is permitted, The changes you made required table to re-created and dropped"
Please suggest me what should i do to make relationship(foreign key) among them ?
My Child table design is this
this is my parent table:-
please now right what alter query i should write..?
You can try this link
"Error message when you try to save a table in SQL Server 2008: "Saving changes is not permitted"
Another solution is below.
I think the problem is because of a feature when using the GUI. If you have a look at this link it shows you how to work round it. It is a feature which prevents you from dropping and recreating the table which is what SSMS does in the background when you click ok.
The code provided by the previous posted is the best way to do this.
You could do this with a script like this:
alter table ChildTable
add constraint FK_ChildTable_ColumnName foreign key (ColumnName) references ParentTable(PrimaryKeyColumnName)
[Edit] If I read your description correctly the script would be:
alter table emp
add constraint FK_emp_salary foreign key(salary) references testing(roll)
You can only add foreign constraints that aren't violated by existing data. You may also have to add suitable indices first, although this depends on the DBMS. In any case, first make sure your existing data is compatible with the foreign keys you want to introduce. In other words, if you were to create the foreign key first, and then insert the data, you should not produce any foreign key violations.

Cascade Delete Use Case

I am pretty new to Business Analysis. I have to write requirements that show both (for now) cascade delete (for two tables) and the rest of the tables will delete explicitly.
I need some guidance for how to write the requirements for cascade deletion.
Delete child entities on parent
deletion.
Delete collection members if collection entity is deleted.
Actually it is hard to understand the task without context and also it smells like university/colledge homework (we had one very similar to this).
Use the ON DELETE CASCADE option to specify whether you want rows deleted in a child table when corresponding rows are deleted in the parent table. If you do not specify cascading deletes, the default behavior of the database server prevents you from deleting data in a table if other tables reference it.
If you specify this option, later when you delete a row in the parent table, the database server also deletes any rows associated with that row (foreign keys) in a child table. The principal advantage to the cascading-deletes feature is that it allows you to reduce the quantity of SQL statements you need to perform delete actions.
For example, the all_candy table contains the candy_num column as a primary key. The hard_candy table refers to the candy_num column as a foreign key. The following CREATE TABLE statement creates the hard_candy table with the cascading-delete option on the foreign key:
CREATE TABLE all_candy
(candy_num SERIAL PRIMARY KEY,
candy_maker CHAR(25));
CREATE TABLE hard_candy
(candy_num INT,
candy_flavor CHAR(20),
FOREIGN KEY (candy_num) REFERENCES all_candy
ON DELETE CASCADE)
Because ON DELETE CASCADE is specified for the dependent table, when a row of the all_candy table is deleted, the corresponding rows of the hard_candy table are also deleted. For information about syntax restrictions and locking implications when you delete rows from tables that have cascading deletes, see Considerations When Tables Have Cascading Deletes.
Source: http://publib.boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/com.ibm.sqls.doc/sqls292.htm
You don't write use cases for functionality - that is the reason why it is hard to properly answer your question - we don't know the actor who interacts with the system and of course we know nothing about the system, so we cannot tell you how to write description of their interactions.
You should write your use cases first and from them derive the functionality.

Resources