Temporarily disable all foreign key constraints - sql-server

I am running an SSIS package which will replace data for a few tables from FlatFiles to existing tables in a database.
My package will truncate the tables and then insert the new data. When I run my SSIS package, I get an exception because of the foreign keys.
Can I disable the constraints, run my import, then re-enable them?

To disable foreign key constraints:
DECLARE #sql nvarchar(max) = N'';
;WITH x AS
(
SELECT DISTINCT obj =
QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.'
+ QUOTENAME(OBJECT_NAME(parent_object_id))
FROM sys.foreign_keys
)
SELECT #sql += N'ALTER TABLE ' + obj + N' NOCHECK CONSTRAINT ALL;
' FROM x;
EXEC sys.sp_executesql #sql;
To re-enable:
DECLARE #sql nvarchar(max) = N'';
;WITH x AS
(
SELECT DISTINCT obj =
QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.'
+ QUOTENAME(OBJECT_NAME(parent_object_id))
FROM sys.foreign_keys
)
SELECT #sql += N'ALTER TABLE ' + obj + N' WITH CHECK CHECK CONSTRAINT ALL;
' FROM x;
EXEC sys.sp_executesql #sql;
However, you will not be able to truncate the tables, you will have to delete from them in the right order. If you need to truncate them, you need to drop the constraints entirely, and re-create them. This is simple to do if your foreign key constraints are all simple, single-column constraints, but definitely more complex if there are multiple columns involved.
Here is something you can try. In order to make this a part of your SSIS package you'll need a place to store the FK definitions while the SSIS package runs (you won't be able to do this all in one script). So in some utility database, create a table:
CREATE TABLE dbo.PostCommand(cmd nvarchar(max));
Then in your database, you can have a stored procedure that does this:
DELETE other_database.dbo.PostCommand;
DECLARE #sql nvarchar(max) = N'';
SELECT #sql += N'ALTER TABLE '
+ QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(fk.parent_object_id))
+ ' ADD CONSTRAINT ' + fk.name + ' FOREIGN KEY ('
+ STUFF((SELECT ',' + c.name
FROM sys.columns AS c
INNER JOIN sys.foreign_key_columns AS fkc
ON fkc.parent_column_id = c.column_id
AND fkc.parent_object_id = c.[object_id]
WHERE fkc.constraint_object_id = fk.[object_id]
ORDER BY fkc.constraint_column_id
FOR XML PATH(''),
TYPE).value(N'./text()[1]', 'nvarchar(max)'), 1, 1, N'')
+ ') REFERENCES ' +
QUOTENAME(OBJECT_SCHEMA_NAME(fk.referenced_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(fk.referenced_object_id))
+ '(' +
STUFF((SELECT ',' + c.name
FROM sys.columns AS c
INNER JOIN sys.foreign_key_columns AS fkc
ON fkc.referenced_column_id = c.column_id
AND fkc.referenced_object_id = c.[object_id]
WHERE fkc.constraint_object_id = fk.[object_id]
ORDER BY fkc.constraint_column_id
FOR XML PATH(''),
TYPE).value(N'./text()[1]', N'nvarchar(max)'), 1, 1, N'') + ');
' FROM sys.foreign_keys AS fk
WHERE OBJECTPROPERTY(parent_object_id, 'IsMsShipped') = 0;
INSERT other_database.dbo.PostCommand(cmd) SELECT #sql;
IF ##ROWCOUNT = 1
BEGIN
SET #sql = N'';
SELECT #sql += N'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(fk.parent_object_id))
+ ' DROP CONSTRAINT ' + fk.name + ';
' FROM sys.foreign_keys AS fk;
EXEC sys.sp_executesql #sql;
END
Now when your SSIS package is finished, it should call a different stored procedure, which does:
DECLARE #sql nvarchar(max);
SELECT #sql = cmd FROM other_database.dbo.PostCommand;
EXEC sys.sp_executesql #sql;
If you're doing all of this just for the sake of being able to truncate instead of delete, I suggest just taking the hit and running a delete. Maybe use bulk-logged recovery model to minimize the impact of the log. In general I don't see how this solution will be all that much faster than just using a delete in the right order.
In 2014 I published a more elaborate post about this here:
Drop and Re-Create All Foreign Key Constraints in SQL Server

Use the built-in sp_msforeachtable stored procedure.
To disable all constraints:
EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT ALL";
To enable all constraints:
EXEC sp_msforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL";
To drop all the tables:
EXEC sp_msforeachtable "DROP TABLE ?";

A good reference is given at : http://msdn.microsoft.com/en-us/magazine/cc163442.aspx
under the section "Disabling All Foreign Keys"
Inspired from it, an approach can be made by creating a temporary table and inserting the constraints in that table, and then dropping the constraints and then reapplying them from that temporary table. Enough said here is what i am talking about
SET NOCOUNT ON
DECLARE #temptable TABLE(
Id INT PRIMARY KEY IDENTITY(1, 1),
FKConstraintName VARCHAR(255),
FKConstraintTableSchema VARCHAR(255),
FKConstraintTableName VARCHAR(255),
FKConstraintColumnName VARCHAR(255),
PKConstraintName VARCHAR(255),
PKConstraintTableSchema VARCHAR(255),
PKConstraintTableName VARCHAR(255),
PKConstraintColumnName VARCHAR(255)
)
INSERT INTO #temptable(FKConstraintName, FKConstraintTableSchema, FKConstraintTableName, FKConstraintColumnName)
SELECT
KeyColumnUsage.CONSTRAINT_NAME,
KeyColumnUsage.TABLE_SCHEMA,
KeyColumnUsage.TABLE_NAME,
KeyColumnUsage.COLUMN_NAME
FROM
INFORMATION_SCHEMA.KEY_COLUMN_USAGE KeyColumnUsage
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TableConstraints
ON KeyColumnUsage.CONSTRAINT_NAME = TableConstraints.CONSTRAINT_NAME
WHERE
TableConstraints.CONSTRAINT_TYPE = 'FOREIGN KEY'
UPDATE #temptable SET
PKConstraintName = UNIQUE_CONSTRAINT_NAME
FROM
#temptable tt
INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS ReferentialConstraint
ON tt.FKConstraintName = ReferentialConstraint.CONSTRAINT_NAME
UPDATE #temptable SET
PKConstraintTableSchema = TABLE_SCHEMA,
PKConstraintTableName = TABLE_NAME
FROM #temptable tt
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TableConstraints
ON tt.PKConstraintName = TableConstraints.CONSTRAINT_NAME
UPDATE #temptable SET
PKConstraintColumnName = COLUMN_NAME
FROM #temptable tt
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KeyColumnUsage
ON tt.PKConstraintName = KeyColumnUsage.CONSTRAINT_NAME
--Now to drop constraint:
SELECT
'
ALTER TABLE [' + FKConstraintTableSchema + '].[' + FKConstraintTableName + ']
DROP CONSTRAINT ' + FKConstraintName + '
GO'
FROM
#temptable
--Finally to add constraint:
SELECT
'
ALTER TABLE [' + FKConstraintTableSchema + '].[' + FKConstraintTableName + ']
ADD CONSTRAINT ' + FKConstraintName + ' FOREIGN KEY(' + FKConstraintColumnName + ') REFERENCES [' + PKConstraintTableSchema + '].[' + PKConstraintTableName + '](' + PKConstraintColumnName + ')
GO'
FROM
#temptable
GO

There is an easy way to this.
-- Disable all the constraint in database
EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all'
-- Enable all the constraint in database
EXEC sp_msforeachtable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all'
Reference SQL SERVER – Disable All the Foreign Key Constraint in Database – Enable All the Foreign Key Constraint in Database

Disable all table constraints
ALTER TABLE TableName NOCHECK CONSTRAINT ConstraintName
-- Enable all table constraints
ALTER TABLE TableName CHECK CONSTRAINT ConstraintName

In case you use a different database schemas than ".dbo" or your db is containing Pk´s, which are composed by several fields, please don´t use the the solution of Carter Medlin, otherwise you will damage your db!!!
When you are working with different schemas try this (don´t forget to make a backup of your database before!):
DECLARE #sql AS NVARCHAR(max)=''
select #sql = #sql +
'ALTER INDEX ALL ON ' + SCHEMA_NAME( t.schema_id) +'.'+ '['+ t.[name] + '] DISABLE;'+CHAR(13)
from
sys.tables t
where type='u'
select #sql = #sql +
'ALTER INDEX ' + i.[name] + ' ON ' + SCHEMA_NAME( t.schema_id) +'.'+'[' + t.[name] + '] REBUILD;'+CHAR(13)
from
sys.key_constraints i
join
sys.tables t on i.parent_object_id=t.object_id
where i.type='PK'
exec dbo.sp_executesql #sql;
go
After doing some Fk-free actions, you can switch back with
DECLARE #sql AS NVARCHAR(max)=''
select #sql = #sql +
'ALTER INDEX ALL ON ' + SCHEMA_NAME( t.schema_id) +'.'+'[' + t.[name] + '] REBUILD;'+CHAR(13)
from
sys.tables t
where type='u'
print #sql
exec dbo.sp_executesql #sql;
exec sp_msforeachtable "ALTER TABLE ? WITH NOCHECK CHECK CONSTRAINT ALL";

