How to DELETE without ON DELETE CASCADE (conflict REFERENCE constraint) - sql-server

I have a gigantic legacy database with a table that has multiple foreign keys pointing to one other table and with not a single cascade in sight, similar to sample tables below:
create table Users (
Id int primary key identity,
Name varchar(max)
)
create table Products (
Id int primary key identity,
Name varchar(max),
CreatedBy int foreign key references Users(Id),
UpdatedBy int foreign key references Users(Id)
)
insert into Users values('Bar')
insert into Users values('Baz')
insert into Products values('Foo', 1, 2)
I need to be able to to delete some of the old data, but it of course throws reference exceptions:
delete from Users where Name='Bar'
The DELETE statement conflicted with the REFERENCE constraint "FK__Products__Create__1AD3FDA4". The conflict occurred in database "Foo", table "dbo.Products", column 'CreatedBy'.
Due to the sheer complexity of the database I can't predelete all of the references, so I'm trying to add temporary foreign keys programmatically with cascades set to resolve them. However, for this particular table that has multiple foreign keys to one other table, this results in cycles or multiple cascade paths on the second UpdatedBy alter:
alter table Products add foreign key (CreatedBy) references Users(Id) on delete cascade
alter table Products add foreign key (UpdatedBy) references Users(Id) on delete cascade
Introducing FOREIGN KEY constraint 'FK__Products__Update__1DB06A4F' on table 'Products' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
How can I make delete from Users where work while maintaining referential integrity, either by somehow getting around multiple cascade path issues or otherwise?

Personally I would not do this (I would pre-delete all the referenced data and manually check the integrity). See: Can foreign key constraints be temporarily disabled using T-SQL?
Quote:
-- disable all constraints
EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"
Delete your data once the constraints are disabled, but remember to turn them back on again afterwards!
-- enable all constraints
EXEC sp_msforeachtable #command1="print '?'", #command2="ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"
Also note that the stored procedure sp_msforeachtable is undocumented and may disappear in future releases of SQL Server.
If you'd rather not blanket-disable constraints (perhaps you have a list of the tables that apply) then simply disable them as you can see in the code above.
ALTER TABLE [Products] NOCHECK CONSTRAINT ALL
DELETE FROM [Users] where Name='Bar'
ALTER TABLE [Products] WITH CHECK CHECK CONSTRAINT ALL
All credit goes to kristof's answer. Please up vote!

Related

In the FK of the two tables, error to cycles or multiple cascade paths

enter image description here
The three tables have a FK relationship.
Post.PostBy is NOT NULL, Post.Category_id is Nullable.
An error has occurred.
Introducing FOREIGN KEY constraint 'FK_Post_Category' on table 'Post' 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.
ALTER TABLE [Category] ADD CONSTRAINT [FK_Category_CreatedBy] FOREIGN KEY ([CreatedBy])
REFERENCES [Account]([_id])
ON DELETE CASCADE
ALTER TABLE [Post] ADD CONSTRAINT [FK_Post_PostBy] FOREIGN KEY ([PostBy])
REFERENCES [Account]([_id])
ON DELETE CASCADE
ALTER TABLE [Post] ADD CONSTRAINT [FK_Post_Category_id] FOREIGN KEY ([Category_id])
REFERENCES [Category]([_id])
ON DELETE SET NULL
I don't understand.
PostBy is NOT NULL, so when the referenced row is deleted, we want it to be deleted along with it.
Category_id is NULLABLE, so if the reference row is deleted, set a NULL value.
Category and Post refer to Account, but I think it should work because they have different Account values.

Is there a way to turn off foreign key constraints at database level?

We need to use existing sql to create a bunch of tables and this sql includes ALTER TABLE statements to add in foreign keys. When we run this block of SQL, however, errors are thrown because tables needed for the foreign keys haven't been created yet (they are later on in the block of SQL).
Is there a way to turn off foreign key constraints at database level? (versus at table level) We just need to create all of the tables and foreign keys and then turn it back on.
Thanks!
To disable foreign key constraints when you want to truncate a table:
Use FOREIGN_KEY_CHECKS
SET FOREIGN_KEY_CHECKS=0;
and remember to enable it when you’re done:
SET FOREIGN_KEY_CHECKS=1;
Or you can use DISABLE KEYS:
ALTER TABLE table_name DISABLE KEYS;
Again, remember to enable if thereafter:
ALTER TABLE table_name ENABLE KEYS;
Note that DISABLE KEYS does not work on InnoDB tables as it works properly for MyISAM.
Use ON DELETE SET NULL
If you don’t want to turn key checking on and off, you can permanently modify it to ON DELETE SET NULL:
--Delete the current foreign key first:
ALTER TABLE table_name1 DROP FOREIGN KEY fk_name1;
ALTER TABLE table_name2 DROP FOREIGN KEY fk_name2;
--Then add the foreign key constraints back
ALTER TABLE table_name1
ADD FOREIGN KEY (table2_id)
REFERENCES table2(id)
ON DELETE SET NULL;
ALTER TABLE tablename2
ADD FOREIGN KEY (table1_id)
REFERENCES table1(id)
ON DELETE SET NULL;

