procedure to drop system-versioned temporal tables - sql-server

I'm looking for a procedure to drop system-versioned temporal tables, ideally without using dynamic SQL. I've looked through the Microsoft documentation and figured out how to get the autogenerated history table name, but I only know a little about cursors and even less about dynamic SQL.
You can't just drop a temporal table. You must first disable versioning, which will cause the history table to become an ordinary table. Then you can drop both the temporal table and its corresponding history table.
ALTER TABLE [dbo].[TemporalTest] SET ( SYSTEM_VERSIONING = OFF )
GO
DROP TABLE [dbo].[TemporalTest]
GO
DROP TABLE [dbo].[TemporalTestHistory]
GO
I am using temporal tables with autogenerated history tables, so I don't know their names. However, the Microsoft docs provide information about how to list the history tables, so I have a way of getting those names.
select schema_name(t.schema_id) as temporal_table_schema,
t.name as temporal_table_name,
schema_name(h.schema_id) as history_table_schema,
h.name as history_table_name,
case when t.history_retention_period = -1
then 'INFINITE'
else cast(t.history_retention_period as varchar) + ' ' +
t.history_retention_period_unit_desc + 'S'
end as retention_period
from sys.tables t
left outer join sys.tables h
on t.history_table_id = h.object_id
where t.temporal_type = 2
order by temporal_table_schema, temporal_table_name
I was hoping I could use a subquery with the DROP statement, e.g. DROP TABLE (SELECT '#t'). This throws a syntax error.
I'm looking for a stored procedure which takes two parameters: the name of the table to be dropped and whether the drop should take place if there's any data in the table (eg, must ROWCOUNT=0). Can anyone help, or recommend cursors over Dynamic SQL, or recommend another technique? Thanks!