not need to run queries to sidable FKs on sql. If you have a FK from table A to B, you should:
delete data from table A
delete data from table B
insert data on B
insert data on A
You can also tell the destination not to check constraints

Truncating the table wont be possible even if you disable the foreign keys.so you can use
delete command to remove all the records from the table,but be aware if you are using delete
command for a table which consists of millions of records then your package will be slow
and your transaction log size will increase and it may fill up your valuable disk space.
If you drop the constraints it may happen that you will fill up your table with unclean data
and when you try to recreate the constraints it may not allow you to as it will give errors.
so make sure that if you drop the constraints,you are loading data which are correctly related to each other and satisfy the constraint relations which you are going to recreate.
so please carefully think the pros and cons of each method and use it according to your requirements

Disable all indexes (including the pk, which will disable all fks), then reenable the pks.
DECLARE #sql AS NVARCHAR(max)=''
select #sql = #sql +
'ALTER INDEX ALL ON [' + t.[name] + '] DISABLE;'+CHAR(13)
from
sys.tables t
where type='u'
select #sql = #sql +
'ALTER INDEX ' + i.[name] + ' ON [' + t.[name] + '] REBUILD;'+CHAR(13)
from
sys.key_constraints i
join
sys.tables t on i.parent_object_id=t.object_id
where
i.type='PK'
exec dbo.sp_executesql #sql;
go
[Do your data load]
Then bring everything back to life...
DECLARE #sql AS NVARCHAR(max)=''
select #sql = #sql +
'ALTER INDEX ALL ON [' + t.[name] + '] REBUILD;'+CHAR(13)
from
sys.tables t
where type='u'
exec dbo.sp_executesql #sql;
go

Related

T-SQL Drop all tables

I am trying to drop all tables in a database without having to do it in the proper order. From what I have read running the NOCHECK command will prevent foreign keys from being checked. However, even after running that I still get an error trying to drop the first table.
Could not drop object 'dbo.TABLENAME' because it is referenced by
a FOREIGN KEY constraint
I have seen this question answered successfully before so I don't understand what is different with what I am doing. This is running on SQL Server 2008 R2.
BEGIN TRANSACTION
--get current list of tables
SELECT QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) as 'Dropped Table'
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
WHERE t.type = 'U'
--disable constraint checking in all tables
DECLARE #sql NVARCHAR(max)
SET #sql = ''
SELECT #sql += ' ALTER TABLE ' + QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) + ' NOCHECK CONSTRAINT ALL; '
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
WHERE t.type = 'U'
select #sql
Exec sp_executesql #sql
--disable all constraints (this also didn't work)
--EXEC sp_MSforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"
--drop all tables
SET #sql = ''
SELECT #sql += ' DROP TABLE ' + QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) + '; '
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
WHERE t.type = 'U'
select #sql
Exec sp_executesql #sql
--check current list, should be empty
SELECT QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) as 'Tables'
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
WHERE t.type = 'U'
ROLLBACK TRANSACTION
Update 1
I removed the constraint disabling code in place of constraint dropping code but it gives and error.
--drop all constraints
DECLARE #sql NVARCHAR(max)
SET #sql = ''
SELECT #sql += ' ALTER TABLE ' +QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) + ' DROP CONSTRAINT ' + ctu.CONSTRAINT_NAME + ';'
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
INNER JOIN EOS_DEV.INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE as ctu
ON ctu.TABLE_SCHEMA = s.name AND ctu.TABLE_NAME = t.name
WHERE t.type = 'U'
Exec sp_executesql #sql
The constraint '[CONSTRAINT_NAME]' is being referenced by table
'[TABLE_NAME]', foreign key constraint '[FK_NAME]'
How can I modify this query so I only target FK constraints?
Thanks everyone for your help. I updated my query and can now confirm that it has the ability to drop all tables indiscriminately. I also added a section to drop all stored procs for a little added flavor.
BEGIN TRANSACTION
--get current list of tables
SELECT QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) as 'Dropped Table'
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
WHERE t.type = 'U'
--drop all constraints
DECLARE #sql NVARCHAR(max)
SET #sql = ''
SELECT #sql += ' ALTER TABLE ' +QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) + ' DROP CONSTRAINT ' + tc.CONSTRAINT_NAME + ';'
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
INNER JOIN EOS_DEV.INFORMATION_SCHEMA.TABLE_CONSTRAINTS as tc
ON tc.TABLE_SCHEMA = s.name AND tc.TABLE_NAME = t.name
WHERE t.type = 'U'
AND tc.CONSTRAINT_TYPE = 'FOREIGN KEY'
Exec sp_executesql #sql
--drop all tables
SET #sql = ''
SELECT #sql += ' DROP TABLE ' + QUOTENAME(s.NAME) + '.' + QUOTENAME(t.NAME) + '; '
FROM sys.tables t
JOIN sys.schemas s
ON t.[schema_id] = s.[schema_id]
WHERE t.type = 'U'
Exec sp_executesql #sql
--drop all stored procs
SET #sql = ''
SELECT #sql += 'DROP PROCEDURE [' + SCHEMA_NAME(p.schema_id) + '].[' + p.NAME + ']'
FROM sys.procedures as p
where p.is_ms_shipped = 0
AND p.type = 'P'
Exec sp_executesql #sql
ROLLBACK TRANSACTION
Setting a FK to NOCHECK will allow you to INSERT,UPDATE, or DELETE rows that would violate the constraint. It will not allow you to DROP or TRUNCATE the target table.
EG:
use tempdb
create table a(id int primary key)
create table b(id int primary key, aid int references a)
alter table b nocheck constraint all
insert into b(id,aid) values (1,1) --succeeds because of nocheck
drop table a --fails
--Msg 3726, Level 16, State 1, Line 11
--Could not drop object 'a' because it is referenced by a FOREIGN KEY constraint.
Do you have to make this so difficult? Why not just restore an empty database (or a database that contains just your schema and whatever "default" rows are needed)?

How can I drop a table if there is a foreign key constraint in SQL Server?

