SSDT Disable an Restore constraints during Publish - sql

I'm adding scripts to an SSDT project to manage the addition/update of data from static data tables. Some of these tables reference each other, so I need to be able to shut down the constraints during the update so that I can let the data sit in an inconsistent state until all the scripts are run (I've got a file for table A, and a separate one for Table B).
Once completed, I need to re-enable all the constraints (and let the system check the data to ensure it's consistent). The caveat, is that for various reasons some of the constraints are currently disabled - and I need to ensure that they restore back to the state they were in before my script.
I can't seem to find a view/table that lists the current status of the FK constraints.
Is there any way to have SSDT publish do this automatically? Or if not, can anyone recommend a good solution for doing this?

In the end, I used a combination of sys.Foreign_Keys and sys.check_constraints, since the disable all command disabled both of them. I'm recording the status of the constraints prior to doing my work, then re-enabling them back to the original state at the end.
If OBJECT_ID('tempdb..#tempConstraints') is not null Drop Table #tempConstraints;
GO
IF (SELECT OBJECT_ID('tempdb..#tmpScriptErrors')) IS NOT NULL DROP TABLE #tmpScriptErrors
GO
CREATE TABLE #tmpScriptErrors (Error int)
GO
Create Table #tempConstraints
(
ConstraintName nVarchar(200),
TableName nVarchar(200),
SchemaName nVarchar(200),
IsNotTrusted bit
);
GO
Begin Tran
Insert into #tempConstraints (ConstraintName, TableName, SchemaName, IsNotTrusted)
Select K.name, object_name(K.parent_object_id), SCHEMA_NAME(T.schema_id), K.Is_Not_Trusted
FROM sys.foreign_keys K
Inner Join sys.tables T on K.parent_object_id = T.object_id
Where is_disabled = 0
Union all
Select K.name, object_name(K.parent_object_id), SCHEMA_NAME(T.schema_id), K.Is_Not_Trusted
from sys.check_constraints K
Inner Join sys.tables T on K.parent_object_id = T.object_id
Where is_disabled = 0
--Disable the Constraints.
Print 'Disabling Constraints'
Exec sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL';
----------------------------------------------------------------------------------------
--Do Work Here
----------------------------------------------------------------------------------------
Declare #name nvarchar(200);
Declare #table nvarchar(200);
Declare #schema nvarchar(200);
Declare #script nvarchar(max);
Declare #NotTrusted bit;
Declare constraints_cursor CURSOR FOR
Select ConstraintName, TableName, SchemaName, IsNotTrusted
From #tempConstraints;
Open constraints_cursor;
Fetch Next from constraints_cursor
into #name, #table, #schema, #NotTrusted;
While ##FETCH_STATUS = 0
Begin
--Restore each of the Constraints back to exactly the state they were in prior to disabling.
If #NotTrusted = 1
Set #script = 'ALTER TABLE [' + #schema + '].[' + #table + '] WITH NOCHECK CHECK CONSTRAINT [' + #name + ']';
Else
Set #script = 'ALTER TABLE [' + #schema + '].[' + #table + '] WITH CHECK CHECK CONSTRAINT [' + #name + ']';
exec sp_executesql #script;
If ##ERROR <> 0
Begin
INSERT INTO #tmpScriptErrors (Error)
VALUES (1);
End
Fetch Next from constraints_cursor
into #name, #table, #schema, #NotTrusted;
End
Close constraints_cursor;
Deallocate constraints_cursor;
If exists (Select 'x' from #tmpScriptErrors)
ROLLBACK TRAN;
Else
COMMIT TRAN;
Drop table #tmpScriptErrors
GO
Drop table #tempConstraints
GO

Related

Azure SQL rebuild index script fails if many indexes to rebuild

I have a script to rebuild/reorganize indexes as follows in Azure SQL server. Problem is that it causes the application to hang because all the database sessions will be taken from this script. It is calling the rebuild sql statement inside a cursor, so I was expecting that it will rebuild the indexes one after the other. But it seems all the index rebuilds will run parallel, otherwise there is no reason why the database starts to hang and no connection can be made during this process. If there are few indexes to rebuild, then it is fine. The problem starts when there are like 60 indexes to rebuild. Is there a way to force to build the indexes one after the other? (sequentially , not in parallel).
CREATE PROCEDURE [dbo].[RebuildIndexes]
AS
BEGIN
SET NOCOUNT ON;
DECLARE #objectid int;
DECLARE #indexid int;
DECLARE #partitioncount bigint;
DECLARE #schemaname nvarchar(130);
DECLARE #objectname nvarchar(130);
DECLARE #indexname nvarchar(250);
DECLARE #partitionnum bigint;
DECLARE #partitions bigint;
DECLARE #frag float;
DECLARE #command nvarchar(4000);
-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function
-- and convert object and index IDs to names.
SELECT
object_id AS objectid,
index_id AS indexid,
partition_number AS partitionnum,
avg_fragmentation_in_percent AS frag
INTO #indexes_to_build
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED')
WHERE avg_fragmentation_in_percent > 10.0 AND index_id > 0 and page_count > 200
ORDER BY avg_fragmentation_in_percent DESC;
-- Declare the cursor for the list of partitions to be processed.
DECLARE partitions CURSOR FOR SELECT * FROM #indexes_to_build;
-- Open the cursor.
OPEN partitions;
-- Loop through the partitions.
WHILE (1=1)
BEGIN;
FETCH NEXT
FROM partitions
INTO #objectid, #indexid, #partitionnum, #frag;
IF ##FETCH_STATUS < 0 BREAK;
SELECT #objectname = QUOTENAME(o.name), #schemaname = QUOTENAME(s.name)
FROM sys.objects AS o
JOIN sys.schemas as s ON s.schema_id = o.schema_id
WHERE o.object_id = #objectid;
SELECT #indexname = QUOTENAME(name)
FROM sys.indexes
WHERE object_id = #objectid AND index_id = #indexid;
SELECT #partitioncount = count (*)
FROM sys.partitions
WHERE object_id = #objectid AND index_id = #indexid;
-- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding.
IF #frag < 30.0
SET #command = N'ALTER INDEX ' + #indexname + N' ON ' + #schemaname + N'.' + #objectname + N' REORGANIZE';
IF #frag >= 30.0
SET #command = N'ALTER INDEX ' + #indexname + N' ON ' + #schemaname + N'.' + #objectname + N' REBUILD WITH (ONLINE = ON)';
IF #partitioncount > 1
SET #command = #command + N' PARTITION=' + CAST(#partitionnum AS nvarchar(10));
EXEC (#command);
PRINT N'Executed: ' + #command;
END;
-- Close and deallocate the cursor.
CLOSE partitions;
DEALLOCATE partitions;
-- Drop the temporary table.
DROP TABLE #indexes_to_build;
COMMIT;
END;
Is there a way to force to build the indexes one after the other?
TSQL always executes sequentially. And your ALTER INDEX commands are no exception.
The COMMIT at the end is the problem. That procedure, as written, will only run with IMPLICIT_TRANSACTIONS on. With a COMMIT after the loop, you are accumulating exclusive locks (Sch-M) on the target indexes as you rebuild them. As you work through a large number of indexes, you will block more and more other sessions.
You should not do that. Instead don't use IMPLICIT_TRANSACTIONS or COMMIT after each index rebuild. EG:
IF #partitioncount > 1
SET #command = #command + N' PARTITION=' + CAST(#partitionnum AS nvarchar(10));
EXEC (#command);
PRINT N'Executed: ' + #command;
COMMIT;
My suggestion is to use Ola Hallemgren's stored procedure name Index Optimize which you can download from here. Everybody use his scripts for index maintenance tasks.
You can run the stored procedure as shown below:
EXECUTE dbo.IndexOptimize
#Databases = 'mydbnamehere',
#FragmentationLow = NULL,
#FragmentationMedium = 'INDEX_REORGANIZE,INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
#FragmentationHigh = 'INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
#FragmentationLevel1 = 5,
#FragmentationLevel2 = 30,
#UpdateStatistics = 'ALL',
#OnlyModifiedStatistics = 'Y'
For more information, please visit this Web page.

Stored procedure to remove FK of a given table

I need to create a stored procedure that:
Accepts a table name as a parameter
Find its dependencies (FKs)
Removes them
Truncate the table
I created the following so far based on http://www.mssqltips.com/sqlservertip/1376/disable-enable-drop-and-recreate-sql-server-foreign-keys/ . My problem is that the following script successfully does 1 and 2 and generates queries to alter tables but does not actually execute them. In another word how can execute the resulting "Alter Table ..." queries to actually remove FKs?
CREATE PROCEDURE DropDependencies(#TableName VARCHAR(50))
AS
BEGIN
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(#TableName)
END
EXEC DropDependencies 'TableName'
Any idea is appreciated!
Update:
I added the cursor to the SP but I still get and error:
"Msg 203, Level 16, State 2, Procedure DropRestoreDependencies, Line 75
The name 'ALTER TABLE [dbo].[ChildTable] DROP CONSTRAINT [FK__ChileTable__ParentTable__745C7C5D]' is not a valid identifier."
Here is the updated SP:
CREATE PROCEDURE DropRestoreDependencies(#schemaName sysname, #tableName sysname)
AS
BEGIN
SET NOCOUNT ON
DECLARE #operation VARCHAR(10)
SET #operation = 'DROP' --ENABLE, DISABLE, DROP
DECLARE #cmd NVARCHAR(1000)
DECLARE
#FK_NAME sysname,
#FK_OBJECTID INT,
#FK_DISABLED INT,
#FK_NOT_FOR_REPLICATION INT,
#DELETE_RULE smallint,
#UPDATE_RULE smallint,
#FKTABLE_NAME sysname,
#FKTABLE_OWNER sysname,
#PKTABLE_NAME sysname,
#PKTABLE_OWNER sysname,
#FKCOLUMN_NAME sysname,
#PKCOLUMN_NAME sysname,
#CONSTRAINT_COLID INT
DECLARE cursor_fkeys CURSOR FOR
SELECT Fk.name,
Fk.OBJECT_ID,
Fk.is_disabled,
Fk.is_not_for_replication,
Fk.delete_referential_action,
Fk.update_referential_action,
OBJECT_NAME(Fk.parent_object_id) AS Fk_table_name,
schema_name(Fk.schema_id) AS Fk_table_schema,
TbR.name AS Pk_table_name,
schema_name(TbR.schema_id) Pk_table_schema
FROM sys.foreign_keys Fk LEFT OUTER JOIN
sys.tables TbR ON TbR.OBJECT_ID = Fk.referenced_object_id --inner join
WHERE TbR.name = #tableName
AND schema_name(TbR.schema_id) = #schemaName
OPEN cursor_fkeys
FETCH NEXT FROM cursor_fkeys
INTO #FK_NAME,#FK_OBJECTID,
#FK_DISABLED,
#FK_NOT_FOR_REPLICATION,
#DELETE_RULE,
#UPDATE_RULE,
#FKTABLE_NAME,
#FKTABLE_OWNER,
#PKTABLE_NAME,
#PKTABLE_OWNER
WHILE ##FETCH_STATUS = 0
BEGIN
-- create statement for dropping FK and also for recreating FK
IF #operation = 'DROP'
BEGIN
-- drop statement
SET #cmd = 'ALTER TABLE [' + #FKTABLE_OWNER + '].[' + #FKTABLE_NAME
+ '] DROP CONSTRAINT [' + #FK_NAME + ']'
EXEC #cmd
-- create process
DECLARE #FKCOLUMNS VARCHAR(1000), #PKCOLUMNS VARCHAR(1000), #COUNTER INT
-- create cursor to get FK columns
DECLARE cursor_fkeyCols CURSOR FOR
SELECT COL_NAME(Fk.parent_object_id, Fk_Cl.parent_column_id) AS Fk_col_name,
COL_NAME(Fk.referenced_object_id, Fk_Cl.referenced_column_id) AS Pk_col_name
FROM sys.foreign_keys Fk LEFT OUTER JOIN
sys.tables TbR ON TbR.OBJECT_ID = Fk.referenced_object_id INNER JOIN
sys.foreign_key_columns Fk_Cl ON Fk_Cl.constraint_object_id = Fk.OBJECT_ID
WHERE TbR.name = #tableName
AND schema_name(TbR.schema_id) = #schemaName
AND Fk_Cl.constraint_object_id = #FK_OBJECTID -- added 6/12/2008
ORDER BY Fk_Cl.constraint_column_id
OPEN cursor_fkeyCols
FETCH NEXT FROM cursor_fkeyCols INTO #FKCOLUMN_NAME,#PKCOLUMN_NAME
SET #COUNTER = 1
SET #FKCOLUMNS = ''
SET #PKCOLUMNS = ''
WHILE ##FETCH_STATUS = 0
BEGIN
IF #COUNTER > 1
BEGIN
SET #FKCOLUMNS = #FKCOLUMNS + ','
SET #PKCOLUMNS = #PKCOLUMNS + ','
END
SET #FKCOLUMNS = #FKCOLUMNS + '[' + #FKCOLUMN_NAME + ']'
SET #PKCOLUMNS = #PKCOLUMNS + '[' + #PKCOLUMN_NAME + ']'
SET #COUNTER = #COUNTER + 1
FETCH NEXT FROM cursor_fkeyCols INTO #FKCOLUMN_NAME,#PKCOLUMN_NAME
END
CLOSE cursor_fkeyCols
DEALLOCATE cursor_fkeyCols
END
FETCH NEXT FROM cursor_fkeys
INTO #FK_NAME,#FK_OBJECTID,
#FK_DISABLED,
#FK_NOT_FOR_REPLICATION,
#DELETE_RULE,
#UPDATE_RULE,
#FKTABLE_NAME,
#FKTABLE_OWNER,
#PKTABLE_NAME,
#PKTABLE_OWNER
END
CLOSE cursor_fkeys
DEALLOCATE cursor_fkeys
END
For running use:
EXEC DropRestoreDependencies dbo, ParentTable
Use a cursor to go through your SELECT results, populating a variable with the single column, and executing that query with EXEC(#YourVariable). Be sure to use parens around the variable!
The issue is that you are only preparing the SQL statement and not executing it (I think)
CREATE PROCEDURE DropDependencies(#TableName VARCHAR(50))
AS
BEGIN
DECLARE #SQL nvarchar(max)
SELECT #SQL = '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(#TableName)
EXEC #SQL
END
EXEC DropDependencies 'TableName'
Whenever using EXEC though from constructed strings, ensure you aren't vulnerable to SQL Injection attacks.
Try Out SP_ExecuteSQL or Exec. I see that you are using Exec. Perhaps SP_ExecuteSQL will work?

How to turn off/on all the foreign keys and triggers in Microsoft SQL Server?

It can be needed for inserting and modifying of big amounts of data.
Disable all FKs:
EXEC sp_MSforeachtable #command1="ALTER TABLE ? NOCHECK CONSTRAINT ALL"
GO
Enable all FKs:
EXEC sp_MSforeachtable #command1="ALTER TABLE ? CHECK CONSTRAINT ALL"
GO
Disable all triggers:
EXEC sp_MSforeachtable #command1="ALTER TABLE ? DISABLE TRIGGER ALL"
GO
Enable all triggers:
EXEC sp_MSforeachtable #command1="ALTER TABLE ? ENABLE TRIGGER ALL"
GO
Of course, note that if you had any FKs/triggers disabled prior to this, the enable script will re-enable these.
To disable all FKs in a table:
ALTER TABLE Table2 NOCHECK CONSTRAINT ALL
To disable a single FK in a table:
ALTER TABLE Table2 NOCHECK CONSTRAINT FK_Table2_Table1
To enable them replace NOCHECK with CHECK.
If you want to disable all FK's, and then restore them back to their original state, the following can be used:
Disable All Constraints
If OBJECT_ID('tempdb..#tempConstraints') is not null Drop Table #tempConstraints;
GO
IF (SELECT OBJECT_ID('tempdb..#tmpScriptErrors')) IS NOT NULL DROP TABLE #tmpScriptErrors
GO
CREATE TABLE #tmpScriptErrors (Error int)
GO
Create Table #tempConstraints
(
ConstraintName nVarchar(200),
TableName nVarchar(200),
SchemaName nVarchar(200),
IsNotTrusted bit
);
GO
Begin Tran
Insert into #tempConstraints (ConstraintName, TableName, SchemaName, IsNotTrusted)
Select K.name, object_name(K.parent_object_id), SCHEMA_NAME(T.schema_id), K.Is_Not_Trusted
FROM sys.foreign_keys K
Inner Join sys.tables T on K.parent_object_id = T.object_id
Where is_disabled = 0
Union all
Select K.name, object_name(K.parent_object_id), SCHEMA_NAME(T.schema_id), K.Is_Not_Trusted
from sys.check_constraints K
Inner Join sys.tables T on K.parent_object_id = T.object_id
Where is_disabled = 0
--Disable the Constraints.
Print 'Disabling Constraints'
Exec sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL';
Restore Constraints to Original State
Declare #name nvarchar(200);
Declare #table nvarchar(200);
Declare #schema nvarchar(200);
Declare #script nvarchar(max);
Declare #NotTrusted bit;
Declare constraints_cursor CURSOR FOR
Select ConstraintName, TableName, SchemaName, IsNotTrusted
From #tempConstraints;
Open constraints_cursor;
Fetch Next from constraints_cursor
into #name, #table, #schema, #NotTrusted;
While ##FETCH_STATUS = 0
Begin
--Restore each of the Constraints back to exactly the state they were in prior to disabling.
If #NotTrusted = 1
Set #script = 'ALTER TABLE [' + #schema + '].[' + #table + '] WITH NOCHECK CHECK CONSTRAINT [' + #name + ']';
Else
Set #script = 'ALTER TABLE [' + #schema + '].[' + #table + '] WITH CHECK CHECK CONSTRAINT [' + #name + ']';
exec sp_executesql #script;
If ##ERROR <> 0
Begin
PRINT 'Re-Enabling ' + #name;
INSERT INTO #tmpScriptErrors (Error)
VALUES (1);
End
Fetch Next from constraints_cursor
into #name, #table, #schema, #NotTrusted;
End
Close constraints_cursor;
Deallocate constraints_cursor;
If exists (Select 'x' from #tmpScriptErrors)
ROLLBACK TRAN;
Else
COMMIT TRAN;
Drop table #tmpScriptErrors
GO
Drop table #tempConstraints
GO
Disabling triggers in a single statement
DISABLE TRIGGER and ENABLE TRIGGER - check MSDN for their syntax. E.g., search google for : DISABLE TRIGGER t-sql
E.g.,
DISABLE TRIGGER ALL ON ALL SERVER; -- Disabling all DML triggers defined on server level and all logon triggers
There is no built-in way how to disable all FKs in a single statement.

Dropping a table with all its dependencies (Microsoft SQL Server)

How can I drop a table with all its dependencies [SPs, Views, etc.] (Microsoft SQL Server) without knowing its dependencies upfront? I know I can display all dependencies in Mangement Studio but I'm searching for utility script that I could simply speficy an object and it would drop this object with all its dependencies.
The best thing to do it is "Generate scripts for Drop"
Select Database -> Right Click -> Tasks -> Generate Scripts - will open wizard for generating scripts
Select the database -> next
Set option 'Script to create' to true (want to create)
Set option 'Script to Drop' to true (want to drop)
Set option 'Generate script for dependent object' to true -> Next
Select the Check box to select objects wish to create script
Select the choice to write script (File, New window, Clipboard)
Execute the script
This way we can customize our script i.e., we can do scripting for selected objects of a database.
I hope this will help you!
Best Wishes, JP
You can use Sp_Depends to find the dependencies. With that you can modify the script from this answer Maybe someone less lazy than me will do that for you.
Note: Each object of course could have its own dependencies so you'll need to process them as well.
Delete a SQL object using its schema-qualified name. For tables, the constraints are dropped first.
Errors are ignored.
create procedure [dbo].[spDropObject] (#fullname nvarchar(520))
as
begin
begin try
declare #type nvarchar(5)
declare #resolvedFullname nvarchar(520)
declare #resolvedName nvarchar(255)
set #type = null
set #resolvedFullname = null
set #resolvedName = null
--find the object
select
#type = o.[type]
,#resolvedFullname = '[' + object_schema_name(o.id) + '].[' + o.[name] + ']'
,#resolvedName = '[' + o.[name] + ']'
from dbo.sysobjects o
where id = object_id(#fullname)
--PROCEDURE
if(#type = 'P')
begin
exec('drop procedure ' + #resolvedFullname);
return;
end
--VIEW
if(#type = 'V')
begin
exec('drop view ' + #resolvedFullname);
return;
end
--FUNCTION
if(#type = 'FN' or #type = 'TF')
begin
exec('drop function ' + #resolvedFullname);
return;
end
--TRIGGER
if(#type = 'TF')
begin
exec('drop trigger ' + #resolvedFullname);
return;
end
--CONSTRAINT
if(#type = 'C' or #type = 'UQ' or #type = 'D' or #type = 'F' or #type = 'PK' or #type = 'K')
begin
declare #fullTablename nvarchar(520);
set #fullTablename = null
--find the contraint's table
select #fullTablename ='[' + object_schema_name(t.[object_id]) + '].[' + t.[Name] + ']'
from sys.tables t
join sys.schemas s on t.schema_id = s.schema_id
where t.object_id = (select parent_obj from dbo.sysobjects where id = object_id(#resolvedFullname))
exec('alter table ' + #fullTablename + ' drop constraint ' + #resolvedName);
return;
end
--TABLE (drop all constraints then drop the table)
if(#type = 'U')
begin
--find FK references to the table
declare #fktab table([Name] nvarchar(255))
insert #fktab
select
[Name] = '[' + object_name(fkc.[constraint_object_id]) + ']'
/*
,[Parent] = '[' + object_schema_name(fkc.[parent_object_id]) + '].[' + object_name(fkc.[parent_object_id]) + ']'
,[Ref] = '[' + object_schema_name(fkc.[referenced_object_id]) + '].[' + object_name(fkc.[referenced_object_id]) + ']'
*/
from sys.foreign_key_columns as fkc
where referenced_object_id = object_id(#resolvedFullname)
order by [Name]
--iterate FKs
while(1=1)
begin
declare #constraint nvarchar(255)
set #constraint = null
select top 1
#constraint = [Name]
from #fktab
if(#constraint is not null)
begin
--drop FK constraint
exec [dbo].[spDropObject] #constraint;
delete from #fktab where [Name] = #constraint --remove current record from working table
end
else break;
end
--find constraints for table
declare #constraintTab table ([Name] nvarchar(255));
insert #constraintTab
select [name]
from sys.objects
where parent_object_id = object_id(#resolvedFullname)
order by [name]
--iterate constraints
while(1=1)
begin
set #constraint = null;
select top 1 #constraint = [Name] from #constraintTab
if(#constraint is not null)
begin
--drop constraint
exec [dbo].[spDropObject] #constraint;
delete from #constraintTab where [Name] = #constraint --remove current record from working table
end
else break;
end
--drop table
exec('drop table ' + #resolvedFullname);
return;
end
end try
begin catch
declare #message nvarchar(max)
set #message = error_message( ) ;
print #message
end catch
end
In my case, I specifically wanted to drop a specified table and the tables that depend on that table. It wasn't useful to me to only drop the foreign key constraints that reference it. I wrote a stored procedure to do this
CREATE PROCEDURE DropDependentTables (
#tableName NVARCHAR(64))
AS
-- Find and drop all tables that depend on #tableName
WHILE EXISTS(SELECT *
FROM sys.foreign_keys
WHERE OBJECT_NAME(referenced_object_id) = #tableName AND
OBJECT_NAME(parent_object_id) != #tableName)
BEGIN
DECLARE #dependentTableName NVARCHAR(64)
SELECT TOP 1 #dependentTableName = OBJECT_NAME(parent_object_id)
FROM sys.foreign_keys
WHERE OBJECT_NAME(referenced_object_id) = #tableName AND
OBJECT_NAME(parent_object_id) != #tableName
EXEC DropDependentTables #dependentTableName
END
I'm going to leave a late answer (after around 10 years). I hope you'll find it handy.
In our company, we use this script to properly delete database tables. For each table, we first drop the dependencies (REFERENTIAL_CONSTRAINTS) then delete the table itself.
USE [database-name]
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
The credit goes to a colleague of mine, Abolfazl Najafzade, for the script.

How to delete all rows from all tables in a SQL Server database?

How to delete all rows from all tables in a SQL Server database?
Note that TRUNCATE won't work if you have any referential integrity set.
In that case, this will work:
EXEC sp_MSForEachTable 'DISABLE TRIGGER ALL ON ?'
GO
EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
GO
EXEC sp_MSForEachTable 'SET QUOTED_IDENTIFIER ON; DELETE FROM ?'
GO
EXEC sp_MSForEachTable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL'
GO
EXEC sp_MSForEachTable 'ENABLE TRIGGER ALL ON ?'
GO
Edit: To be clear, the ? in the statements is a ?. It's replaced with the table name by the sp_MSForEachTable procedure.
In my recent project my task was to clean an entire database by using sql statement and each table having many constraints like Primary Key and Foreign Key. There are more than 1000 tables in database so its not possible to write a delete query on each and ever table.
By using a stored procedure named sp_MSForEachTable which allows us to easily process some code against each and every table in a single database. It means that it is used to process a single T-SQL command or a different T-SQL commands against every table in the database.
So follow the below steps to truncate all tables in a SQL Server Database:
Step 1- Disable all constraints on the database by using below sql query :
EXEC sys.sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
Step 2- Execute a Delete or truncate operation on each table of the database by using below sql command :
EXEC sys.sp_msforeachtable 'DELETE FROM ?'
Step 3- Enable all constraints on the database by using below sql statement:
EXEC sys.sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
I had to delete all the rows and did it with the next script:
DECLARE #Nombre NVARCHAR(MAX);
DECLARE curso CURSOR FAST_FORWARD
FOR
Select Object_name(object_id) AS Nombre from sys.objects where type = 'U'
OPEN curso
FETCH NEXT FROM curso INTO #Nombre
WHILE (##FETCH_STATUS <> -1)
BEGIN
IF (##FETCH_STATUS <> -2)
BEGIN
DECLARE #statement NVARCHAR(200);
SET #statement = 'DELETE FROM ' + #Nombre;
print #statement
execute sp_executesql #statement;
END
FETCH NEXT FROM curso INTO #Nombre
END
CLOSE curso
DEALLOCATE curso
Hope this helps!
In my case, I needed to set QUOTED_IDENTIFIER on. This led to a slight modification of Mark Rendle's answer above:
EXEC sp_MSforeachtable 'DISABLE TRIGGER ALL ON ?'
GO
EXEC sp_MSforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
GO
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; DELETE FROM ?'
GO
EXEC sp_MSforeachtable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
GO
EXEC sp_MSforeachtable 'ENABLE TRIGGER ALL ON ?'
GO
Here is a solution that:
Drops constraints (thanks to this post)
Iterates through INFORMATION_SCHEMA.TABLES for a particular database
SELECTS tables based on some search criteria
Deletes all the data from those tables
Re-adds constraints
Allows for ignoring of certain tables such as sysdiagrams and __RefactorLog
I initially tried EXECUTE sp_MSforeachtable 'TRUNCATE TABLE ?', but that deleted my diagrams.
USE <DB name>;
GO
-- Disable all constraints in the database
EXEC sp_MSforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"
declare #catalog nvarchar(250);
declare #schema nvarchar(250);
declare #tbl nvarchar(250);
DECLARE i CURSOR LOCAL FAST_FORWARD FOR select
TABLE_CATALOG,
TABLE_SCHEMA,
TABLE_NAME
from INFORMATION_SCHEMA.TABLES
where
TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME != 'sysdiagrams'
AND TABLE_NAME != '__RefactorLog'
OPEN i;
FETCH NEXT FROM i INTO #catalog, #schema, #tbl;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #sql NVARCHAR(MAX) = N'DELETE FROM [' + #catalog + '].[' + #schema + '].[' + #tbl + '];'
/* Make sure these are the commands you want to execute before executing */
PRINT 'Executing statement: ' + #sql
-- EXECUTE sp_executesql #sql
FETCH NEXT FROM i INTO #catalog, #schema, #tbl;
END
CLOSE i;
DEALLOCATE i;
-- Re-enable all constraints again
EXEC sp_MSforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"
Set nocount on
Exec sp_MSforeachtable 'Alter Table ? NoCheck Constraint All'
Exec sp_MSforeachtable
'
If ObjectProperty(Object_ID(''?''), ''TableHasForeignRef'')=1
Begin
-- Just to know what all table used delete syntax.
Print ''Delete from '' + ''?''
Delete From ?
End
Else
Begin
-- Just to know what all table used Truncate syntax.
Print ''Truncate Table '' + ''?''
Truncate Table ?
End
'
Exec sp_MSforeachtable 'Alter Table ? Check Constraint All'
If you just have constraints just paste this lines in the query and run it
EXEC sys.sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
EXEC sys.sp_msforeachtable 'DELETE FROM ?'
EXEC sys.sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
You could delete all the rows from all tables using an approach like Rubens suggested, or you could just drop and recreate all the tables. Always a good idea to have the full db creation scripts anyway so that may be the easiest/quickest method.
This answer builds on Zach Smith's answer by resetting the identity column as well:
Disabling all constraints
Iterating through all tables except those you choose to exclude
Deletes all rows from the table
Resets the identity column if one exists
Re-enables all constraints
Here is the query:
-- Disable all constraints in the database
EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"
declare #catalog nvarchar(250);
declare #schema nvarchar(250);
declare #tbl nvarchar(250);
DECLARE i CURSOR LOCAL FAST_FORWARD FOR select
TABLE_CATALOG,
TABLE_SCHEMA,
TABLE_NAME
from INFORMATION_SCHEMA.TABLES
where
TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME != 'sysdiagrams'
AND TABLE_NAME != '__RefactorLog'
-- Optional
-- AND (TABLE_SCHEMA = 'dbo')
OPEN i;
FETCH NEXT FROM i INTO #catalog, #schema, #tbl;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #sql NVARCHAR(MAX) = N'DELETE FROM [' + #catalog + '].[' + #schema + '].[' + #tbl + '];'
/* Make sure these are the commands you want to execute before executing */
PRINT 'Executing statement: ' + #sql
--EXECUTE sp_executesql #sql
-- Reset identity counter if one exists
IF ((SELECT OBJECTPROPERTY( OBJECT_ID(#catalog + '.' + #schema + '.' + #tbl), 'TableHasIdentity')) = 1)
BEGIN
SET #sql = N'DBCC CHECKIDENT ([' + #catalog + '.' + #schema + '.' + #tbl + '], RESEED, 0)'
PRINT 'Executing statement: ' + #sql
--EXECUTE sp_executesql #sql
END
FETCH NEXT FROM i INTO #catalog, #schema, #tbl;
END
CLOSE i;
DEALLOCATE i;
-- Re-enable all constraints again
EXEC sp_msforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"
For some requirements we might have to skip certain tables. I wrote the below script to add some extra conditions to filter the list of tables. The below script will also display the pre delete count and post delete count.
IF OBJECT_ID('TEMPDB..#TEMPRECORDCOUNT') IS NOT NULL
DROP TABLE #TEMPRECORDCOUNT
CREATE TABLE #TEMPRECORDCOUNT
( TABLENAME NVARCHAR(128)
,PREDELETECOUNT BIGINT
,POSTDELETECOUNT BIGINT
)
INSERT INTO #TEMPRECORDCOUNT (TABLENAME, PREDELETECOUNT, POSTDELETECOUNT)
SELECT O.name TableName
,DDPS.ROW_COUNT PREDELETECOUNT
,NULL FROM sys.objects O
INNER JOIN (
SELECT OBJECT_ID, SUM(row_count) ROW_COUNT
FROM SYS.DM_DB_PARTITION_STATS
GROUP BY OBJECT_ID
) DDPS ON DDPS.OBJECT_ID = O.OBJECT_ID
WHERE O.type = 'U' AND O.name NOT LIKE 'OC%' AND O.schema_id = 1
DECLARE #TableName NVARCHAR(MAX);
DECLARE TableDeleteCursor CURSOR FAST_FORWARD
FOR
SELECT TableName from #TEMPRECORDCOUNT
OPEN TableDeleteCursor
FETCH NEXT FROM TableDeleteCursor INTO #TableName
WHILE (##FETCH_STATUS <> -1)
BEGIN
IF (##FETCH_STATUS <> -2)
BEGIN
DECLARE #STATEMENT NVARCHAR(MAX);
SET #STATEMENT = ' DISABLE TRIGGER ALL ON ' + #TableName +
'; ALTER TABLE ' + #TableName + ' NOCHECK CONSTRAINT ALL' +
'; DELETE FROM ' + #TableName +
'; ALTER TABLE ' + #TableName + ' CHECK CONSTRAINT ALL' +
'; ENABLE TRIGGER ALL ON ' + #TableName;
PRINT #STATEMENT
EXECUTE SP_EXECUTESQL #STATEMENT;
END
FETCH NEXT FROM TableDeleteCursor INTO #TableName
END
CLOSE TableDeleteCursor
DEALLOCATE TableDeleteCursor
UPDATE T
SET T.POSTDELETECOUNT = I.ROW_COUNT
FROM #TEMPRECORDCOUNT T
INNER JOIN (
SELECT O.name TableName, DDPS.ROW_COUNT ROW_COUNT
FROM sys.objects O
INNER JOIN (
SELECT OBJECT_ID, SUM(row_count) ROW_COUNT
FROM SYS.DM_DB_PARTITION_STATS
GROUP BY OBJECT_ID
) DDPS ON DDPS.OBJECT_ID = O.OBJECT_ID
WHERE O.type = 'U' AND O.name NOT LIKE 'OC%' AND O.schema_id = 1
) I ON I.TableName COLLATE DATABASE_DEFAULT = T.TABLENAME
SELECT * FROM #TEMPRECORDCOUNT
ORDER BY TABLENAME ASC
--Load tables to delete from
SELECT
DISTINCT
' Delete top 1000000 from <DBName>.<schema>.' + c.TABLE_NAME + ' WHERE <Filter Clause Here>' AS query,c.TABLE_NAME AS TableName, IsDeleted=0, '<InsertSomeDescriptorHere>' AS [Source]--,t.TABLE_TYPE, c.*
INTO dbo.AllTablesToDeleteFrom
FROM INFORMATION_SCHEMA.TABLES AS t
INNER JOIN information_schema.columns c ON c.TABLE_NAME = t.TABLE_NAME
WHERE c.COLUMN_NAME = '<column name>'
AND c.TABLE_SCHEMA = 'dbo'
AND c.TABLE_CATALOG = '<DB Name here>'
AND t.TABLE_TYPE='Base table'
--AND t.TABLE_NAME LIKE '<put filter here>'
DECLARE #TableSelect NVARCHAR(1000)= '';
DECLARE #Table NVARCHAR(1000)= '';
DECLARE #IsDeleted INT= 0;
DECLARE #NumRows INT = 1000000;
DECLARE #Source NVARCHAR(50)='';
WHILE ( #IsDeleted = 0 )
BEGIN
--This grabs one table at a time to be deleted from. #TableSelect has the sql to execute. it is important to order by IsDeleted ASC
--because it will pull tables to delete from by those that have a 0=IsDeleted first. Once the loop grabs a table with IsDeleted=1 then this will pop out of loop
SELECT TOP 1
#TableSelect = query,
#IsDeleted = IsDeleted,
#Table = TableName,
#Source=[a].[Source]
FROM dbo.AllTablesToDeleteFrom a
WHERE a.[Source]='SomeDescriptorHere'--use only if needed
ORDER BY a.IsDeleted ASC;--this is required because only those records returned with IsDeleted=0 will run through loop
--SELECT #Table; can add this in to monitor what table is being deleted from
WHILE ( #NumRows = 1000000 )--only delete a million rows at a time?
BEGIN
EXEC sp_executesql #TableSelect;
SET #NumRows = ##ROWCOUNT;
--IF #NumRows = 1000000 --can do something here if needed
--One wants this loop to continue as long as a million rows is deleted. Once < 1 million rows is deleted it pops out of loop
--and grabs next table to delete
-- BEGIN
--SELECT #NumRows;--can add this in to see current number of deleted records for table
INSERT INTO dbo.DeleteFromAllTables
( tableName,
query,
cnt,
[Source]
)
SELECT #Table,
#TableSelect,
#NumRows,
#Source;
-- END;
END;
SET #NumRows = 1000000;
UPDATE a
SET a.IsDeleted = 1
FROM dbo.AllTablesToDeleteFrom a
WHERE a.TableName = #Table;
--flag this as deleted so you can move on to the next table to delete from
END;
if you want to delete the whole table, you must follow the next SQL instruction
Delete FROM TABLE Where PRIMARY_KEY_ is Not NULL;