You can't issue DDL against data (like the output of a subquery), or pass an entity name as a variable to a statement; you need dynamic SQL.
CREATE PROCEDURE dbo.DropTemporalTable
#schema sysname = N'dbo',
#table sysname
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql nvarchar(max) = N'';
SELECT #sql += N'ALTER TABLE ' + src + N' SET (SYSTEM_VERSIONING = OFF);
DROP TABLE ' + src + N';
DROP TABLE ' + hist + N';'
FROM
(
SELECT src = QUOTENAME(SCHEMA_NAME(t.schema_id))
+ N'.' + QUOTENAME(t.name),
hist = QUOTENAME(SCHEMA_NAME(h.schema_id))
+ N'.' + QUOTENAME(h.name)
FROM sys.tables AS t
INNER JOIN sys.tables AS h
ON t.history_table_id = h.[object_id]
WHERE t.temporal_type = 2
AND t.[schema_id] = SCHEMA_ID(#schema)
AND t.name = #table
) AS x;
EXEC sys.sp_executesql #sql;
END
GO

I am using temporal tables with autogenerated history tables, so I
don't know their names. However, the Microsoft docs provide
information about how to list the history tables, so I have a way of
getting those names.
I don't know if you know this but you can specify the name of the history table in several ways.
If you create your own history table:
ALTER TABLE [TemporalTable] SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[HistoryTable]))
Or if you want your history table created for you:
CREATE TABLE [dbo].[TemporalTable](
[Id] UNIQUEIDENTIFIER NOT NULL CONSTRAINT [DF_TemporalTable_Id] DEFAULT(NEWID()),
[SysStartTime] DATETIME2(2) GENERATED ALWAYS AS ROW START NOT NULL CONSTRAINT [DF_TemporalTable_SysStartTime] DEFAULT(SYSUTCDATETIME()),
[SysEndTime] DATETIME2(2) GENERATED ALWAYS AS ROW END NOT NULL CONSTRAINT [DF_TemporalTable_SysEndTime] DEFAULT(CONVERT(DATETIME2(2),'9999-12-31 23:59:59.99')),
CONSTRAINT [PK_Product] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY],
PERIOD FOR SYSTEM_TIME ([SysStartTime], [SysEndTime])
) ON [PRIMARY]
WITH
(
SYSTEM_VERSIONING = ON ( HISTORY_TABLE = [dbo].[HistoryTable] )
)
Other than that I don't know of a way to create a stored procedure which takes a table name as a parameter and drops it without using dynamic SQL. Something like below will be necessary. Depending on if you want the stored procedure to look up the name of the history table linked to it you can add the query you mentioned in your post instead of a parameter.
CREATE PROCEDURE DeleteTemporalTable (#tableName NVARCHAR(MAX), #historyTableName) AS
BEGIN
EXEC ('
IF EXISTS (
SELECT
1
FROM
SYSOBJECTS
WHERE
id = OBJECT_ID(N''[dbo].[' + #tableName + ']'') AND
OBJECTPROPERTY(id, N''IsTable'') = 1 AND
OBJECTPROPERTY(id, N''TableTemporalType'') = 2
)
BEGIN
ALTER TABLE [dbo].[' + #tableName + '] SET (SYSTEM_VERSIONING = OFF)
END
DROP TABLE IF EXISTS [dbo].[' + #tableName + ']
DROP TABLE IF EXISTS [dbo].[' + #historyTableName + ']')
END
If you're just looking for a way to delete all tables, and you want something that works with temporal tables, this is a script I use:
DECLARE #temporalTableName varchar(max) = (SELECT TOP 1 [name] FROM sys.tables WHERE [temporal_type_desc] = 'SYSTEM_VERSIONED_TEMPORAL_TABLE')
WHILE #temporalTableName IS NOT NULL
BEGIN
EXEC('ALTER TABLE [dbo].[' + #temporalTableName + '] SET (SYSTEM_VERSIONING = OFF)')
SET #temporalTableName = (SELECT TOP 1 [name] FROM sys.tables WHERE [temporal_type_desc] = 'SYSTEM_VERSIONED_TEMPORAL_TABLE')
END
DECLARE #tableName varchar(max) = (SELECT TOP 1 [name] FROM sys.tables)
WHILE #tableName IS NOT NULL
BEGIN
EXEC('DROP TABLE [dbo].[' + #tableName + ']')
SET #tableName = (SELECT TOP 1 [name] FROM sys.tables)
END

I've adapted Aaron's answer. Here's final solution:
CREATE OR ALTER PROCEDURE [dbo].[DropTemporalTable]
#t as nvarchar(max),
#s as nvarchar(max) = 'dbo'
-- See https://stackoverflow.com/questions/55522278/procedure-to-drop-system-versioned-temporal-tables/55524067#55524067
AS
BEGIN
-- TODO: check if src table is empty first
DECLARE #sql nvarchar(max) = N'';
SELECT #sql += N'ALTER TABLE ' + src + N' SET (SYSTEM_VERSIONING = OFF);
DROP TABLE ' + src + N';
DROP TABLE ' + hist + N';
'
FROM
(
SELECT src = QUOTENAME(SCHEMA_NAME(t.schema_id))
+ N'.' + QUOTENAME(t.name),
hist = QUOTENAME(SCHEMA_NAME(h.schema_id))
+ N'.' + QUOTENAME(h.name)
FROM sys.tables AS t
INNER JOIN sys.tables AS h
ON t.history_table_id = h.[object_id]
WHERE t.temporal_type = 2 AND t.name=#t AND t.schema_id=SCHEMA_ID(#s)
) AS x;
PRINT #sql;
--EXEC sys.sp_executesql #sql;
END

/****** Object: Table [Intake].[MER_SF_Asset_Temporal] Script Date: 04/05/2021 12:33:57 PM ******/
ALTER TABLE [Intake].[MER_SF_Asset_Temporal] SET ( SYSTEM_VERSIONING = OFF )
GO
/****** Object: Table [Intake].[MER_SF_Asset_Temporal] Script Date: 04/05/2021 12:33:57 PM ******/
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Intake].[MER_SF_Asset_Temporal]') AND type in (N'U'))
DROP TABLE [Intake].[MER_SF_Asset_Temporal]
GO
/****** Object: Table [Intake].[MERSFAssetTemporalHistory] Script Date: 04/05/2021 12:33:58 PM ******/
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Intake].[MERSFAssetTemporalHistory]') AND type in (N'U'))
DROP TABLE [Intake].[MERSFAssetTemporalHistory]
GO

Related

Delete data from all tables except master tables with foreign key contraints in SQL Azure

I have 70+ tables in my azure sql database. I want to delete data from all these tables except some by bypassing the foriegn keys. Is there any script available to do the same because some table may have complex and long foreign key relationships.
I have gone through several links but not getting exact solution to automate this process.
Does anyone know how I could proceed?
Sample data:
Here I have Employee and Customer as master table and other tables are my child tables before truncating child table you need to drop the foreign key constraints otherwise you will face this error.
You can use dynamic SQL script to perform this sample script
--Get the list of all the tables to be truncated
DECLARE #TablesToBeTruncated AS TABLE
(Id INT IDENTITY(1,1),TableObjectId INT, TableName SYSNAME,
SchemaId INT)
INSERT INTO #TablesToBeTruncated
SELECT Sf.referenced_object_id ,So.name , so.schema_id
FROM sys.foreign_keys Sf
join sys.objects so on sf.referenced_object_id = so.object_id
WHERE So.type = 'U'
--Generate the foreignkeys drop
DECLARE #CreateScript AS NVARCHAR(MAX), #DropScript AS NVARCHAR(MAX)
SELECT
------------DROP SCRIPT--------------------
#DropScript = ISNULL(#DropScript,'') + 'ALTER TABLE ' + QUOTENAME(SCHEMA_NAME(Tlist.SchemaId)) + '.'
+ QUOTENAME(OBJECT_NAME(FKey.parent_object_id)) + ' DROP CONSTRAINT ' + QUOTENAME(FKey.name)
+ CHAR(10)
FROM #TablesToBeTruncated Tlist
INNER JOIN SYS.FOREIGN_KEYS FKey
ON Tlist.TableObjectId = FKey.referenced_object_id
--PRINT THE TRUNCATION SCRIPT
IF LEN(ISNULL(#DropScript,'')) > 0
BEGIN
PRINT CHAR(10) + ' GO ' + CHAR(10) + '--------DROP FOREIGN KEY CONSTRAINTS SCRIPT--------'
PRINT #DropScript + CHAR(10) + ' GO ' + CHAR(10)
EXEC(#DropScript)
END
PRINT '--------TRUNCATE TABLES SCRIPT--------'
--TRUNCATE TABLES
DECLARE #id INT,#truncatescript NVARCHAR(MAX)
SELECT #id = MIN(Id)FROM #TablesToBeTruncated
WHILE #id is not null
BEGIN
SELECT #truncatescript = 'TRUNCATE TABLE ' + QUOTENAME(SCHEMA_NAME(SchemaId)) + '.' + QUOTENAME(TableName)
FROM #TablesToBeTruncated WHERE Id = #id
PRINT #truncatescript
EXEC(#truncatescript)
SELECT #id = MIN(Id)FROM #TablesToBeTruncated WHERE Id > #id
END
Output:

SQL Server delete all tables under special schema with temporal tables

I'm trying to delete a database scheme with temporal tables.
Non of the existing scripts found through googling, supports temporal tables.
Is there anyone already done this?
There are many temporal tables on that scheme with many constraints with dependencies. so when I try to drop the scheme it complain about dependencies.
Basically I'm looking for a stored procedure or something that go through all the DB objects and remove one by one.
Script to Create sample tables
USE [master];
GO
CREATE DATABASE [TestDb];
GO
USE [TestDb];
GO
CREATE SCHEMA [TestScheme];
GO
SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
CREATE TABLE [TestScheme].[Country]
(
[CountryCode] [char](2) NOT NULL,
[Country] [varchar](60) NOT NULL,
[ValidFrom] [datetime2](2) GENERATED ALWAYS AS ROW START NOT NULL,
[ValidTo] [datetime2](2) GENERATED ALWAYS AS ROW END NOT NULL,
CONSTRAINT [PK_TestScheme_Country_CountryCode]
PRIMARY KEY CLUSTERED([CountryCode] ASC)
WITH (PAD_INDEX = ON, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 95) ON [PRIMARY],
PERIOD FOR SYSTEM_TIME([ValidFrom], [ValidTo])
) ON [PRIMARY]
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [TestScheme].[CountryHistory]));
GO
SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
CREATE TABLE [TestScheme].[Address]
(
[AddressId] [int] IDENTITY(1, 1) NOT NULL,
[City] [varchar](100) NOT NULL,
[CountryCode] [char](2) NOT NULL,
[ValidFrom] [datetime2](7) GENERATED ALWAYS AS ROW START NOT NULL,
[ValidTo] [datetime2](7) GENERATED ALWAYS AS ROW END NOT NULL,
CONSTRAINT [PK_TestScheme_Address_AddressId]
PRIMARY KEY CLUSTERED([AddressId] ASC)
WITH (PAD_INDEX = ON, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY],
PERIOD FOR SYSTEM_TIME([ValidFrom], [ValidTo])
)
ON [PRIMARY]
WITH (SYSTEM_VERSIONING = ON(HISTORY_TABLE = [TestScheme].[AddressHistory]));
GO
ALTER TABLE [TestScheme].[Address] WITH CHECK
ADD CONSTRAINT [FK_TestScheme_CountryCode]
FOREIGN KEY([CountryCode]) REFERENCES [TestScheme].[Country]([CountryCode]);
GO
ALTER TABLE [TestScheme].[Address] CHECK CONSTRAINT [FK_TestScheme_CountryCode];
GO
Query to drop scheme:
USE [TestDb];
GO
DROP SCHEMA [TestScheme];
GO
Query to delete table:
USE [TestDb]
GO
ALTER TABLE [TestScheme].[Country] SET (SYSTEM_VERSIONING = OFF)
GO
IF EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[TestScheme].[Country]') AND type in (N'U'))
DROP TABLE [TestScheme].[Country]
GO
IF EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[TestScheme].[CountryHistory]') AND type in (N'U'))
DROP TABLE [TestScheme].[CountryHistory]
GO
So the problem is there are many DB objects that I really don't want to create a huge script to delete one by one.
Thanks!
Thanks every one, following is the script I created and it worked for me.
USE TestDb;
GO
DECLARE #SchemeName varchar(50)= 'TestScheme';
DECLARE #DatabaseName varchar(50)= 'TestDb';
DECLARE #sql nvarchar(max)= '';
/*Removing versioning on temporal tables*/
WITH selectedTables
AS (SELECT concat('[', #DatabaseName, '].[', #SchemeName, '].[', name, ']') AS TableName
FROM SYS.TABLES WHERE history_table_id IS NOT NULL AND SCHEMA_NAME(schema_id) = #SchemeName)
SELECT #sql = COALESCE(#sql, N'') + 'ALTER TABLE ' + TableName + ' SET ( SYSTEM_VERSIONING = OFF );'
FROM selectedTables;
SELECT #sql;
EXEC sp_executesql #sql;
/*Remove constraints*/
SET #sql = N'';
SELECT #sql = COALESCE(#sql, N'') + 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' ) AND s.name = #SchemeName
ORDER BY c.[type];
SELECT #sql;
EXEC sp_executesql #sql;
/*Delete Tables*/
SET #sql = N'';
SELECT #sql = COALESCE(#sql, N'') + N'DROP TABLE ['+#SchemeName+'].' + QUOTENAME(TABLE_NAME) + N';' + CHAR(13)
FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = #SchemeName AND TABLE_TYPE = 'BASE TABLE';
SELECT #sql
EXEC sp_executesql #sql;
/*Drop scheme*/
SET #sql = N'';
SELECT #sql = COALESCE(#sql, N'') + N'DROP SCHEMA IF EXISTS ' + #SchemeName + ';' + CHAR(13);
SELECT #sql
EXEC sp_executesql #sql;
GO
Thanks again!

How to drop column with constraint?

How to drop a column which is having Default constraint in SQL Server 2008?
My query is
alter table tbloffers
drop column checkin
I am getting below error
ALTER TABLE DROP COLUMN checkin failed because one or more objects access this column.
Can anyone correct my query to drop a column with constraint?
First you should drop the problematic DEFAULT constraint, after that you can drop the column
alter table tbloffers drop constraint [ConstraintName]
go
alter table tbloffers drop column checkin
But the error may appear from other reasons - for example the user defined function or view with SCHEMABINDING option set for them.
UPD:
Completely automated dropping of constraints script:
DECLARE #sql NVARCHAR(MAX)
WHILE 1=1
BEGIN
SELECT TOP 1 #sql = N'alter table tbloffers drop constraint ['+dc.NAME+N']'
from sys.default_constraints dc
JOIN sys.columns c
ON c.default_object_id = dc.object_id
WHERE
dc.parent_object_id = OBJECT_ID('tbloffers')
AND c.name = N'checkin'
IF ##ROWCOUNT = 0 BREAK
EXEC (#sql)
END
Here's another way to drop a default constraint with an unknown name without having to first run a separate query to get the constraint name:
DECLARE #ConstraintName nvarchar(200)
SELECT #ConstraintName = Name FROM SYS.DEFAULT_CONSTRAINTS
WHERE PARENT_OBJECT_ID = OBJECT_ID('__TableName__')
AND PARENT_COLUMN_ID = (SELECT column_id FROM sys.columns
WHERE NAME = N'__ColumnName__'
AND object_id = OBJECT_ID(N'__TableName__'))
IF #ConstraintName IS NOT NULL
EXEC('ALTER TABLE __TableName__ DROP CONSTRAINT ' + #ConstraintName)
You can also drop the column and its constraint(s) in a single statement rather than individually.
CREATE TABLE #T
(
Col1 INT CONSTRAINT UQ UNIQUE CONSTRAINT CK CHECK (Col1 > 5),
Col2 INT
)
ALTER TABLE #T DROP CONSTRAINT UQ ,
CONSTRAINT CK,
COLUMN Col1
DROP TABLE #T
Some dynamic SQL that will look up the names of dependent check constraints and default constraints and drop them along with the column is below
(but not other possible column dependencies such as foreign keys, unique and primary key constraints, computed columns, indexes)
CREATE TABLE [dbo].[TestTable]
(
A INT DEFAULT '1' CHECK (A=1),
B INT,
CHECK (A > B)
)
GO
DECLARE #TwoPartTableNameQuoted nvarchar(500) = '[dbo].[TestTable]',
#ColumnNameUnQuoted sysname = 'A',
#DynSQL NVARCHAR(MAX);
SELECT #DynSQL =
'ALTER TABLE ' + #TwoPartTableNameQuoted + ' DROP' +
ISNULL(' CONSTRAINT ' + QUOTENAME(OBJECT_NAME(c.default_object_id)) + ',','') +
ISNULL(check_constraints,'') +
' COLUMN ' + QUOTENAME(#ColumnNameUnQuoted)
FROM sys.columns c
CROSS APPLY (SELECT ' CONSTRAINT ' + QUOTENAME(OBJECT_NAME(referencing_id)) + ','
FROM sys.sql_expression_dependencies
WHERE referenced_id = c.object_id
AND referenced_minor_id = c.column_id
AND OBJECTPROPERTYEX(referencing_id, 'BaseType') = 'C'
FOR XML PATH('')) ck(check_constraints)
WHERE c.object_id = object_id(#TwoPartTableNameQuoted)
AND c.name = #ColumnNameUnQuoted;
PRINT #DynSQL;
EXEC (#DynSQL);
Find the default constraint with this query here:
SELECT
df.name 'Constraint Name' ,
t.name 'Table Name',
c.NAME 'Column Name'
FROM sys.default_constraints df
INNER JOIN sys.tables t ON df.parent_object_id = t.object_id
INNER JOIN sys.columns c ON df.parent_object_id = c.object_id AND df.parent_column_id = c.column_id
This gives you the name of the default constraint, as well as the table and column name.
When you have that information you need to first drop the default constraint:
ALTER TABLE dbo.YourTable
DROP CONSTRAINT name-of-the-default-constraint-here
and then you can drop the column
ALTER TABLE dbo.YourTable DROP COLUMN YourColumn
The following worked for me against a SQL Azure backend (using SQL Server Management Studio), so YMMV, but, if it works for you, it's waaaaay simpler than the other solutions.
ALTER TABLE MyTable
DROP CONSTRAINT FK_MyColumn
CONSTRAINT DK_MyColumn
-- etc...
COLUMN MyColumn
GO
Based on the previous answers, I have added it as a stored procedure to simplify the deletion of a column when it has attached constraints
CREATE OR ALTER PROC DROP_COLUMN(#TableName nvarchar(200), #ColumnName nvarchar(200))
AS
BEGIN
DECLARE #ConstraintName nvarchar(200)
SELECT #ConstraintName = Name FROM SYS.DEFAULT_CONSTRAINTS
WHERE PARENT_OBJECT_ID = OBJECT_ID(#TableName)
AND PARENT_COLUMN_ID = (SELECT column_id FROM sys.columns
WHERE NAME = #ColumnName
AND object_id = OBJECT_ID(#TableName))
IF #ConstraintName IS NOT NULL
EXEC('ALTER TABLE '+#TableName+' DROP CONSTRAINT ' + #ConstraintName)
EXEC('ALTER TABLE '+#TableName+' DROP COLUMN IF EXISTS ' + #ColumnName)
END
GO
--example:
EXEC DROP_COLUMN N'VEHICLES', N'SCMT'
EXEC DROP_COLUMN N'VEHICLES', N'SSC'
EXEC DROP_COLUMN N'VEHICLES', N'RS'
EXEC DROP_COLUMN N'VEHICLES', N'RCEC'
DROP PROCEDURE IF EXISTS DROP_COLUMN
I got the same:
ALTER TABLE DROP COLUMN failed because one or more objects access this column message.
My column had an index which needed to be deleted first. Using sys.indexes did the trick:
DECLARE #sql VARCHAR(max)
SELECT #sql = 'DROP INDEX ' + idx.NAME + ' ON tblName'
FROM sys.indexes idx
INNER JOIN sys.tables tbl ON idx.object_id = tbl.object_id
INNER JOIN sys.index_columns idxCol ON idx.index_id = idxCol.index_id
INNER JOIN sys.columns col ON idxCol.column_id = col.column_id
WHERE idx.type <> 0
AND tbl.NAME = 'tblName'
AND col.NAME = 'colName'
EXEC sp_executeSql #sql
GO
ALTER TABLE tblName
DROP COLUMN colName
I have updated script a little bit to my SQL server version
DECLARE #sql nvarchar(max)
SELECT #sql = 'ALTER TABLE `table_name` DROP CONSTRAINT ' + df.NAME
FROM sys.default_constraints df
INNER JOIN sys.tables t ON df.parent_object_id = t.object_id
INNER JOIN sys.columns c ON df.parent_object_id = c.object_id AND df.parent_column_id = c.column_id
where t.name = 'table_name' and c.name = 'column_name'
EXEC sp_executeSql #sql
GO
ALTER TABLE table_name
DROP COLUMN column_name;
It's not always just a default constraint that prevents from droping a column and sometimes indexes can also block you from droping the constraint.
So I wrote a procedure that drops any index or constraint on a column and the column it self at the end.
IF OBJECT_ID ('ADM_delete_column', 'P') IS NOT NULL
DROP procedure ADM_delete_column;
GO
CREATE procedure ADM_delete_column
#table_name_in nvarchar(300)
, #column_name_in nvarchar(300)
AS
BEGIN
/* Author: Matthis (matthis#online.ms at 2019.07.20)
License CC BY (creativecommons.org)
Desc: Administrative procedure that drops columns at MS SQL Server
- if there is an index or constraint on the column
that will be dropped in advice
=> input parameters are TABLE NAME and COLUMN NAME as STRING
*/
SET NOCOUNT ON
--drop index if exist (search first if there is a index on the column)
declare #idx_name VARCHAR(100)
SELECT top 1 #idx_name = i.name
from sys.tables t
join sys.columns c
on t.object_id = c.object_id
join sys.index_columns ic
on c.object_id = ic.object_id
and c.column_id = ic.column_id
join sys.indexes i
on i.object_id = ic.object_id
and i.index_id = ic.index_id
where t.name like #table_name_in
and c.name like #column_name_in
if #idx_name is not null
begin
print concat('DROP INDEX ', #idx_name, ' ON ', #table_name_in)
exec ('DROP INDEX ' + #idx_name + ' ON ' + #table_name_in)
end
--drop fk constraint if exist (search first if there is a constraint on the column)
declare #fk_name VARCHAR(100)
SELECT top 1 #fk_name = CONSTRAINT_NAME
from INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE
where TABLE_NAME like #table_name_in
and COLUMN_NAME like #column_name_in
if #fk_name is not null
begin
print concat('ALTER TABLE ', #table_name_in, ' DROP CONSTRAINT ', #fk_name)
exec ('ALTER TABLE ' + #table_name_in + ' DROP CONSTRAINT ' + #fk_name)
end
--drop column if exist
declare #column_name VARCHAR(100)
SELECT top 1 #column_name = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME like concat('%',#column_name_in,'%')
if #column_name is not null
begin
print concat('ALTER TABLE ', #table_name_in, ' DROP COLUMN ', #column_name)
exec ('ALTER TABLE ' + #table_name_in + ' DROP COLUMN ' + #column_name)
end
end;
GO
--to run the procedure use this execute and fill the parameters
execute ADM_delete_column
#table_name_in = ''
, #column_name_in = ''
;

Cannot truncate table because it is being referenced by a FOREIGN KEY constraint?

Using MSSQL2005, can I truncate a table with a foreign key constraint if I first truncate the child table (the table with the primary key of the FK relationship)?
I know that I can either
Use a DELETE without a where clause and then RESEED the identity (or)
Remove the FK, truncate the table, and recreate the FK.
I thought that as long as I truncated the child table before the parent, I'd be okay without doing either of the options above, but I'm getting this error:
Cannot truncate table 'TableName' because it is being referenced by a FOREIGN KEY constraint.
DELETE FROM TABLENAME
DBCC CHECKIDENT ('DATABASENAME.dbo.TABLENAME', RESEED, 0)
Note that this isn't probably what you'd want if you have millions+ of records, as it's very slow.
Correct; you cannot truncate a table which has an FK constraint on it.
Typically my process for this is:
Drop the constraints
Trunc the table
Recreate the constraints.
(All in a transaction, of course.)
Of course, this only applies if the child has already been truncated. Otherwise I go a different route, dependent entirely on what my data looks like. (Too many variables to get into here.)
The original poster determined WHY this is the case; see this answer for more details.
Because TRUNCATE TABLE is a DDL command, it cannot check to see whether the records in the table are being referenced by a record in the child table.
This is why DELETE works and TRUNCATE TABLE doesn't: because the database is able to make sure that it isn't being referenced by another record.
Without ALTER TABLE
-- Delete all records
DELETE FROM [TableName]
-- Set current ID to "1"
-- If table already contains data, use "0"
-- If table is empty and never insert data, use "1"
-- Use SP https://github.com/reduardo7/TableTruncate
DBCC CHECKIDENT ([TableName], RESEED, 0)
As Stored Procedure
https://github.com/reduardo7/TableTruncate
Note that this isn't probably what you'd want if you have millions+ of records, as it's very slow.
The solution #denver_citizen provided above did not work for me, but I liked the spirit of it so I modified a few things :
made it a stored procedure
changed the way the foreign keys are populated and recreated
the original script truncates all referenced tables, this can cause foreign key violation error when the referenced table has other foreign key references. This script truncates only the table specified as parameter. It is up to the user, to call this stored procedure multiple times on all tables in the correct order
For the benefit of the public here is the updated script :
CREATE PROCEDURE [dbo].[truncate_non_empty_table]
#TableToTruncate VARCHAR(64)
AS
BEGIN
SET NOCOUNT ON
-- GLOBAL VARIABLES
DECLARE #i int
DECLARE #Debug bit
DECLARE #Recycle bit
DECLARE #Verbose bit
DECLARE #TableName varchar(80)
DECLARE #ColumnName varchar(80)
DECLARE #ReferencedTableName varchar(80)
DECLARE #ReferencedColumnName varchar(80)
DECLARE #ConstraintName varchar(250)
DECLARE #CreateStatement varchar(max)
DECLARE #DropStatement varchar(max)
DECLARE #TruncateStatement varchar(max)
DECLARE #CreateStatementTemp varchar(max)
DECLARE #DropStatementTemp varchar(max)
DECLARE #TruncateStatementTemp varchar(max)
DECLARE #Statement varchar(max)
-- 1 = Will not execute statements
SET #Debug = 0
-- 0 = Will not create or truncate storage table
-- 1 = Will create or truncate storage table
SET #Recycle = 0
-- 1 = Will print a message on every step
set #Verbose = 1
SET #i = 1
SET #CreateStatement = 'ALTER TABLE [dbo].[<tablename>] WITH NOCHECK ADD CONSTRAINT [<constraintname>] FOREIGN KEY([<column>]) REFERENCES [dbo].[<reftable>] ([<refcolumn>])'
SET #DropStatement = 'ALTER TABLE [dbo].[<tablename>] DROP CONSTRAINT [<constraintname>]'
SET #TruncateStatement = 'TRUNCATE TABLE [<tablename>]'
-- Drop Temporary tables
IF OBJECT_ID('tempdb..#FKs') IS NOT NULL
DROP TABLE #FKs
-- GET FKs
SELECT ROW_NUMBER() OVER (ORDER BY OBJECT_NAME(parent_object_id), clm1.name) as ID,
OBJECT_NAME(constraint_object_id) as ConstraintName,
OBJECT_NAME(parent_object_id) as TableName,
clm1.name as ColumnName,
OBJECT_NAME(referenced_object_id) as ReferencedTableName,
clm2.name as ReferencedColumnName
INTO #FKs
FROM sys.foreign_key_columns fk
JOIN sys.columns clm1
ON fk.parent_column_id = clm1.column_id
AND fk.parent_object_id = clm1.object_id
JOIN sys.columns clm2
ON fk.referenced_column_id = clm2.column_id
AND fk.referenced_object_id= clm2.object_id
--WHERE OBJECT_NAME(parent_object_id) not in ('//tables that you do not wont to be truncated')
WHERE OBJECT_NAME(referenced_object_id) = #TableToTruncate
ORDER BY OBJECT_NAME(parent_object_id)
-- Prepare Storage Table
IF Not EXISTS(SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Internal_FK_Definition_Storage')
BEGIN
IF #Verbose = 1
PRINT '1. Creating Process Specific Tables...'
-- CREATE STORAGE TABLE IF IT DOES NOT EXISTS
CREATE TABLE [Internal_FK_Definition_Storage]
(
ID int not null identity(1,1) primary key,
FK_Name varchar(250) not null,
FK_CreationStatement varchar(max) not null,
FK_DestructionStatement varchar(max) not null,
Table_TruncationStatement varchar(max) not null
)
END
ELSE
BEGIN
IF #Recycle = 0
BEGIN
IF #Verbose = 1
PRINT '1. Truncating Process Specific Tables...'
-- TRUNCATE TABLE IF IT ALREADY EXISTS
TRUNCATE TABLE [Internal_FK_Definition_Storage]
END
ELSE
PRINT '1. Process specific table will be recycled from previous execution...'
END
IF #Recycle = 0
BEGIN
IF #Verbose = 1
PRINT '2. Backing up Foreign Key Definitions...'
-- Fetch and persist FKs
WHILE (#i <= (SELECT MAX(ID) FROM #FKs))
BEGIN
SET #ConstraintName = (SELECT ConstraintName FROM #FKs WHERE ID = #i)
SET #TableName = (SELECT TableName FROM #FKs WHERE ID = #i)
SET #ColumnName = (SELECT ColumnName FROM #FKs WHERE ID = #i)
SET #ReferencedTableName = (SELECT ReferencedTableName FROM #FKs WHERE ID = #i)
SET #ReferencedColumnName = (SELECT ReferencedColumnName FROM #FKs WHERE ID = #i)
SET #DropStatementTemp = REPLACE(REPLACE(#DropStatement,'<tablename>',#TableName),'<constraintname>',#ConstraintName)
SET #CreateStatementTemp = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#CreateStatement,'<tablename>',#TableName),'<column>',#ColumnName),'<constraintname>',#ConstraintName),'<reftable>',#ReferencedTableName),'<refcolumn>',#ReferencedColumnName)
SET #TruncateStatementTemp = REPLACE(#TruncateStatement,'<tablename>',#TableName)
INSERT INTO [Internal_FK_Definition_Storage]
SELECT #ConstraintName, #CreateStatementTemp, #DropStatementTemp, #TruncateStatementTemp
SET #i = #i + 1
IF #Verbose = 1
PRINT ' > Backing up [' + #ConstraintName + '] from [' + #TableName + ']'
END
END
ELSE
PRINT '2. Backup up was recycled from previous execution...'
IF #Verbose = 1
PRINT '3. Dropping Foreign Keys...'
-- DROP FOREING KEYS
SET #i = 1
WHILE (#i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
BEGIN
SET #ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = #i)
SET #Statement = (SELECT FK_DestructionStatement FROM [Internal_FK_Definition_Storage] WITH (NOLOCK) WHERE ID = #i)
IF #Debug = 1
PRINT #Statement
ELSE
EXEC(#Statement)
SET #i = #i + 1
IF #Verbose = 1
PRINT ' > Dropping [' + #ConstraintName + ']'
END
IF #Verbose = 1
PRINT '4. Truncating Tables...'
-- TRUNCATE TABLES
-- SzP: commented out as the tables to be truncated might also contain tables that has foreign keys
-- to resolve this the stored procedure should be called recursively, but I dont have the time to do it...
/*
SET #i = 1
WHILE (#i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
BEGIN
SET #Statement = (SELECT Table_TruncationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = #i)
IF #Debug = 1
PRINT #Statement
ELSE
EXEC(#Statement)
SET #i = #i + 1
IF #Verbose = 1
PRINT ' > ' + #Statement
END
*/
IF #Verbose = 1
PRINT ' > TRUNCATE TABLE [' + #TableToTruncate + ']'
IF #Debug = 1
PRINT 'TRUNCATE TABLE [' + #TableToTruncate + ']'
ELSE
EXEC('TRUNCATE TABLE [' + #TableToTruncate + ']')
IF #Verbose = 1
PRINT '5. Re-creating Foreign Keys...'
-- CREATE FOREING KEYS
SET #i = 1
WHILE (#i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
BEGIN
SET #ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = #i)
SET #Statement = (SELECT FK_CreationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = #i)
IF #Debug = 1
PRINT #Statement
ELSE
EXEC(#Statement)
SET #i = #i + 1
IF #Verbose = 1
PRINT ' > Re-creating [' + #ConstraintName + ']'
END
IF #Verbose = 1
PRINT '6. Process Completed'
END
use the following command after deletion of all rows in that table by using delete statement
delete from tablename
DBCC CHECKIDENT ('tablename', RESEED, 0)
EDIT: Corrected syntax for SQL Server
Well, since I did not find examples of the very simple solution I used, which is:
Drop foreign key;
Truncate table
Recreate foreign key
Here it goes:
1) Find the foreign key name that is causing the failure (for example: FK_PROBLEM_REASON, with field ID, from table TABLE_OWNING_CONSTRAINT)
2) Remove that key from the table:
ALTER TABLE TABLE_OWNING_CONSTRAINT DROP CONSTRAINT FK_PROBLEM_REASON
3) Truncate wanted table
TRUNCATE TABLE TABLE_TO_TRUNCATE
4) Re-add the key to that first table:
ALTER TABLE TABLE_OWNING_CONSTRAINT ADD CONSTRAINT FK_PROBLEM_REASON FOREIGN KEY(ID) REFERENCES TABLE_TO_TRUNCATE (ID)
That's it.
The process is removing foreign key constraint and truncate table
then add constrain by following steps.
This is Just for MySQL
SET FOREIGN_KEY_CHECKS = 0;
truncate table "yourTableName";
SET FOREIGN_KEY_CHECKS = 1;
you can follow this step,
By reseeding table you can delete the data of the table.
delete from table_name
dbcc checkident('table_name',reseed,0)
if some error comes then you have to reseed the primary table.
Here is a script I wrote in order to automate the process. I hope it helps.
SET NOCOUNT ON
-- GLOBAL VARIABLES
DECLARE #i int
DECLARE #Debug bit
DECLARE #Recycle bit
DECLARE #Verbose bit
DECLARE #TableName varchar(80)
DECLARE #ColumnName varchar(80)
DECLARE #ReferencedTableName varchar(80)
DECLARE #ReferencedColumnName varchar(80)
DECLARE #ConstraintName varchar(250)
DECLARE #CreateStatement varchar(max)
DECLARE #DropStatement varchar(max)
DECLARE #TruncateStatement varchar(max)
DECLARE #CreateStatementTemp varchar(max)
DECLARE #DropStatementTemp varchar(max)
DECLARE #TruncateStatementTemp varchar(max)
DECLARE #Statement varchar(max)
-- 1 = Will not execute statements
SET #Debug = 0
-- 0 = Will not create or truncate storage table
-- 1 = Will create or truncate storage table
SET #Recycle = 0
-- 1 = Will print a message on every step
set #Verbose = 1
SET #i = 1
SET #CreateStatement = 'ALTER TABLE [dbo].[<tablename>] WITH NOCHECK ADD CONSTRAINT [<constraintname>] FOREIGN KEY([<column>]) REFERENCES [dbo].[<reftable>] ([<refcolumn>])'
SET #DropStatement = 'ALTER TABLE [dbo].[<tablename>] DROP CONSTRAINT [<constraintname>]'
SET #TruncateStatement = 'TRUNCATE TABLE [<tablename>]'
-- Drop Temporary tables
DROP TABLE #FKs
-- GET FKs
SELECT ROW_NUMBER() OVER (ORDER BY OBJECT_NAME(parent_object_id), clm1.name) as ID,
OBJECT_NAME(constraint_object_id) as ConstraintName,
OBJECT_NAME(parent_object_id) as TableName,
clm1.name as ColumnName,
OBJECT_NAME(referenced_object_id) as ReferencedTableName,
clm2.name as ReferencedColumnName
INTO #FKs
FROM sys.foreign_key_columns fk
JOIN sys.columns clm1
ON fk.parent_column_id = clm1.column_id
AND fk.parent_object_id = clm1.object_id
JOIN sys.columns clm2
ON fk.referenced_column_id = clm2.column_id
AND fk.referenced_object_id= clm2.object_id
WHERE OBJECT_NAME(parent_object_id) not in ('//tables that you do not wont to be truncated')
ORDER BY OBJECT_NAME(parent_object_id)
-- Prepare Storage Table
IF Not EXISTS(SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Internal_FK_Definition_Storage')
BEGIN
IF #Verbose = 1
PRINT '1. Creating Process Specific Tables...'
-- CREATE STORAGE TABLE IF IT DOES NOT EXISTS
CREATE TABLE [Internal_FK_Definition_Storage]
(
ID int not null identity(1,1) primary key,
FK_Name varchar(250) not null,
FK_CreationStatement varchar(max) not null,
FK_DestructionStatement varchar(max) not null,
Table_TruncationStatement varchar(max) not null
)
END
ELSE
BEGIN
IF #Recycle = 0
BEGIN
IF #Verbose = 1
PRINT '1. Truncating Process Specific Tables...'
-- TRUNCATE TABLE IF IT ALREADY EXISTS
TRUNCATE TABLE [Internal_FK_Definition_Storage]
END
ELSE
PRINT '1. Process specific table will be recycled from previous execution...'
END
IF #Recycle = 0
BEGIN
IF #Verbose = 1
PRINT '2. Backing up Foreign Key Definitions...'
-- Fetch and persist FKs
WHILE (#i <= (SELECT MAX(ID) FROM #FKs))
BEGIN
SET #ConstraintName = (SELECT ConstraintName FROM #FKs WHERE ID = #i)
SET #TableName = (SELECT TableName FROM #FKs WHERE ID = #i)
SET #ColumnName = (SELECT ColumnName FROM #FKs WHERE ID = #i)
SET #ReferencedTableName = (SELECT ReferencedTableName FROM #FKs WHERE ID = #i)
SET #ReferencedColumnName = (SELECT ReferencedColumnName FROM #FKs WHERE ID = #i)
SET #DropStatementTemp = REPLACE(REPLACE(#DropStatement,'<tablename>',#TableName),'<constraintname>',#ConstraintName)
SET #CreateStatementTemp = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#CreateStatement,'<tablename>',#TableName),'<column>',#ColumnName),'<constraintname>',#ConstraintName),'<reftable>',#ReferencedTableName),'<refcolumn>',#ReferencedColumnName)
SET #TruncateStatementTemp = REPLACE(#TruncateStatement,'<tablename>',#TableName)
INSERT INTO [Internal_FK_Definition_Storage]
SELECT #ConstraintName, #CreateStatementTemp, #DropStatementTemp, #TruncateStatementTemp
SET #i = #i + 1
IF #Verbose = 1
PRINT ' > Backing up [' + #ConstraintName + '] from [' + #TableName + ']'
END
END
ELSE
PRINT '2. Backup up was recycled from previous execution...'
IF #Verbose = 1
PRINT '3. Dropping Foreign Keys...'
-- DROP FOREING KEYS
SET #i = 1
WHILE (#i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
BEGIN
SET #ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = #i)
SET #Statement = (SELECT FK_DestructionStatement FROM [Internal_FK_Definition_Storage] WITH (NOLOCK) WHERE ID = #i)
IF #Debug = 1
PRINT #Statement
ELSE
EXEC(#Statement)
SET #i = #i + 1
IF #Verbose = 1
PRINT ' > Dropping [' + #ConstraintName + ']'
END
IF #Verbose = 1
PRINT '4. Truncating Tables...'
-- TRUNCATE TABLES
SET #i = 1
WHILE (#i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
BEGIN
SET #Statement = (SELECT Table_TruncationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = #i)
IF #Debug = 1
PRINT #Statement
ELSE
EXEC(#Statement)
SET #i = #i + 1
IF #Verbose = 1
PRINT ' > ' + #Statement
END
IF #Verbose = 1
PRINT '5. Re-creating Foreign Keys...'
-- CREATE FOREING KEYS
SET #i = 1
WHILE (#i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage]))
BEGIN
SET #ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = #i)
SET #Statement = (SELECT FK_CreationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = #i)
IF #Debug = 1
PRINT #Statement
ELSE
EXEC(#Statement)
SET #i = #i + 1
IF #Verbose = 1
PRINT ' > Re-creating [' + #ConstraintName + ']'
END
IF #Verbose = 1
PRINT '6. Process Completed'
#denver_citizen and #Peter Szanto's answers didn't quite work for me, but I modified them to account for:
Composite Keys
On Delete and On Update actions
Checking the index when re-adding
Schemas other than dbo
Multiple tables at once
DECLARE #Debug bit = 0;
-- List of tables to truncate
select
SchemaName, Name
into #tables
from (values
('schema', 'table')
,('schema2', 'table2')
) as X(SchemaName, Name)
BEGIN TRANSACTION TruncateTrans;
with foreignKeys AS (
SELECT
SCHEMA_NAME(fk.schema_id) as SchemaName
,fk.Name as ConstraintName
,OBJECT_NAME(fk.parent_object_id) as TableName
,SCHEMA_NAME(t.SCHEMA_ID) as ReferencedSchemaName
,OBJECT_NAME(fk.referenced_object_id) as ReferencedTableName
,fc.constraint_column_id
,COL_NAME(fk.parent_object_id, fc.parent_column_id) AS ColumnName
,COL_NAME(fk.referenced_object_id, fc.referenced_column_id) as ReferencedColumnName
,fk.delete_referential_action_desc
,fk.update_referential_action_desc
FROM sys.foreign_keys AS fk
JOIN sys.foreign_key_columns AS fc
ON fk.object_id = fc.constraint_object_id
JOIN #tables tbl
ON OBJECT_NAME(fc.referenced_object_id) = tbl.Name
JOIN sys.tables t on OBJECT_NAME(t.object_id) = tbl.Name
and SCHEMA_NAME(t.schema_id) = tbl.SchemaName
and t.OBJECT_ID = fc.referenced_object_id
)
select
quotename(fk.ConstraintName) AS ConstraintName
,quotename(fk.SchemaName) + '.' + quotename(fk.TableName) AS TableName
,quotename(fk.ReferencedSchemaName) + '.' + quotename(fk.ReferencedTableName) AS ReferencedTableName
,replace(fk.delete_referential_action_desc, '_', ' ') AS DeleteAction
,replace(fk.update_referential_action_desc, '_', ' ') AS UpdateAction
,STUFF((
SELECT ',' + quotename(fk2.ColumnName)
FROM foreignKeys fk2
WHERE fk2.ConstraintName = fk.ConstraintName and fk2.SchemaName = fk.SchemaName
ORDER BY fk2.constraint_column_id
FOR XML PATH('')
),1,1,'') AS ColumnNames
,STUFF((
SELECT ',' + quotename(fk2.ReferencedColumnName)
FROM foreignKeys fk2
WHERE fk2.ConstraintName = fk.ConstraintName and fk2.SchemaName = fk.SchemaName
ORDER BY fk2.constraint_column_id
FOR XML PATH('')
),1,1,'') AS ReferencedColumnNames
into #FKs
from foreignKeys fk
GROUP BY fk.SchemaName, fk.ConstraintName, fk.TableName, fk.ReferencedSchemaName, fk.ReferencedTableName, fk.delete_referential_action_desc, fk.update_referential_action_desc
-- Drop FKs
select
identity(int,1,1) as ID,
'ALTER TABLE ' + fk.TableName + ' DROP CONSTRAINT ' + fk.ConstraintName AS script
into #scripts
from #FKs fk
-- Truncate
insert into #scripts
select distinct
'TRUNCATE TABLE ' + quotename(tbl.SchemaName) + '.' + quotename(tbl.Name) AS script
from #tables tbl
-- Recreate
insert into #scripts
select
'ALTER TABLE ' + fk.TableName +
' WITH CHECK ADD CONSTRAINT ' + fk.ConstraintName +
' FOREIGN KEY ('+ fk.ColumnNames +')' +
' REFERENCES ' + fk.ReferencedTableName +' ('+ fk.ReferencedColumnNames +')' +
' ON DELETE ' + fk.DeleteAction COLLATE Latin1_General_CI_AS_KS_WS + ' ON UPDATE ' + fk.UpdateAction COLLATE Latin1_General_CI_AS_KS_WS AS script
from #FKs fk
DECLARE #script nvarchar(MAX);
DECLARE curScripts CURSOR FOR
select script
from #scripts
order by ID
OPEN curScripts
WHILE 1=1 BEGIN
FETCH NEXT FROM curScripts INTO #script
IF ##FETCH_STATUS != 0 BREAK;
print #script;
IF #Debug = 0
EXEC (#script);
END
CLOSE curScripts
DEALLOCATE curScripts
drop table #scripts
drop table #FKs
drop table #tables
COMMIT TRANSACTION TruncateTrans;
You cannot truncate a table if you don't drop the constraints. A disable also doesn't work. you need to Drop everything. i've made a script that drop all constrainsts and then recreate then.
Be sure to wrap it in a transaction ;)
SET NOCOUNT ON
GO
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
--DROP CONSTRAINT:
DECLARE #dynSQL varchar(MAX);
DECLARE cur CURSOR FOR
SELECT
'
ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + ']
DROP CONSTRAINT ' + ForeignKeyConstraintName + '
'
FROM
#table
OPEN cur
FETCH cur into #dynSQL
WHILE ##FETCH_STATUS = 0
BEGIN
exec(#dynSQL)
print #dynSQL
FETCH cur into #dynSQL
END
CLOSE cur
DEALLOCATE cur
---------------------
--HERE GOES YOUR TRUNCATES!!!!!
--HERE GOES YOUR TRUNCATES!!!!!
--HERE GOES YOUR TRUNCATES!!!!!
truncate table your_table
--HERE GOES YOUR TRUNCATES!!!!!
--HERE GOES YOUR TRUNCATES!!!!!
--HERE GOES YOUR TRUNCATES!!!!!
---------------------
--ADD CONSTRAINT:
DECLARE cur2 CURSOR FOR
SELECT
'
ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + ']
ADD CONSTRAINT ' + ForeignKeyConstraintName + ' FOREIGN KEY(' + ForeignKeyConstraintColumnName + ') REFERENCES [' + PrimaryKeyConstraintTableSchema + '].[' + PrimaryKeyConstraintTableName + '](' + PrimaryKeyConstraintColumnName + ')
'
FROM
#table
OPEN cur2
FETCH cur2 into #dynSQL
WHILE ##FETCH_STATUS = 0
BEGIN
exec(#dynSQL)
print #dynSQL
FETCH cur2 into #dynSQL
END
CLOSE cur2
DEALLOCATE cur2
If I understand correctly, what you want to do is to have a clean environment to be set up for DB involving integration tests.
My approach here would be to drop the whole schema and recreate it later.
Reasons:
You probably already have a "create schema" script. Re-using it for test isolation is easy.
Creating a schema is pretty quick.
With that approach, it is pretty easy to set up your script to have each fixture create a NEW schema (with a temporary name), and then you can start running test-fixtures in parallel, making the slowest part of your test suite much faster.
Found elsewhere on the web
EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
EXEC sp_MSForEachTable 'ALTER TABLE ? DISABLE TRIGGER ALL'
-- EXEC sp_MSForEachTable 'DELETE FROM ?' -- Uncomment to execute
EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
EXEC sp_MSForEachTable 'ALTER TABLE ? ENABLE TRIGGER ALL'
I write the following ways and tried to parameterized them, so you can Run them in a Query document Or Make a useful SP with them easily.
A) Delete
If your table has not millions of records this works good and hasn't any Alter commands:
---------------------------------------------------------------
------------------- Just Fill Parameters Value ----------------
---------------------------------------------------------------
DECLARE #DbName AS NVARCHAR(30) = 'MyDb' --< Db Name
DECLARE #Schema AS NVARCHAR(30) = 'dbo' --< Schema
DECLARE #TableName AS NVARCHAR(30) = 'Book' --< Table Name
------------------ /Just Fill Parameters Value ----------------
DECLARE #Query AS NVARCHAR(500) = 'Delete FROM ' + #TableName
EXECUTE sp_executesql #Query
SET #Query=#DbName+'.'+#Schema+'.'+#TableName
DBCC CHECKIDENT (#Query,RESEED, 0)
In above answer of mine the method of resolve the mentioned problem in the question is based on #s15199d answer.
B) Truncate
If your table has millions of records or you hasn't any problem with Alter command in your codes, then use this one:
-- Book Student
--
-- | BookId | Field1 | | StudentId | BookId |
-- --------------------- ------------------------
-- | 1 | A | | 2 | 1 |
-- | 2 | B | | 1 | 1 |
-- | 3 | C | | 2 | 3 |
---------------------------------------------------------------
------------------- Just Fill Parameters Value ----------------
---------------------------------------------------------------
DECLARE #DbName AS NVARCHAR(30) = 'MyDb'
DECLARE #Schema AS NVARCHAR(30) = 'dbo'
DECLARE #TableName_ToTruncate AS NVARCHAR(30) = 'Book'
DECLARE #TableName_OfOwnerOfConstraint AS NVARCHAR(30) = 'Student' --< Decelations About FK_Book_Constraint
DECLARE #Ref_ColumnName_In_TableName_ToTruncate AS NVARCHAR(30) = 'BookId' --< Decelations About FK_Book_Constraint
DECLARE #FK_ColumnName_In_TableOfOwnerOfConstraint AS NVARCHAR(30) = 'Fk_BookId' --< Decelations About FK_Book_Constraint
DECLARE #FK_ConstraintName AS NVARCHAR(30) = 'FK_Book_Constraint' --< Decelations About FK_Book_Constraint
------------------ /Just Fill Parameters Value ----------------
DECLARE #Query AS NVARCHAR(2000)
SET #Query= 'ALTER TABLE '+#TableName_OfOwnerOfConstraint+' DROP CONSTRAINT '+#FK_ConstraintName
EXECUTE sp_executesql #Query
SET #Query= 'Truncate Table '+ #TableName_ToTruncate
EXECUTE sp_executesql #Query
SET #Query= 'ALTER TABLE '+#TableName_OfOwnerOfConstraint+' ADD CONSTRAINT '+#FK_ConstraintName+' FOREIGN KEY('+#FK_ColumnName_In_TableOfOwnerOfConstraint+') REFERENCES '+#TableName_ToTruncate+'('+#Ref_ColumnName_In_TableName_ToTruncate+')'
EXECUTE sp_executesql #Query
In above answer of mine the method of resolve the mentioned problem in the question is based on #LauroWolffValenteSobrinho answer.
If you have more than one CONSTRAINT then you should append its codes like me to the above query
Also you can change the above code base #SerjSagan answer to disable an enable the constraint
truncate did not work for me, delete + reseed is the best way out.
In case there are some of you out there who need to iterate over huge number of tables to perform delete + reseed, you might run into issues with some tables which does not have an identity column, the following code checks if identity column exist before attempting to reseed
EXEC ('DELETE FROM [schemaName].[tableName]')
IF EXISTS (Select * from sys.identity_columns where object_name(object_id) = 'tableName')
BEGIN
EXEC ('DBCC CHECKIDENT ([schemaName.tableName], RESEED, 0)')
END
For MS SQL, at least the newer versions, you can just disable the constrains with code like this:
ALTER TABLE Orders
NOCHECK CONSTRAINT [FK_dbo.Orders_dbo.Customers_Customer_Id]
GO
TRUNCATE TABLE Customers
GO
ALTER TABLE Orders
WITH CHECK CHECK CONSTRAINT [FK_dbo.Orders_dbo.Customers_Customer_Id]
GO
The only way is to drop foreign keys before doing the truncate. And after truncating the data, you must re-create the indexes.
The following script generates the required SQL for dropping all foreign key constraints.
DECLARE #drop NVARCHAR(MAX) = N'';
SELECT #drop += N'
ALTER TABLE ' + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name)
+ ' DROP CONSTRAINT ' + QUOTENAME(fk.name) + ';'
FROM sys.foreign_keys AS fk
INNER JOIN sys.tables AS ct
ON fk.parent_object_id = ct.[object_id]
INNER JOIN sys.schemas AS cs
ON ct.[schema_id] = cs.[schema_id];
SELECT #drop
Next, the following script generates the required SQL for re-creating foreign keys.
DECLARE #create NVARCHAR(MAX) = N'';
SELECT #create += N'
ALTER TABLE '
+ QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name)
+ ' ADD CONSTRAINT ' + QUOTENAME(fk.name)
+ ' FOREIGN KEY (' + STUFF((SELECT ',' + QUOTENAME(c.name)
-- get all the columns in the constraint table
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(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'')
+ ') REFERENCES ' + QUOTENAME(rs.name) + '.' + QUOTENAME(rt.name)
+ '(' + STUFF((SELECT ',' + QUOTENAME(c.name)
-- get all the referenced columns
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(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'') + ');'
FROM sys.foreign_keys AS fk
INNER JOIN sys.tables AS rt -- referenced table
ON fk.referenced_object_id = rt.[object_id]
INNER JOIN sys.schemas AS rs
ON rt.[schema_id] = rs.[schema_id]
INNER JOIN sys.tables AS ct -- constraint table
ON fk.parent_object_id = ct.[object_id]
INNER JOIN sys.schemas AS cs
ON ct.[schema_id] = cs.[schema_id]
WHERE rt.is_ms_shipped = 0 AND ct.is_ms_shipped = 0;
SELECT #create
Run the generated script to drop all foreign keys, truncate tables, and then run the generated script to re-create all foreign keys.
The queries are taken from here.
It's my solution of this issue. I used it for altering PK, but idea the same. Hope this will be useful)
PRINT 'Script starts'
DECLARE #foreign_key_name varchar(255)
DECLARE #keycnt int
DECLARE #foreign_table varchar(255)
DECLARE #foreign_column_1 varchar(255)
DECLARE #foreign_column_2 varchar(255)
DECLARE #primary_table varchar(255)
DECLARE #primary_column_1 varchar(255)
DECLARE #primary_column_2 varchar(255)
DECLARE #TablN varchar(255)
-->> Type the primary table name
SET #TablN = ''
--------------------------------------------------------------------------------------- ------------------------------
--Here will be created the temporary table with all reference FKs
---------------------------------------------------------------------------------------------------------------------
PRINT 'Creating the temporary table'
select cast(f.name as varchar(255)) as foreign_key_name
, r.keycnt
, cast(c.name as varchar(255)) as foreign_table
, cast(fc.name as varchar(255)) as foreign_column_1
, cast(fc2.name as varchar(255)) as foreign_column_2
, cast(p.name as varchar(255)) as primary_table
, cast(rc.name as varchar(255)) as primary_column_1
, cast(rc2.name as varchar(255)) as primary_column_2
into #ConTab
from sysobjects f
inner join sysobjects c on f.parent_obj = c.id
inner join sysreferences r on f.id = r.constid
inner join sysobjects p on r.rkeyid = p.id
inner join syscolumns rc on r.rkeyid = rc.id and r.rkey1 = rc.colid
inner join syscolumns fc on r.fkeyid = fc.id and r.fkey1 = fc.colid
left join syscolumns rc2 on r.rkeyid = rc2.id and r.rkey2 = rc.colid
left join syscolumns fc2 on r.fkeyid = fc2.id and r.fkey2 = fc.colid
where f.type = 'F' and p.name = #TablN
ORDER BY cast(p.name as varchar(255))
---------------------------------------------------------------------------------------------------------------------
--Cursor, below, will drop all reference FKs
---------------------------------------------------------------------------------------------------------------------
DECLARE #CURSOR CURSOR
/*Fill in cursor*/
PRINT 'Cursor 1 starting. All refernce FK will be droped'
SET #CURSOR = CURSOR SCROLL
FOR
select foreign_key_name
, keycnt
, foreign_table
, foreign_column_1
, foreign_column_2
, primary_table
, primary_column_1
, primary_column_2
from #ConTab
OPEN #CURSOR
FETCH NEXT FROM #CURSOR INTO #foreign_key_name, #keycnt, #foreign_table, #foreign_column_1, #foreign_column_2,
#primary_table, #primary_column_1, #primary_column_2
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC ('ALTER TABLE ['+#foreign_table+'] DROP CONSTRAINT ['+#foreign_key_name+']')
FETCH NEXT FROM #CURSOR INTO #foreign_key_name, #keycnt, #foreign_table, #foreign_column_1, #foreign_column_2,
#primary_table, #primary_column_1, #primary_column_2
END
CLOSE #CURSOR
PRINT 'Cursor 1 finished work'
---------------------------------------------------------------------------------------------------------------------
--Here you should provide the chainging script for the primary table
---------------------------------------------------------------------------------------------------------------------
PRINT 'Altering primary table begin'
TRUNCATE TABLE table_name
PRINT 'Altering finished'
---------------------------------------------------------------------------------------------------------------------
--Cursor, below, will add again all reference FKs
--------------------------------------------------------------------------------------------------------------------
PRINT 'Cursor 2 starting. All refernce FK will added'
SET #CURSOR = CURSOR SCROLL
FOR
select foreign_key_name
, keycnt
, foreign_table
, foreign_column_1
, foreign_column_2
, primary_table
, primary_column_1
, primary_column_2
from #ConTab
OPEN #CURSOR
FETCH NEXT FROM #CURSOR INTO #foreign_key_name, #keycnt, #foreign_table, #foreign_column_1, #foreign_column_2,
#primary_table, #primary_column_1, #primary_column_2
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC ('ALTER TABLE [' +#foreign_table+ '] WITH NOCHECK ADD CONSTRAINT [' +#foreign_key_name+ '] FOREIGN KEY(['+#foreign_column_1+'])
REFERENCES [' +#primary_table+'] (['+#primary_column_1+'])')
EXEC ('ALTER TABLE [' +#foreign_table+ '] CHECK CONSTRAINT [' +#foreign_key_name+']')
FETCH NEXT FROM #CURSOR INTO #foreign_key_name, #keycnt, #foreign_table, #foreign_column_1, #foreign_column_2,
#primary_table, #primary_column_1, #primary_column_2
END
CLOSE #CURSOR
PRINT 'Cursor 2 finished work'
---------------------------------------------------------------------------------------------------------------------
PRINT 'Temporary table droping'
drop table #ConTab
PRINT 'Finish'
The following works for me even with FK constraints, and combines the following answers to only drop the specified tables:
Transaction Automatic Rollback
Looping through comma-separated list
Executing Dynamic SQL (with table names from variable)
DELETE and RESEED table (in this thread)
USE [YourDB];
DECLARE #TransactionName varchar(20) = 'stopdropandroll';
BEGIN TRAN #TransactionName;
set xact_abort on; /* automatic rollback https://stackoverflow.com/a/1749788/1037948 */
-- ===== DO WORK // =====
-- dynamic sql placeholder
DECLARE #SQL varchar(300);
-- LOOP: https://stackoverflow.com/a/10031803/1037948
-- list of things to loop
DECLARE #delim char = ';';
DECLARE #foreach varchar(MAX) = 'Table;Names;Separated;By;Delimiter' + #delim + 'AnotherName' + #delim + 'Still Another';
DECLARE #token varchar(MAX);
WHILE len(#foreach) > 0
BEGIN
-- set current loop token
SET #token = left(#foreach, charindex(#delim, #foreach+#delim)-1)
-- ======= DO WORK // ===========
-- dynamic sql (parentheses are required): https://stackoverflow.com/a/989111/1037948
SET #SQL = 'DELETE FROM [' + #token + ']; DBCC CHECKIDENT (''' + #token + ''',RESEED, 0);'; -- https://stackoverflow.com/a/11784890
PRINT #SQL;
EXEC (#SQL);
-- ======= // END WORK ===========
-- continue loop, chopping off token
SET #foreach = stuff(#foreach, 1, charindex(#delim, #foreach+#delim), '')
END
-- ===== // END WORK =====
-- review and commit
SELECT ##TRANCOUNT as TransactionsPerformed, ##ROWCOUNT as LastRowsChanged;
COMMIT TRAN #TransactionName;
Note:
I think it still helps to declare the tables in the order you want them deleted (i.e. kill dependencies first). As seen in this answer, rather than loop specific names you could substitute all tables with
EXEC sp_MSForEachTable 'DELETE FROM ?; DBCC CHECKIDENT (''?'',RESEED, 0);';
If none of these answers worked like in my case do this:
Drop constraints
Set all values to allow nulls
Truncate table
Add constraints that were dropped.
Good luck!
Delete then reset auto-increment:
delete from tablename;
then
ALTER TABLE tablename AUTO_INCREMENT = 1;
In SSMS I had Diagram open showing the Key. After deleting the Key and truncating the file I refreshed then focused back on the Diagram and created an update by clearing then restoring an Identity box. Saving the Diagram brought up a Save dialog box, than a "Changes were made in the database while you where working" dialog box, clicking Yes restored the Key, restoring it from the latched copy in the Diagram.
If you're doing this at any sort of a frequency, heck even on a schedule, I would absolutely, unequivocally never use a DML statement. The cost of writing to the transaction log is just to high, and setting the entire database into SIMPLE recovery mode to truncate one table is ridiculous.
The best way, is unfortunately the hard or laborious way. That being:
Drop constraints
Truncate table
Re-create constraints
My process for doing this involves the following steps:
In SSMS right-click on the table in question, and select View Dependencies
Take note of the tables referenced (if any)
Back in object explorer, expand the Keys node and take note of the foreign keys (if any)
Start scripting (drop / truncate / re-create)
Scripts of this nature should be done within a begin tran and commit tran block.
This is an example for someone that use Entity Framework
Table to be reset: Foo
Another table that depends on: Bar
Constraint Column on table Foo : FooColumn
Constraint Column on table Bar : BarColumn
public override void Down()
{
DropForeignKey("dbo.Bar", "BarColumn", "dbo.Foo");
Sql("TRUNCATE TABLE Foo");
AddForeignKey("dbo.Bar", "BarColumn", "dbo.Foo", "FooColumn", cascadeDelete: true);
}
The following script truncates all foreign key constraints & recreates them:
DECLARE #DROP_CONSTRAINT_SCRIPT VARCHAR(MAX);
DECLARE #CREATE_CONSTRAINT_SCRIPT VARCHAR(MAX);
SET #DROP_CONSTRAINT_SCRIPT='';
SET #CREATE_CONSTRAINT_SCRIPT='';
SELECT #DROP_CONSTRAINT_SCRIPT=#DROP_CONSTRAINT_SCRIPT + 'ALTER TABLE '+FK_Table+'
DROP CONSTRAINT '+FK_Name+';
',
#CREATE_CONSTRAINT_SCRIPT = #CREATE_CONSTRAINT_SCRIPT +
'ALTER TABLE '+FK_Table+'
ADD CONSTRAINT '+FK_Name+'
FOREIGN KEY ('+FK_Column+') REFERENCES '+PK_Table+'('+PK_Column+');
'
FROM (
SELECT RC.CONSTRAINT_NAME FK_Name
, KF.TABLE_SCHEMA FK_Schema
, KF.TABLE_NAME FK_Table
, KF.COLUMN_NAME FK_Column
, RC.UNIQUE_CONSTRAINT_NAME PK_Name
, KP.TABLE_SCHEMA PK_Schema
, KP.TABLE_NAME PK_Table
, KP.COLUMN_NAME PK_Column
, RC.MATCH_OPTION MatchOption
, RC.UPDATE_RULE UpdateRule
, RC.DELETE_RULE DeleteRule
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KF ON RC.CONSTRAINT_NAME = KF.CONSTRAINT_NAME
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KP ON RC.UNIQUE_CONSTRAINT_NAME = KP.CONSTRAINT_NAME
WHERE KP.TABLE_NAME='TABLE_NAME_TRUNCATE'
) TBL
-- DROP CONSTRAINTS
EXEC( #DROP_CONSTRAINT_SCRIPT);
-------
-- TRUNCATE TABLE SCRIPT NEEDS TO BE PUT BELOW
-------
TRUNCATE TABLE TABLE_NAME_TRUNCATE
-- RECREATE CONSTRAINTS
EXEC( #CREATE_CONSTRAINT_SCRIPT);
SET FOREIGN_KEY_CHECKS=0;
TRUNCATE table1;
TRUNCATE table2;
SET FOREIGN_KEY_CHECKS=1;
reference - truncate foreign key constrained table
Working for me in MYSQL
You could try DELETE FROM <your table >;.
The server will show you the name of the restriction and the table, and deleting that table you can delete what you need.
I have just found that you can use TRUNCATE table on a parent table with foreign key constraints on a child as long as you DISABLE the constraints on the child table first.
E.g.
Foreign key CONSTRAINT child_par_ref on child table, references PARENT_TABLE
ALTER TABLE CHILD_TABLE DISABLE CONSTRAINT child_par_ref;
TRUNCATE TABLE CHILD_TABLE;
TRUNCATE TABLE PARENT_TABLE;
ALTER TABLE CHILD_TABLE ENABLE CONSTRAINT child_par_ref;
The easiest way:
1 - Enter in phpmyadmin
2 - Click on table name in left column
3 - Click in Operation (top menu)
4 - Click "Empty the table (TRUNCATE)
5 - Disable box "Enable foreign key checks"
6 - Done!
Link to image tutorial
Tutorial: http://www.imageno.com/wz6gv1wuqajrpic.html
(sorry, I don't have enough reputation to upload images here :P)

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