I have the following:
DROP TABLE [dbo].[ExtraUserInformation];
DROP TABLE [dbo].[UserProfile];
DROP TABLE [dbo].[webpages_Membership];
DROP TABLE [dbo].[webpages_OAuthMembership];
DROP TABLE [dbo].[webpages_Roles];
DROP TABLE [dbo].[webpages_UsersInRoles];
CREATE TABLE [dbo].[ExtraUserInformation] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[UserId] INT NOT NULL,
[FullName] NVARCHAR (MAX) NULL,
[Link] NVARCHAR (MAX) NULL,
[Verified] BIT NULL,
CONSTRAINT [PK_dbo.ExtraUserInformation] PRIMARY KEY CLUSTERED ([Id] ASC)
);
CREATE TABLE [dbo].[webpages_UsersInRoles] (
[UserId] INT NOT NULL,
[RoleId] INT NOT NULL,
PRIMARY KEY CLUSTERED ([UserId] ASC, [RoleId] ASC),
CONSTRAINT [fk_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[UserProfile] ([UserId]),
CONSTRAINT [fk_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [dbo].[webpages_Roles] ([RoleId])
);
However this is failing with a message saying:
Msg 3726, Level 16, State 1, Line 6
Could not drop object 'dbo.UserProfile' because it is referenced by a FOREIGN KEY constraint.
Msg 3726, Level 16, State 1, Line 9
Could not drop object 'dbo.webpages_Roles' because it is referenced by a FOREIGN KEY constraint.
Msg 2714, Level 16, State 6, Line 27
There is already an object named 'UserProfile' in the database.
Checking identity information: current identity value 'NULL', current column value 'NULL'.
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
How can I drop a table in these circumstances?
You must drop the constraint before you can drop the table. Otherwise its rule violation that could break the databases Referential Integrity.
How to get foreign key relationships see this old question.
SQL DROP TABLE foreign key constraint
1-firstly, drop the foreign key constraint after that drop the tables.
2-you can drop all foreign key via executing the following query:
DECLARE #SQL varchar(4000)=''
SELECT #SQL =
#SQL + 'ALTER TABLE ' + s.name+'.'+t.name + ' DROP CONSTRAINT [' + RTRIM(f.name) +'];' + CHAR(13)
FROM sys.Tables t
INNER JOIN sys.foreign_keys f ON f.parent_object_id = t.object_id
INNER JOIN sys.schemas s ON s.schema_id = f.schema_id
--EXEC (#SQL)
PRINT #SQL
if you execute the printed results #SQL, the foreign keys will be dropped.
The Best Answer to dropping the table containing foreign constraints is :
Step 1 : Drop the Primary key of the table.
Step 2 : Now it will prompt whether to delete all the foreign references or not.
Step 3 : Delete the table.
To drop a table if there is a foreign key constraint in MySQL Server?
Run the sql query:
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE table_name
Hope it helps!
--Find and drop the constraints
DECLARE #dynamicSQL VARCHAR(MAX)
DECLARE MY_CURSOR CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT dynamicSQL = 'ALTER TABLE [' + OBJECT_SCHEMA_NAME(parent_object_id) + '].[' + OBJECT_NAME(parent_object_id) + '] DROP CONSTRAINT [' + name + ']'
FROM sys.foreign_keys
WHERE object_name(referenced_object_id) in ('table1', 'table2', 'table3')
OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO #dynamicSQL
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #dynamicSQL
EXEC (#dynamicSQL)
FETCH NEXT FROM MY_CURSOR INTO #dynamicSQL
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
-- Drop tables
DROP 'table1'
DROP 'table2'
DROP 'table3'
You have to drop the constraint before drop your table.
You can use those queries to find all FKs in your table and find the FKs in the tables in which your table is used.
Declare #SchemaName VarChar(200) = 'Your Schema name'
Declare #TableName VarChar(200) = 'Your Table Name'
-- Find FK in This table.
SELECT
' IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id =
OBJECT_ID(N''' +
'[' + OBJECT_SCHEMA_NAME(FK.parent_object_id) + '].[' + FK.name + ']'
+ ''') AND parent_object_id = OBJECT_ID(N''' +
'[' + OBJECT_SCHEMA_NAME(FK.parent_object_id) + '].[' +
OBJECT_NAME(FK.parent_object_id) + ']' + ''')) ' +
'ALTER TABLE ' + OBJECT_SCHEMA_NAME(FK.parent_object_id) +
'.[' + OBJECT_NAME(FK.parent_object_id) +
'] DROP CONSTRAINT ' + FK.name
, S.name , O.name, OBJECT_NAME(FK.parent_object_id)
FROM sys.foreign_keys AS FK
INNER JOIN Sys.objects As O
ON (O.object_id = FK.parent_object_id )
INNER JOIN SYS.schemas AS S
ON (O.schema_id = S.schema_id)
WHERE
O.name = #TableName
And S.name = #SchemaName
-- Find the FKs in the tables in which this table is used
SELECT
' IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id =
OBJECT_ID(N''' +
'[' + OBJECT_SCHEMA_NAME(FK.parent_object_id) + '].[' + FK.name + ']'
+ ''') AND parent_object_id = OBJECT_ID(N''' +
'[' + OBJECT_SCHEMA_NAME(FK.parent_object_id) + '].[' +
OBJECT_NAME(FK.parent_object_id) + ']' + ''')) ' +
' ALTER TABLE ' + OBJECT_SCHEMA_NAME(FK.parent_object_id) +
'.[' + OBJECT_NAME(FK.parent_object_id) +
'] DROP CONSTRAINT ' + FK.name
, S.name , O.name, OBJECT_NAME(FK.parent_object_id)
FROM sys.foreign_keys AS FK
INNER JOIN Sys.objects As O
ON (O.object_id = FK.referenced_object_id )
INNER JOIN SYS.schemas AS S
ON (O.schema_id = S.schema_id)
WHERE
O.name = #TableName
And S.name = #SchemaName
BhupeshC and murat , this is what I was looking for. However #SQL varchar(4000) wasn't big enough. So, small change
DECLARE #cmd varchar(4000)
DECLARE MY_CURSOR CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
select 'ALTER TABLE ['+s.name+'].['+t.name+'] DROP CONSTRAINT [' + RTRIM(f.name) +'];' FROM sys.Tables t INNER JOIN sys.foreign_keys f ON f.parent_object_id = t.object_id INNER JOIN sys.schemas s ON s.schema_id = f.schema_id
OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO #cmd
WHILE ##FETCH_STATUS = 0
BEGIN
-- EXEC (#cmd)
PRINT #cmd
FETCH NEXT FROM MY_CURSOR INTO #cmd
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
GO
Re removing constraints and dropping the tables, this script can get all constraints for a selected list of tables and then drop the constraints and then delete the tables.
DECLARE #id INT
DECLARE #strSQL NVARCHAR(max)
DECLARE #deleteCurser CURSOR
DECLARE #deleteTableCurser CURSOR
declare #SelectedTables table ([name] sysname, [object_id] int)
Insert into #SelectedTables ([name], [object_id])
SELECT t.name, t.object_id
FROM sys.Tables t
where t.name in
-- Change Name of tables here
('table1','table2','table100')
SET #deleteTableCurser = CURSOR FOR
SELECT strSQL =
'ALTER TABLE ' + s.name+'.'+t.name + ' DROP CONSTRAINT [' + RTRIM(f.name) +'];'
FROM #SelectedTables t
INNER JOIN sys.foreign_keys f ON f.parent_object_id = t.object_id
INNER JOIN sys.schemas s ON s.schema_id = f.schema_id
OPEN #deleteTableCurser
FETCH Next
FROM #deleteTableCurser INTO #strSQL
WHILE ##FETCH_STATUS = 0
BEGIN
print(#strSQL)
EXEC (#strSQL)
FETCH NEXT
FROM #deleteTableCurser INTO #strSQL
END
CLOSE #deleteTableCurser
DEALLOCATE #deleteTableCurser
SET #deleteCurser = CURSOR FOR
SELECT strSQL = 'DROP TABLE ['+ t.name+ '];'
FROM #SelectedTables t
OPEN #deleteCurser
FETCH Next
FROM #deleteCurser INTO #strSQL
WHILE ##FETCH_STATUS = 0
BEGIN
print(#strSQL)
EXEC (#strSQL)
FETCH NEXT
FROM #deleteCurser INTO #strSQL
END
CLOSE #deleteCurser
DEALLOCATE #deleteCurser
Type this .... SET foreign_key_checks = 0;
delete your table then type SET foreign_key_checks = 1;
MySQL – Temporarily disable Foreign Key Checks or Constraints

How can I find out what table is joined with a certain table?

I am refactoring my application and I don't need one of my db tables any more. I try to delete it but it gives me an error:
Drop Failed for: 'XYZ'. Could not drop because it is referenced by a Foreign Key Constraint
How can I find out what other table has a foreign key column to this table?
Right click on the table in the Object Explore and View Dependencies?
You can get the list here (leave off the where clause if you want a list of all FK constraints in the database):
SELECT name,
QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(parent_object_id))
+ ' references '
+ QUOTENAME(OBJECT_SCHEMA_NAME(referenced_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(referenced_object_id))
FROM sys.foreign_keys
WHERE OBJECT_NAME(referenced_object_id) = N'XYZ';
To generate a drop, you can just say:
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'';
SELECT #sql = #sql + '
ALTER TABLE ' +
QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(parent_object_id))
+ ' DROP CONSTRAINT ' + QUOTENAME(name) + ';'
FROM sys.foreign_keys
WHERE OBJECT_NAME(referenced_object_id) = N'XYZ';
EXEC sp_executesql #sql;
Try this
select * from sys.foreign_keys fk where referenced_object_id = object_id(<tablename>)

How to drop all tables in a SQL Server database?

I'm trying to write a script that will completely empty a SQL Server database. This is what I have so far:
USE [dbname]
GO
EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all'
EXEC sp_msforeachtable 'DELETE ?'
When I run it in the Management Studio, I get:
Command(s) completed successfully.
but when I refresh the table list, they are all still there. What am I doing wrong?
You can also delete all tables from database using only MSSMS UI tools (without using SQL script). Sometimes this way can be more comfortable (especially if it is performed occasionally)
I do this step by step as follows:
Select 'Tables' on the database tree (Object Explorer)
Press F7 to open Object Explorer Details view
In this view select tables which have to be deleted (in this case all of them)
Keep pressing Delete until all tables have been deleted (you repeat it as many times as amount of errors due to key constraints/dependencies)
It doesn't work for me either when there are multiple foreign key tables.
I found that code that works and does everything you try (delete all tables from your database):
DECLARE #Sql NVARCHAR(500) DECLARE #Cursor CURSOR
SET #Cursor = CURSOR FAST_FORWARD FOR
SELECT DISTINCT sql = 'ALTER TABLE [' + tc2.TABLE_SCHEMA + '].[' + tc2.TABLE_NAME + '] DROP [' + rc1.CONSTRAINT_NAME + '];'
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc1
LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc2 ON tc2.CONSTRAINT_NAME =rc1.CONSTRAINT_NAME
OPEN #Cursor FETCH NEXT FROM #Cursor INTO #Sql
WHILE (##FETCH_STATUS = 0)
BEGIN
Exec sp_executesql #Sql
FETCH NEXT FROM #Cursor INTO #Sql
END
CLOSE #Cursor DEALLOCATE #Cursor
GO
EXEC sp_MSforeachtable 'DROP TABLE ?'
GO
You can find the post here. It is the post by Groker.
In SSMS:
Right click the database
Go to "Tasks"
Click "Generate Scripts"
In the "Choose Objects" section, select "Script entire database and all database objects"
In the "Set Scripting Options" section, click the "Advanced" button
On "Script DROP and CREATE" switch "Script CREATE" to "Script DROP" and press OK
Then, either save to file, clipboard, or new query window.
Run script.
Now, this will drop everything, including the database. Make sure to remove the code for the items you don't want dropped. Alternatively, in the "Choose Objects" section, instead of selecting to script entire database just select the items you want to remove.
The accepted answer doesn't support Azure. It uses an undocumented stored procedure "sp_MSforeachtable". If you get an "azure could not find stored procedure 'sp_msforeachtable" error when running or simply want to avoid relying on undocumented features (which can be removed or have their functionality changed at any point) then try the below.
This version ignores the entity framework migration history table "__MigrationHistory" and the "database_firewall_rules" which is an Azure table you will not have permission to delete.
Lightly tested on Azure. Do check to make this this has no undesired effects on your environment.
DECLARE #sql NVARCHAR(2000)
WHILE(EXISTS(SELECT 1 from INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE='FOREIGN KEY'))
BEGIN
SELECT TOP 1 #sql=('ALTER TABLE ' + TABLE_SCHEMA + '.[' + TABLE_NAME + '] DROP CONSTRAINT [' + CONSTRAINT_NAME + ']')
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE CONSTRAINT_TYPE = 'FOREIGN KEY'
EXEC(#sql)
PRINT #sql
END
WHILE(EXISTS(SELECT * from INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME != '__MigrationHistory' AND TABLE_NAME != 'database_firewall_rules'))
BEGIN
SELECT TOP 1 #sql=('DROP TABLE ' + TABLE_SCHEMA + '.[' + TABLE_NAME + ']')
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME != '__MigrationHistory' AND TABLE_NAME != 'database_firewall_rules'
EXEC(#sql)
PRINT #sql
END
Taken from:
https://edspencer.me.uk/2013/02/25/drop-all-tables-in-a-sql-server-database-azure-friendly/
http://www.sqlservercentral.com/blogs/sqlservertips/2011/10/11/remove-all-foreign-keys/
delete is used for deleting rows from a table. You should use drop table instead.
EXEC sp_msforeachtable 'drop table [?]'
/* Drop all Primary Key constraints */
DECLARE #name VARCHAR(128)
DECLARE #constraint VARCHAR(254)
DECLARE #SQL VARCHAR(254)
SELECT #name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME)
WHILE #name IS NOT NULL
BEGIN
SELECT #constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_NAME = #name ORDER BY CONSTRAINT_NAME)
WHILE #constraint is not null
BEGIN
SELECT #SQL = 'ALTER TABLE [dbo].[' + RTRIM(#name) +'] DROP CONSTRAINT [' + RTRIM(#constraint)+']'
EXEC (#SQL)
PRINT 'Dropped PK Constraint: ' + #constraint + ' on ' + #name
SELECT #constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND CONSTRAINT_NAME <> #constraint AND TABLE_NAME = #name ORDER BY CONSTRAINT_NAME)
END
SELECT #name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME)
END
GO
/* Drop all tables */
DECLARE #name VARCHAR(128)
DECLARE #SQL VARCHAR(254)
SELECT #name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 ORDER BY [name])
WHILE #name IS NOT NULL
BEGIN
SELECT #SQL = 'DROP TABLE [dbo].[' + RTRIM(#name) +']'
EXEC (#SQL)
PRINT 'Dropped Table: ' + #name
SELECT #name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 AND [name] > #name ORDER BY [name])
END
GO
You are almost right, use instead:
EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all'
EXEC sp_msforeachtable 'DROP TABLE ?'
but second line you might need to execute more then once until you stop getting error:
Could not drop object 'dbo.table' because it is referenced by a FOREIGN KEY constraint.
Message:
Command(s) completed successfully.
means that all table were successfully deleted.
Short and sweet:
USE YOUR_DATABASE_NAME
-- Disable all referential integrity constraints
EXEC sp_MSforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
GO
-- Drop all PKs and FKs
declare #sql nvarchar(max)
SELECT #sql = STUFF((SELECT '; ' + 'ALTER TABLE ' + Table_Name +' drop constraint ' + Constraint_Name from Information_Schema.CONSTRAINT_TABLE_USAGE ORDER BY Constraint_Name FOR XML PATH('')),1,1,'')
EXECUTE (#sql)
GO
-- Drop all tables
EXEC sp_MSforeachtable 'DROP TABLE ?'
GO
Spot on!!
You can use below query to remove all the tables from database
EXEC sp_MSforeachtable #command1 = "DROP TABLE ?"
Happy coding !
Seems the command should be without the square blanket
EXEC sp_msforeachtable 'drop table ?'
The fasted way is:
New Database Diagrams
Add all table
Ctrl + A to select all
Right Click "Remove from Database"
Ctrl + S to save
Enjoy
For me, the easiest way:
--First delete all constraints
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'';
SELECT #sql = #sql + N'
ALTER TABLE ' + QUOTENAME(s.name) + N'.'
+ QUOTENAME(t.name) + N' DROP CONSTRAINT '
+ QUOTENAME(c.name) + ';'
FROM sys.objects AS c
INNER JOIN sys.tables AS t
ON c.parent_object_id = t.[object_id]
INNER JOIN sys.schemas AS s
ON t.[schema_id] = s.[schema_id]
WHERE c.[type] IN ('D','C','F','PK','UQ')
ORDER BY c.[type];
EXEC sys.sp_executesql #sql;
-- Then drop all tables
exec sp_MSforeachtable 'DROP TABLE ?'
Azure SQL + tables (with constraints) in a different schema than dbo + ipv6_database_firewall_rules condition.
This is a little extension for https://stackoverflow.com/a/43128914/4510954 answer.
DECLARE #sql NVARCHAR(2000)
WHILE(EXISTS(SELECT 1 from INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE='FOREIGN KEY'))
BEGIN
SELECT TOP 1 #sql=('ALTER TABLE ' + CONSTRAINT_SCHEMA + '.[' + TABLE_NAME + '] DROP CONSTRAINT [' + CONSTRAINT_NAME + ']')
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE CONSTRAINT_TYPE = 'FOREIGN KEY'
EXEC(#sql)
PRINT #sql
END
WHILE(EXISTS(SELECT * from INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME != '__MigrationHistory' AND TABLE_NAME != 'database_firewall_rules' AND TABLE_NAME != 'ipv6_database_firewall_rules'))
BEGIN
SELECT TOP 1 #sql=('DROP TABLE ' + CONSTRAINT_SCHEMA + '.[' + TABLE_NAME + ']')
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE TABLE_NAME != '__MigrationHistory' AND TABLE_NAME != 'database_firewall_rules'
EXEC(#sql)
PRINT #sql
END
How about dropping the entire database and then creating it again? This works for me.
DROP DATABASE mydb;
CREATE DATABASE mydb;
For Temporal Tables it is a bit more complicated due to the fact there may be some foreign keys and also exception:
Drop table operation failed on table XXX because it is not a supported operation on system-versioned temporal tables
What you can use is:
-- Disable constraints (foreign keys)
EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
GO
-- Disable system versioning (temporial tables)
EXEC sp_MSForEachTable '
IF OBJECTPROPERTY(object_id(''?''), ''TableTemporalType'') = 2
ALTER TABLE ? SET (SYSTEM_VERSIONING = OFF)
'
GO
-- Removing tables
EXEC sp_MSForEachTable 'DROP TABLE ?'
GO
I know this is an old post now but I have tried all the answers on here on a multitude of databases and I have found they all work sometimes but not all of the time for various (I can only assume) quirks of SQL Server.
Eventually I came up with this. I have tested this everywhere (generally speaking) I can and it works (without any hidden store procedures).
For note mostly on SQL Server 2014. (but most of the other versions I tried it also seems to worked fine).
I have tried while loops and nulls etc etc, cursors and various other forms but they always seem to fail on some databases but not others for no obvious reason.
Getting a count and using that to iterate always seems to work on everything Ive tested.
USE [****YOUR_DATABASE****]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- Drop all referential integrity constraints --
-- Drop all Primary Key constraints. --
DECLARE #sql NVARCHAR(296)
DECLARE #table_name VARCHAR(128)
DECLARE #constraint_name VARCHAR(128)
SET #constraint_name = ''
DECLARE #row_number INT
SELECT #row_number = Count(*) FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc1
LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc2 ON tc2.CONSTRAINT_NAME = rc1.CONSTRAINT_NAME
WHILE #row_number > 0
BEGIN
BEGIN
SELECT TOP 1 #table_name = tc2.TABLE_NAME, #constraint_name = rc1.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc1
LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc2 ON tc2.CONSTRAINT_NAME = rc1.CONSTRAINT_NAME
AND rc1.CONSTRAINT_NAME > #constraint_name
ORDER BY rc1.CONSTRAINT_NAME
SELECT #sql = 'ALTER TABLE [dbo].[' + RTRIM(#table_name) +'] DROP CONSTRAINT [' + RTRIM(#constraint_name)+']'
EXEC (#sql)
PRINT 'Dropped Constraint: ' + #constraint_name + ' on ' + #table_name
SET #row_number = #row_number - 1
END
END
GO
-- Drop all tables --
DECLARE #sql NVARCHAR(156)
DECLARE #name VARCHAR(128)
SET #name = ''
DECLARE #row_number INT
SELECT #row_number = Count(*) FROM sysobjects WHERE [type] = 'U' AND category = 0
WHILE #row_number > 0
BEGIN
SELECT #name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 AND [name] > #name ORDER BY [name])
SELECT #sql = 'DROP TABLE [dbo].[' + RTRIM(#name) +']'
EXEC (#sql)
PRINT 'Dropped Table: ' + #name
SET #row_number = #row_number - 1
END
GO
sp_msforeachtable is not available in Azure SQL
For Azure SQL:
This query will drop Foreign Key constraints
DECLARE #Name VARCHAR(200)
DECLARE #Constraint VARCHAR(300)
DECLARE #SQL VARCHAR(300)
SELECT #Name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME)
WHILE #Name is not null
BEGIN
SELECT #Constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND TABLE_NAME = #Name ORDER BY CONSTRAINT_NAME)
WHILE #Constraint IS NOT NULL
BEGIN
SELECT #SQL = 'ALTER TABLE [dbo].[' + RTRIM(#Name) +'] DROP CONSTRAINT [' + RTRIM(#Constraint) +']'
EXEC (#SQL)
PRINT 'Dropped FK Constraint: ' + #Constraint + ' on ' + #Name
SELECT #Constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND CONSTRAINT_NAME <> #Constraint AND TABLE_NAME = #Name ORDER BY CONSTRAINT_NAME)
END
SELECT #Name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME)
END
GO
This will drop all the tables from the database
DECLARE #Name VARCHAR(200)
DECLARE #SQL VARCHAR(300)
SELECT #Name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 ORDER BY [name])
WHILE #Name IS NOT NULL
BEGIN
SELECT #SQL = 'DROP TABLE [dbo].[' + RTRIM(#name) +']' /*here you can change schema if it is different from dbo*/
EXEC (#SQL)
PRINT 'Dropped Table: ' + #Name
SELECT #Name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 AND [name] > #Name ORDER BY [name])
END
GO

How can foreign key constraints be temporarily disabled using T-SQL?

Are disabling and enabling foreign key constraints supported in SQL Server? Or is my only option to drop and then re-create the constraints?
If you want to disable all constraints in the database just run this code:
-- disable all constraints
EXEC sp_MSforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"
To switch them back on, run: (the print is optional of course and it is just listing the tables)
-- enable all constraints
exec sp_MSforeachtable #command1="print '?'", #command2="ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"
I find it useful when populating data from one database to another. It is much better approach than dropping constraints. As you mentioned it comes handy when dropping all the data in the database and repopulating it (say in test environment).
If you are deleting all the data you may find this solution to be helpful.
Also sometimes it is handy to disable all triggers as well, you can see the complete solution here.
(Copied from from http://www.sqljunkies.com/WebLog/roman/archive/2005/01/30/7037.aspx,
which is now archived in the Wayback Machine)
Foreign key constraints and check constraint are very useful for enforcing data integrity and business rules. There are certain scenarios though where it is useful to temporarily turn them off because their behavior is either not needed or could do more harm than good. I sometimes disable constraint checking on tables during data loads from external sources or when I need to script a table drop/recreate with reloading the data back into the table. I usually do it in scenarios where I don't want a time consuming process to fail because one or a few of many million rows have bad data in it. But I always turn the constraints back on once the process is finished and also in some cases I run data integrity checks on the imported data.
If you disable a foreign key constraint, you will be able to insert a value that does not exist in the parent table. If you disable a check constraint, you will be able to put a value in a column as if the check constraint was not there. Here are a few examples of disabling and enabling table constraints:
-- Disable all table constraints
ALTER TABLE MyTable NOCHECK CONSTRAINT ALL
-- Enable all table constraints
ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT ALL
-- Disable single constraint
ALTER TABLE MyTable NOCHECK CONSTRAINT MyConstraint
-- Enable single constraint
ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT MyConstraint
To disable the constraint you have ALTER the table using NOCHECK
ALTER TABLE [TABLE_NAME] NOCHECK CONSTRAINT [ALL|CONSTRAINT_NAME]
To enable you to have to use double CHECK:
ALTER TABLE [TABLE_NAME] WITH CHECK CHECK CONSTRAINT [ALL|CONSTRAINT_NAME]
Pay attention to the double CHECK CHECK when enabling.
ALL means for all constraints in the table.
Once completed, if you need to check the status, use this script to list the constraint status. Will be very helpfull:
SELECT (CASE
WHEN OBJECTPROPERTY(CONSTID, 'CNSTISDISABLED') = 0 THEN 'ENABLED'
ELSE 'DISABLED'
END) AS STATUS,
OBJECT_NAME(CONSTID) AS CONSTRAINT_NAME,
OBJECT_NAME(FKEYID) AS TABLE_NAME,
COL_NAME(FKEYID, FKEY) AS COLUMN_NAME,
OBJECT_NAME(RKEYID) AS REFERENCED_TABLE_NAME,
COL_NAME(RKEYID, RKEY) AS REFERENCED_COLUMN_NAME
FROM SYSFOREIGNKEYS
ORDER BY TABLE_NAME, CONSTRAINT_NAME,REFERENCED_TABLE_NAME, KEYNO
Your best option is to DROP and CREATE foreign key constraints.
I didn't find examples in this post that would work for me "as-is", one would not work if foreign keys reference different schemas, the other would not work if foreign key references multiple columns. This script considers both, multiple schemas and multiple columns per foreign key.
Here is the script that generates "ADD CONSTRAINT" statements, for multiple columns it will separate them by comma (be sure to save this output before executing DROP statements):
PRINT N'-- CREATE FOREIGN KEY CONSTRAINTS --';
SET NOCOUNT ON;
SELECT '
PRINT N''Creating '+ const.const_name +'...''
GO
ALTER TABLE ' + const.parent_obj + '
ADD CONSTRAINT ' + const.const_name + ' FOREIGN KEY (
' + const.parent_col_csv + '
) REFERENCES ' + const.ref_obj + '(' + const.ref_col_csv + ')
GO'
FROM (
SELECT QUOTENAME(fk.NAME) AS [const_name]
,QUOTENAME(schParent.NAME) + '.' + QUOTENAME(OBJECT_name(fkc.parent_object_id)) AS [parent_obj]
,STUFF((
SELECT ',' + QUOTENAME(COL_NAME(fcP.parent_object_id, fcp.parent_column_id))
FROM sys.foreign_key_columns AS fcP
WHERE fcp.constraint_object_id = fk.object_id
FOR XML path('')
), 1, 1, '') AS [parent_col_csv]
,QUOTENAME(schRef.NAME) + '.' + QUOTENAME(OBJECT_NAME(fkc.referenced_object_id)) AS [ref_obj]
,STUFF((
SELECT ',' + QUOTENAME(COL_NAME(fcR.referenced_object_id, fcR.referenced_column_id))
FROM sys.foreign_key_columns AS fcR
WHERE fcR.constraint_object_id = fk.object_id
FOR XML path('')
), 1, 1, '') AS [ref_col_csv]
FROM sys.foreign_key_columns AS fkc
INNER JOIN sys.foreign_keys AS fk ON fk.object_id = fkc.constraint_object_id
INNER JOIN sys.objects AS oParent ON oParent.object_id = fkc.parent_object_id
INNER JOIN sys.schemas AS schParent ON schParent.schema_id = oParent.schema_id
INNER JOIN sys.objects AS oRef ON oRef.object_id = fkc.referenced_object_id
INNER JOIN sys.schemas AS schRef ON schRef.schema_id = oRef.schema_id
GROUP BY fkc.parent_object_id
,fkc.referenced_object_id
,fk.NAME
,fk.object_id
,schParent.NAME
,schRef.NAME
) AS const
ORDER BY const.const_name
Here is the script that generates "DROP CONSTRAINT" statements:
PRINT N'-- DROP FOREIGN KEY CONSTRAINTS --';
SET NOCOUNT ON;
SELECT '
PRINT N''Dropping ' + fk.NAME + '...''
GO
ALTER TABLE [' + sch.NAME + '].[' + OBJECT_NAME(fk.parent_object_id) + ']' + ' DROP CONSTRAINT ' + '[' + fk.NAME + ']
GO'
FROM sys.foreign_keys AS fk
INNER JOIN sys.schemas AS sch ON sch.schema_id = fk.schema_id
ORDER BY fk.NAME
The SQL-92 standard allows for a constaint to be declared as DEFERRABLE so that it can be deferred (implicitly or explicitly) within the scope of a transaction. Sadly, SQL Server is still missing this SQL-92 functionality.
For me, changing a constraint to NOCHECK is akin to changing the database structure on the fly -- dropping constraints certainly is -- and something to be avoided (e.g. users require increased privileges).
--Drop and Recreate Foreign Key Constraints
SET NOCOUNT ON
DECLARE #table TABLE(
RowId INT PRIMARY KEY IDENTITY(1, 1),
ForeignKeyConstraintName NVARCHAR(200),
ForeignKeyConstraintTableSchema NVARCHAR(200),
ForeignKeyConstraintTableName NVARCHAR(200),
ForeignKeyConstraintColumnName NVARCHAR(200),
PrimaryKeyConstraintName NVARCHAR(200),
PrimaryKeyConstraintTableSchema NVARCHAR(200),
PrimaryKeyConstraintTableName NVARCHAR(200),
PrimaryKeyConstraintColumnName NVARCHAR(200)
)
INSERT INTO #table(ForeignKeyConstraintName, ForeignKeyConstraintTableSchema, ForeignKeyConstraintTableName, ForeignKeyConstraintColumnName)
SELECT
U.CONSTRAINT_NAME,
U.TABLE_SCHEMA,
U.TABLE_NAME,
U.COLUMN_NAME
FROM
INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
ON U.CONSTRAINT_NAME = C.CONSTRAINT_NAME
WHERE
C.CONSTRAINT_TYPE = 'FOREIGN KEY'
UPDATE #table SET
PrimaryKeyConstraintName = UNIQUE_CONSTRAINT_NAME
FROM
#table T
INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS R
ON T.ForeignKeyConstraintName = R.CONSTRAINT_NAME
UPDATE #table SET
PrimaryKeyConstraintTableSchema = TABLE_SCHEMA,
PrimaryKeyConstraintTableName = TABLE_NAME
FROM #table T
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
ON T.PrimaryKeyConstraintName = C.CONSTRAINT_NAME
UPDATE #table SET
PrimaryKeyConstraintColumnName = COLUMN_NAME
FROM #table T
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
ON T.PrimaryKeyConstraintName = U.CONSTRAINT_NAME
--SELECT * FROM #table
--DROP CONSTRAINT:
SELECT
'
ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + ']
DROP CONSTRAINT ' + ForeignKeyConstraintName + '
GO'
FROM
#table
--ADD CONSTRAINT:
SELECT
'
ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + ']
ADD CONSTRAINT ' + ForeignKeyConstraintName + ' FOREIGN KEY(' + ForeignKeyConstraintColumnName + ') REFERENCES [' + PrimaryKeyConstraintTableSchema + '].[' + PrimaryKeyConstraintTableName + '](' + PrimaryKeyConstraintColumnName + ')
GO'
FROM
#table
GO
I do agree with you, Hamlin. When you are transfer data using SSIS or when want to replicate data, it seems quite necessary to temporarily disable or drop foreign key constraints and then re-enable or recreate them. In these cases, referential integrity is not an issue, because it is already maintained in the source database. Therefore, you can rest assured regarding this matter.
WITH CHECK CHECK is almost certainly required!
This point was raised in some of the answers and comments but I feel that it is important enough to call it out again.
Re-enabling a constraint using the following command (no WITH CHECK) will have some serious drawbacks.
ALTER TABLE MyTable CHECK CONSTRAINT MyConstraint;
WITH CHECK | WITH NOCHECK
Specifies whether the data in the table is or is not validated against
a newly added or re-enabled FOREIGN KEY or CHECK constraint. If not
specified, WITH CHECK is assumed for new constraints, and WITH NOCHECK
is assumed for re-enabled constraints.
If you do not want to verify new CHECK or FOREIGN KEY constraints
against existing data, use WITH NOCHECK. We do not recommend doing
this, except in rare cases. The new constraint will be evaluated in
all later data updates. Any constraint violations that are suppressed
by WITH NOCHECK when the constraint is added may cause future updates
to fail if they update rows with data that does not comply with the
constraint.
The query optimizer does not consider constraints that are defined
WITH NOCHECK. Such constraints are ignored until they are re-enabled
by using ALTER TABLE table WITH CHECK CHECK CONSTRAINT ALL.
Note: WITH NOCHECK is the default for re-enabling constraints. I have to wonder why...
No existing data in the table will be evaluated during the execution of this command - successful completion is no guarantee that the data in the table is valid according to the constraint.
During the next update of the invalid records, the constraint will be evaluated and will fail - resulting in errors that may be unrelated to the actual update that is made.
Application logic that relies on the constraint to ensure that data is valid may fail.
The query optimizer will not make use of any constraint that is enabled in this way.
The sys.foreign_keys system view provides some visibility into the issue. Note that it has both an is_disabled and an is_not_trusted column. is_disabled indicates whether future data manipulation operations will be validated against the constraint. is_not_trusted indicates whether all of the data currently in the table has been validated against the constraint.
ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT MyConstraint;
Are your constraints to be trusted? Find out...
SELECT * FROM sys.foreign_keys WHERE is_not_trusted = 1;
SET NOCOUNT ON
DECLARE #table TABLE(
RowId INT PRIMARY KEY IDENTITY(1, 1),
ForeignKeyConstraintName NVARCHAR(200),
ForeignKeyConstraintTableSchema NVARCHAR(200),
ForeignKeyConstraintTableName NVARCHAR(200),
ForeignKeyConstraintColumnName NVARCHAR(200),
PrimaryKeyConstraintName NVARCHAR(200),
PrimaryKeyConstraintTableSchema NVARCHAR(200),
PrimaryKeyConstraintTableName NVARCHAR(200),
PrimaryKeyConstraintColumnName NVARCHAR(200),
UpdateRule NVARCHAR(100),
DeleteRule NVARCHAR(100)
)
INSERT INTO #table(ForeignKeyConstraintName, ForeignKeyConstraintTableSchema, ForeignKeyConstraintTableName, ForeignKeyConstraintColumnName)
SELECT
U.CONSTRAINT_NAME,
U.TABLE_SCHEMA,
U.TABLE_NAME,
U.COLUMN_NAME
FROM
INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
ON U.CONSTRAINT_NAME = C.CONSTRAINT_NAME
WHERE
C.CONSTRAINT_TYPE = 'FOREIGN KEY'
UPDATE #table SET
T.PrimaryKeyConstraintName = R.UNIQUE_CONSTRAINT_NAME,
T.UpdateRule = R.UPDATE_RULE,
T.DeleteRule = R.DELETE_RULE
FROM
#table T
INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS R
ON T.ForeignKeyConstraintName = R.CONSTRAINT_NAME
UPDATE #table SET
PrimaryKeyConstraintTableSchema = TABLE_SCHEMA,
PrimaryKeyConstraintTableName = TABLE_NAME
FROM #table T
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
ON T.PrimaryKeyConstraintName = C.CONSTRAINT_NAME
UPDATE #table SET
PrimaryKeyConstraintColumnName = COLUMN_NAME
FROM #table T
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
ON T.PrimaryKeyConstraintName = U.CONSTRAINT_NAME
--SELECT * FROM #table
SELECT '
BEGIN TRANSACTION
BEGIN TRY'
--DROP CONSTRAINT:
SELECT
'
ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + ']
DROP CONSTRAINT ' + ForeignKeyConstraintName + '
'
FROM
#table
SELECT '
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
RAISERROR(''Operation failed.'', 16, 1)
END CATCH
IF(##TRANCOUNT != 0)
BEGIN
COMMIT TRANSACTION
RAISERROR(''Operation completed successfully.'', 10, 1)
END
'
--ADD CONSTRAINT:
SELECT '
BEGIN TRANSACTION
BEGIN TRY'
SELECT
'
ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + ']
ADD CONSTRAINT ' + ForeignKeyConstraintName + ' FOREIGN KEY(' + ForeignKeyConstraintColumnName + ') REFERENCES [' + PrimaryKeyConstraintTableSchema + '].[' + PrimaryKeyConstraintTableName + '](' + PrimaryKeyConstraintColumnName + ') ON UPDATE ' + UpdateRule + ' ON DELETE ' + DeleteRule + '
'
FROM
#table
SELECT '
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
RAISERROR(''Operation failed.'', 16, 1)
END CATCH
IF(##TRANCOUNT != 0)
BEGIN
COMMIT TRANSACTION
RAISERROR(''Operation completed successfully.'', 10, 1)
END'
GO
First post :)
For the OP, kristof's solution will work, unless there are issues with massive data and transaction log balloon issues on big deletes. Also, even with tlog storage to spare, since deletes write to the tlog, the operation can take a VERY long time for tables with hundreds of millions of rows.
I use a series of cursors to truncate and reload large copies of one of our huge production databases frequently. The solution engineered accounts for multiple schemas, multiple foreign key columns, and best of all can be sproc'd out for use in SSIS.
It involves creation of three staging tables (real tables) to house the DROP, CREATE, and CHECK FK scripts, creation and insertion of those scripts into the tables, and then looping over the tables and executing them. The attached script is four parts: 1.) creation and storage of the scripts in the three staging (real) tables, 2.) execution of the drop FK scripts via a cursor one by one, 3.) Using sp_MSforeachtable to truncate all the tables in the database other than our three staging tables and 4.) execution of the create FK and check FK scripts at the end of your ETL SSIS package.
Run the script creation portion in an Execute SQL task in SSIS. Run the "execute Drop FK Scripts" portion in a second Execute SQL task. Put the truncation script in a third Execute SQL task, then perform whatever other ETL processes you need to do prior to attaching the CREATE and CHECK scripts in a final Execute SQL task (or two if desired) at the end of your control flow.
Storage of the scripts in real tables has proven invaluable when the re-application of the foreign keys fails as you can select * from sync_CreateFK, copy/paste into your query window, run them one at a time, and fix the data issues once you find ones that failed/are still failing to re-apply.
Do not re-run the script again if it fails without making sure that you re-apply all of the foreign keys/checks prior to doing so, or you will most likely lose some creation and check fk scripting as our staging tables are dropped and recreated prior to the creation of the scripts to execute.
----------------------------------------------------------------------------
1)
/*
Author: Denmach
DateCreated: 2014-04-23
Purpose: Generates SQL statements to DROP, ADD, and CHECK existing constraints for a
database. Stores scripts in tables on target database for execution. Executes
those stored scripts via independent cursors.
DateModified:
ModifiedBy
Comments: This will eliminate deletes and the T-log ballooning associated with it.
*/
DECLARE #schema_name SYSNAME;
DECLARE #table_name SYSNAME;
DECLARE #constraint_name SYSNAME;
DECLARE #constraint_object_id INT;
DECLARE #referenced_object_name SYSNAME;
DECLARE #is_disabled BIT;
DECLARE #is_not_for_replication BIT;
DECLARE #is_not_trusted BIT;
DECLARE #delete_referential_action TINYINT;
DECLARE #update_referential_action TINYINT;
DECLARE #tsql NVARCHAR(4000);
DECLARE #tsql2 NVARCHAR(4000);
DECLARE #fkCol SYSNAME;
DECLARE #pkCol SYSNAME;
DECLARE #col1 BIT;
DECLARE #action CHAR(6);
DECLARE #referenced_schema_name SYSNAME;
--------------------------------Generate scripts to drop all foreign keys in a database --------------------------------
IF OBJECT_ID('dbo.sync_dropFK') IS NOT NULL
DROP TABLE sync_dropFK
CREATE TABLE sync_dropFK
(
ID INT IDENTITY (1,1) NOT NULL
, Script NVARCHAR(4000)
)
DECLARE FKcursor CURSOR FOR
SELECT
OBJECT_SCHEMA_NAME(parent_object_id)
, OBJECT_NAME(parent_object_id)
, name
FROM
sys.foreign_keys WITH (NOLOCK)
ORDER BY
1,2;
OPEN FKcursor;
FETCH NEXT FROM FKcursor INTO
#schema_name
, #table_name
, #constraint_name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #tsql = 'ALTER TABLE '
+ QUOTENAME(#schema_name)
+ '.'
+ QUOTENAME(#table_name)
+ ' DROP CONSTRAINT '
+ QUOTENAME(#constraint_name)
+ ';';
--PRINT #tsql;
INSERT sync_dropFK (
Script
)
VALUES (
#tsql
)
FETCH NEXT FROM FKcursor INTO
#schema_name
, #table_name
, #constraint_name
;
END;
CLOSE FKcursor;
DEALLOCATE FKcursor;
---------------Generate scripts to create all existing foreign keys in a database --------------------------------
----------------------------------------------------------------------------------------------------------
IF OBJECT_ID('dbo.sync_createFK') IS NOT NULL
DROP TABLE sync_createFK
CREATE TABLE sync_createFK
(
ID INT IDENTITY (1,1) NOT NULL
, Script NVARCHAR(4000)
)
IF OBJECT_ID('dbo.sync_createCHECK') IS NOT NULL
DROP TABLE sync_createCHECK
CREATE TABLE sync_createCHECK
(
ID INT IDENTITY (1,1) NOT NULL
, Script NVARCHAR(4000)
)
DECLARE FKcursor CURSOR FOR
SELECT
OBJECT_SCHEMA_NAME(parent_object_id)
, OBJECT_NAME(parent_object_id)
, name
, OBJECT_NAME(referenced_object_id)
, OBJECT_ID
, is_disabled
, is_not_for_replication
, is_not_trusted
, delete_referential_action
, update_referential_action
, OBJECT_SCHEMA_NAME(referenced_object_id)
FROM
sys.foreign_keys WITH (NOLOCK)
ORDER BY
1,2;
OPEN FKcursor;
FETCH NEXT FROM FKcursor INTO
#schema_name
, #table_name
, #constraint_name
, #referenced_object_name
, #constraint_object_id
, #is_disabled
, #is_not_for_replication
, #is_not_trusted
, #delete_referential_action
, #update_referential_action
, #referenced_schema_name;
WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN
SET #tsql = 'ALTER TABLE '
+ QUOTENAME(#schema_name)
+ '.'
+ QUOTENAME(#table_name)
+ CASE
#is_not_trusted
WHEN 0 THEN ' WITH CHECK '
ELSE ' WITH NOCHECK '
END
+ ' ADD CONSTRAINT '
+ QUOTENAME(#constraint_name)
+ ' FOREIGN KEY (';
SET #tsql2 = '';
DECLARE ColumnCursor CURSOR FOR
SELECT
COL_NAME(fk.parent_object_id
, fkc.parent_column_id)
, COL_NAME(fk.referenced_object_id
, fkc.referenced_column_id)
FROM
sys.foreign_keys fk WITH (NOLOCK)
INNER JOIN sys.foreign_key_columns fkc WITH (NOLOCK) ON fk.[object_id] = fkc.constraint_object_id
WHERE
fkc.constraint_object_id = #constraint_object_id
ORDER BY
fkc.constraint_column_id;
OPEN ColumnCursor;
SET #col1 = 1;
FETCH NEXT FROM ColumnCursor INTO #fkCol, #pkCol;
WHILE ##FETCH_STATUS = 0
BEGIN
IF (#col1 = 1)
SET #col1 = 0;
ELSE
BEGIN
SET #tsql = #tsql + ',';
SET #tsql2 = #tsql2 + ',';
END;
SET #tsql = #tsql + QUOTENAME(#fkCol);
SET #tsql2 = #tsql2 + QUOTENAME(#pkCol);
--PRINT '#tsql = ' + #tsql
--PRINT '#tsql2 = ' + #tsql2
FETCH NEXT FROM ColumnCursor INTO #fkCol, #pkCol;
--PRINT 'FK Column ' + #fkCol
--PRINT 'PK Column ' + #pkCol
END;
CLOSE ColumnCursor;
DEALLOCATE ColumnCursor;
SET #tsql = #tsql + ' ) REFERENCES '
+ QUOTENAME(#referenced_schema_name)
+ '.'
+ QUOTENAME(#referenced_object_name)
+ ' ('
+ #tsql2 + ')';
SET #tsql = #tsql
+ ' ON UPDATE '
+
CASE #update_referential_action
WHEN 0 THEN 'NO ACTION '
WHEN 1 THEN 'CASCADE '
WHEN 2 THEN 'SET NULL '
ELSE 'SET DEFAULT '
END
+ ' ON DELETE '
+
CASE #delete_referential_action
WHEN 0 THEN 'NO ACTION '
WHEN 1 THEN 'CASCADE '
WHEN 2 THEN 'SET NULL '
ELSE 'SET DEFAULT '
END
+
CASE #is_not_for_replication
WHEN 1 THEN ' NOT FOR REPLICATION '
ELSE ''
END
+ ';';
END;
-- PRINT #tsql
INSERT sync_createFK
(
Script
)
VALUES (
#tsql
)
-------------------Generate CHECK CONSTRAINT scripts for a database ------------------------------
----------------------------------------------------------------------------------------------------------
BEGIN
SET #tsql = 'ALTER TABLE '
+ QUOTENAME(#schema_name)
+ '.'
+ QUOTENAME(#table_name)
+
CASE #is_disabled
WHEN 0 THEN ' CHECK '
ELSE ' NOCHECK '
END
+ 'CONSTRAINT '
+ QUOTENAME(#constraint_name)
+ ';';
--PRINT #tsql;
INSERT sync_createCHECK
(
Script
)
VALUES (
#tsql
)
END;
FETCH NEXT FROM FKcursor INTO
#schema_name
, #table_name
, #constraint_name
, #referenced_object_name
, #constraint_object_id
, #is_disabled
, #is_not_for_replication
, #is_not_trusted
, #delete_referential_action
, #update_referential_action
, #referenced_schema_name;
END;
CLOSE FKcursor;
DEALLOCATE FKcursor;
--SELECT * FROM sync_DropFK
--SELECT * FROM sync_CreateFK
--SELECT * FROM sync_CreateCHECK
---------------------------------------------------------------------------
2.)
-----------------------------------------------------------------------------------------------------------------
----------------------------execute Drop FK Scripts --------------------------------------------------
DECLARE #scriptD NVARCHAR(4000)
DECLARE DropFKCursor CURSOR FOR
SELECT Script
FROM sync_dropFK WITH (NOLOCK)
OPEN DropFKCursor
FETCH NEXT FROM DropFKCursor
INTO #scriptD
WHILE ##FETCH_STATUS = 0
BEGIN
--PRINT #scriptD
EXEC (#scriptD)
FETCH NEXT FROM DropFKCursor
INTO #scriptD
END
CLOSE DropFKCursor
DEALLOCATE DropFKCursor
--------------------------------------------------------------------------------
3.)
------------------------------------------------------------------------------------------------------------------
----------------------------Truncate all tables in the database other than our staging tables --------------------
------------------------------------------------------------------------------------------------------------------
EXEC sp_MSforeachtable 'IF OBJECT_ID(''?'') NOT IN
(
ISNULL(OBJECT_ID(''dbo.sync_createCHECK''),0),
ISNULL(OBJECT_ID(''dbo.sync_createFK''),0),
ISNULL(OBJECT_ID(''dbo.sync_dropFK''),0)
)
BEGIN TRY
TRUNCATE TABLE ?
END TRY
BEGIN CATCH
PRINT ''Truncation failed on''+ ? +''
END CATCH;'
GO
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------
----------------------------execute Create FK Scripts and CHECK CONSTRAINT Scripts---------------
----------------------------tack me at the end of the ETL in a SQL task-------------------------
-------------------------------------------------------------------------------------------------
DECLARE #scriptC NVARCHAR(4000)
DECLARE CreateFKCursor CURSOR FOR
SELECT Script
FROM sync_createFK WITH (NOLOCK)
OPEN CreateFKCursor
FETCH NEXT FROM CreateFKCursor
INTO #scriptC
WHILE ##FETCH_STATUS = 0
BEGIN
--PRINT #scriptC
EXEC (#scriptC)
FETCH NEXT FROM CreateFKCursor
INTO #scriptC
END
CLOSE CreateFKCursor
DEALLOCATE CreateFKCursor
-------------------------------------------------------------------------------------------------
DECLARE #scriptCh NVARCHAR(4000)
DECLARE CreateCHECKCursor CURSOR FOR
SELECT Script
FROM sync_createCHECK WITH (NOLOCK)
OPEN CreateCHECKCursor
FETCH NEXT FROM CreateCHECKCursor
INTO #scriptCh
WHILE ##FETCH_STATUS = 0
BEGIN
--PRINT #scriptCh
EXEC (#scriptCh)
FETCH NEXT FROM CreateCHECKCursor
INTO #scriptCh
END
CLOSE CreateCHECKCursor
DEALLOCATE CreateCHECKCursor
Find the constraint
SELECT *
FROM sys.foreign_keys
WHERE referenced_object_id = object_id('TABLE_NAME')
Execute the SQL generated by this SQL
SELECT
'ALTER TABLE ' + OBJECT_SCHEMA_NAME(parent_object_id) +
'.[' + OBJECT_NAME(parent_object_id) +
'] DROP CONSTRAINT ' + name
FROM sys.foreign_keys
WHERE referenced_object_id = object_id('TABLE_NAME')
Safeway.
Note: Added solution for droping the constraint so that table can be dropped or modified without any constraint error.
Answer marked '905' looks good but does not work.
Following worked for me. Any Primary Key, Unique Key, or Default constraints CAN NOT be disabled. In fact, if 'sp_helpconstraint '' shows 'n/a' in status_enabled - Means it can NOT be enabled/disabled.
-- To generate script to DISABLE
select 'ALTER TABLE ' + object_name(id) + ' NOCHECK CONSTRAINT [' + object_name(constid) + ']'
from sys.sysconstraints
where status & 0x4813 = 0x813 order by object_name(id)
-- To generate script to ENABLE
select 'ALTER TABLE ' + object_name(id) + ' CHECK CONSTRAINT [' + object_name(constid) + ']'
from sys.sysconstraints
where status & 0x4813 = 0x813 order by object_name(id)
You should actually be able to disable foreign key constraints the same way you temporarily disable other constraints:
Alter table MyTable nocheck constraint FK_ForeignKeyConstraintName
Just make sure you're disabling the constraint on the first table listed in the constraint name. For example, if my foreign key constraint was FK_LocationsEmployeesLocationIdEmployeeId, I would want to use the following:
Alter table Locations nocheck constraint FK_LocationsEmployeesLocationIdEmployeeId
even though violating this constraint will produce an error that doesn't necessarily state that table as the source of the conflict.
Right click the table design and go to Relationships and choose the foreign key on the left-side pane and in the right-side pane, set Enforce foreign key constraint to 'Yes' (to enable foreign key constraints) or 'No' (to disable it).
One script to rule them all: this combines truncate and delete commands with sp_MSforeachtable so that you can avoid dropping and recreating constraints - just specify the tables that need to be deleted rather than truncated and for my purposes I have included an extra schema filter for good measure (tested in 2008r2)
declare #schema nvarchar(max) = 'and Schema_Id=Schema_id(''Value'')'
declare #deletiontables nvarchar(max) = '(''TableA'',''TableB'')'
declare #truncateclause nvarchar(max) = #schema + ' and o.Name not in ' + + #deletiontables;
declare #deleteclause nvarchar(max) = #schema + ' and o.Name in ' + #deletiontables;
exec sp_MSforeachtable 'alter table ? nocheck constraint all', #whereand=#schema
exec sp_MSforeachtable 'truncate table ?', #whereand=#truncateclause
exec sp_MSforeachtable 'delete from ?', #whereand=#deleteclause
exec sp_MSforeachtable 'alter table ? with check check constraint all', #whereand=#schema
You can temporarily disable constraints on your tables, do work, then rebuild them.
Here is an easy way to do it...
Disable all indexes, including the primary keys, which will disable all foreign keys, then re-enable just the primary keys so you can work with them...
DECLARE #sql AS NVARCHAR(max)=''
select #sql = #sql +
'ALTER INDEX ALL ON [' + t.[name] + '] DISABLE;'+CHAR(13)
from
sys.tables t
where type='u'
select #sql = #sql +
'ALTER INDEX ' + i.[name] + ' ON [' + t.[name] + '] REBUILD;'+CHAR(13)
from
sys.key_constraints i
join
sys.tables t on i.parent_object_id=t.object_id
where
i.type='PK'
exec dbo.sp_executesql #sql;
go
[Do something, like loading data]
Then re-enable and rebuild the indexes...
DECLARE #sql AS NVARCHAR(max)=''
select #sql = #sql +
'ALTER INDEX ALL ON [' + t.[name] + '] REBUILD;'+CHAR(13)
from
sys.tables t
where type='u'
exec dbo.sp_executesql #sql;
go
I have a more useful version if you are interested. I lifted a bit of code from here a website where the link is no longer active. I modifyied it to allow for an array of tables into the stored procedure and it populates the drop, truncate, add statements before executing all of them. This gives you control to decide which tables need truncating.
/****** Object: UserDefinedTableType [util].[typ_objects_for_managing] Script Date: 03/04/2016 16:42:55 ******/
CREATE TYPE [util].[typ_objects_for_managing] AS TABLE(
[schema] [sysname] NOT NULL,
[object] [sysname] NOT NULL
)
GO
create procedure [util].[truncate_table_with_constraints]
#objects_for_managing util.typ_objects_for_managing readonly
--#schema sysname
--,#table sysname
as
--select
-- #table = 'TABLE',
-- #schema = 'SCHEMA'
declare #exec_table as table (ordinal int identity (1,1), statement nvarchar(4000), primary key (ordinal));
--print '/*Drop Foreign Key Statements for ['+#schema+'].['+#table+']*/'
insert into #exec_table (statement)
select
'ALTER TABLE ['+SCHEMA_NAME(o.schema_id)+'].['+ o.name+'] DROP CONSTRAINT ['+fk.name+']'
from sys.foreign_keys fk
inner join sys.objects o
on fk.parent_object_id = o.object_id
where
exists (
select * from #objects_for_managing chk
where
chk.[schema] = SCHEMA_NAME(o.schema_id)
and
chk.[object] = o.name
)
;
--o.name = #table and
--SCHEMA_NAME(o.schema_id) = #schema
insert into #exec_table (statement)
select
'TRUNCATE TABLE ' + src.[schema] + '.' + src.[object]
from #objects_for_managing src
;
--print '/*Create Foreign Key Statements for ['+#schema+'].['+#table+']*/'
insert into #exec_table (statement)
select 'ALTER TABLE ['+SCHEMA_NAME(o.schema_id)+'].['+o.name+'] ADD CONSTRAINT ['+fk.name+'] FOREIGN KEY (['+c.name+'])
REFERENCES ['+SCHEMA_NAME(refob.schema_id)+'].['+refob.name+'](['+refcol.name+'])'
from sys.foreign_key_columns fkc
inner join sys.foreign_keys fk
on fkc.constraint_object_id = fk.object_id
inner join sys.objects o
on fk.parent_object_id = o.object_id
inner join sys.columns c
on fkc.parent_column_id = c.column_id and
o.object_id = c.object_id
inner join sys.objects refob
on fkc.referenced_object_id = refob.object_id
inner join sys.columns refcol
on fkc.referenced_column_id = refcol.column_id and
fkc.referenced_object_id = refcol.object_id
where
exists (
select * from #objects_for_managing chk
where
chk.[schema] = SCHEMA_NAME(o.schema_id)
and
chk.[object] = o.name
)
;
--o.name = #table and
--SCHEMA_NAME(o.schema_id) = #schema
declare #looper int , #total_records int, #sql_exec nvarchar(4000)
select #looper = 1, #total_records = count(*) from #exec_table;
while #looper <= #total_records
begin
select #sql_exec = (select statement from #exec_table where ordinal =#looper)
exec sp_executesql #sql_exec
print #sql_exec
set #looper = #looper + 1
end
You can easily turn of CONSTRAINT using :
ALTER TABLE TableName NOCHECK CONSTRAINT ALL
After you finish the transaction do not forget to turn them on again using:
ALTER TABLE TableName CHECK CONSTRAINT ALL

Resources