SQL Server error: introducing foreign key constraint on table may cause cycles or multiple cascade paths

I have two tables, User and Data. For audit purposes, I have two columns added in the Datatable:AddedByandLastModifiedBy`.
Both columns reference the User table and its UserId column. I have a On delete set null constraint set on both the foreign keys. SQL Server does not let me create the table Data and throws the error:
Introducing FOREIGN KEY constraint 'FK__Data__LastModifi__0A9D95DB' on table 'Data' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
These are the SQL scripts:
CREATE TABLE [User]
(
UserId int PRIMARY KEY IDENTITY(1,1),
Name varchar(100) not null
)
CREATE TABLE [Data]
(
Id int PRIMARY KEY IDENTITY(1,1),
A int,
B varchar(10),
AddedBy int
FOREIGN KEY REFERENCES [User](UserId)
ON DELETE SET NULL,
LastModifiedBy int
FOREIGN KEY REFERENCES [User](UserId)
ON DELETE SET NULL
)
Removing the ON DELETE constraint solves the problem, but the question why can't I have two ON DELETE SET NULL conditions?
why can't I have two ON DELETE SET NULL conditions?
Because that would cause multiple cascade paths, and SQL Server simply doesn't support that.
There's an outstanding feedback request for this and to allow cascading in parent-child relationships here.
As a workaround you can either make one of the relationships ON DELETE NO ACTION, or use an INSTEAD OF DELETE trigger on USER that handles the cascading behavior.

Update even though using constraints

I'm trying to update a value (small spelling error) in the SQL Server 2014 database.
I do like this:
update t_Table set funID = 'References' where funID = 'Referencies'
When doing this I get the error
The UPDATE statement conflicted with the FOREIGN KEY constraint "FK_t_Table_Language_t_Table". The conflict occurred in database "db", table "dbo.t_Table".
If updating the foreign key, I get a similar error.
Is there any way to update all values at the same time?
I have a vague memory of someone showing a way to do this in management studio but I do not recall how.
Enable update cascade on the foreign key
ALTER TABLE t_Table_Language DROP CONSTRAINT FK_t_Table_Language_t_Table
ALTER TABLE t_Table_Language ADD CONSTRAINT FK_t_Table_Language_t_Table
FOREIGN KEY (funID) REFERENCES t_Table(funID)
ON UPDATE CASCADE
EDIT:
Or the other way around, i'm not sure which table has the foreing key
ALTER TABLE t_Table DROP CONSTRAINT FK_t_Table_Language_t_Table
ALTER TABLE t_Table ADD CONSTRAINT FK_t_Table_Language_t_Table
FOREIGN KEY (funID) REFERENCES t_Table_Language(funID)
ON UPDATE CASCADE
Then do the update on the referenced table (the master table).
UPDATE t_Table_Language
SET funID = 'References'
WHERE funID = 'Referencies'

Adding constraint conflicts with itself, even though it doesn't exist yet

I'm adding delete cascading to a Table. The Clone table has a column DeviceID that is a foreign key to the Device table's DeviceID column. So the SQL script drops the original FK constraint, and attempts to add the new one:
IF EXISTS
(
SELECT *
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE CONSTRAINT_NAME = 'FK_Clone_Device'
)
BEGIN
ALTER TABLE Clone
DROP CONSTRAINT FK_Clone_Device
END
IF NOT EXISTS
(
SELECT *
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE CONSTRAINT_NAME = 'FK_Clone_Device_Cascade'
)
BEGIN
ALTER TABLE Clone
ADD CONSTRAINT FK_Clone_Device_Cascade
FOREIGN KEY (DeviceID) REFERENCES Device(DeviceID) ON DELETE CASCADE
END
When I run this script, I get the following error:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_Clone_Device_Cascade". The conflict occurred in database "DevelopmentDB", table "dbo.Device", column 'DeviceID'.
Maybe I'm misunderstanding the error message, but it sounds like it's conflicting with itself. I'm confused that it happened on the Device table though.
There is an index in the Clone table on DeviceID. Would that matter?
This is on SQL SERVER R2 (Azure)
Sounds like you currently have data in the table that would violate the FK you are trying to create. One way to test this is to add "WITH (NOCHECK)" to the ALTER TABLE statement and see if it lets you create the constraint.
If it does let you create the constraint with NOCHECK, you can either leave it that way and the constraint will only be used to test future inserts/updates, or you can investigate your data to fix the FK violations.
So your example would be:
ALTER TABLE Clone WITH NOCHECK
ADD CONSTRAINT FK_Clone_Device_Cascade
FOREIGN KEY (DeviceID) REFERENCES Device(DeviceID) ON DELETE CASCADE

Resources