How to delete all rows from all tables in a SQL Server database?
-
See http://www.codeguru.com/forum/showthread.php?t=458182 and scroll down... – Wim ten Brink Dec 14 '09 at 09:24
-
5by drop database will be deleted i just want to reset data – Dec 14 '09 at 09:27
12 Answers
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.

- 693
- 5
- 17

- 9,274
- 1
- 32
- 58
-
1Actually, that's only for DDL triggers. In which case: EXECP sp_MSForEachTable 'DISABLE TRIGGER ALL ON ?' – Mark Rendle Dec 14 '09 at 09:34
-
13
-
Ok I'm a bit confused (maybe you can help) I made a backup of my database and it was about 10 MB, then I ran your SQL code above to empty my database and I made a new backup of what I thought was the empty database to send to someone else in an email but my 'empty' database backup was now 14 MB? What did I do wrong? – Ben Dec 08 '14 at 15:27
-
1Got it - if a backup file already exists then it looks like SSMS appends to it rather than replacing it (I didn't realize this). So I deleted the file and now the 'empty' database backup file is only 3.7 MB – Ben Dec 08 '14 at 15:34
-
1What if I want to choose the DB, something like: `USE [MyDataBase]`? Would the above idea work, if adapted somehow?... Because I don't wanna delete all the DBs kept by the SQL server. – סטנלי גרונן Nov 10 '16 at 09:45
-
2Here is a link to create the sp_MSForEachTable procedure for SQL Azure https://gist.github.com/metaskills/893599 – Breakskater May 01 '18 at 06:32
-
This causes an error if database contains Views from which you cannot delete. – AgentFire May 30 '18 at 16:30
-
Should we literally type the '?', or does something go in place of the '?' ? Also, how do we specify which database we want this to happen in? AKA if I'm in a query window for 'db1' database, will the above code only affect the `db1` database? – Kyle Vassella Jun 16 '20 at 00:17
-
-
What if I also want to set auto increment to 1 in all autoincremental PKs? – Javier Pallarés Jul 22 '21 at 10:53
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'

- 6,322
- 7
- 47
- 75

- 551
- 4
- 4
-
1You can simply execute step 2 mutliple times so that first time it deletes tables with non dependencies, 2nd time to delete those tables failed in first time, 3rd time to delete faild in 2nd time, etc – Jun 03 '16 at 22:10
-
-
This approach will work also in Azure as it uses only plain SQL: http://www.sqlrelease.com/delete-all-rows-from-all-tables – Jakob Lithner Nov 19 '18 at 12:37
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!

- 1,312
- 15
- 20
-
Thanks for this one, because I needed to tweak the select to eliminate some tables. This worked well for that. – Don Rolling Feb 16 '16 at 15:17
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

- 89
- 2
- 9

- 26,513
- 49
- 182
- 323
-
Worked for me - before I was getting this error: `DELETE failed because the following SET options have incorrect settings: 'QUOTED_IDENTIFIER'. Verify that SET options are correct for use with indexed views and/or indexes on computed columns and/or filtered indexes and/or query notifications and/or XML data type methods and/or spatial index operations.` – DharmaTurtle Jan 22 '20 at 02:33
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"

- 89
- 2
- 9

- 8,458
- 13
- 59
- 133
-
1
-
I've never used non dbo schemas, so I wouldn't catch that. But why doesn't it work? I'm not specifying schema anywhere so does it default to dbo only? – Zach Smith Jan 20 '18 at 18:32
-
1If you have a table, for example, called test.Table1, where "test" is the schema, your deletes will fail if trying to execute "DELETE FROM Table1". It needs to be DELETE FROM test.Table1. – influent Jan 22 '18 at 19:03
-
2
-
Unfortunately this seems to fail if there are FK constraints. The `ALTER TABLE` bit to disable constraints fails. – Douglas Gaskell Nov 10 '18 at 02:48
-
-
-
2Indeed @FluidMechanicsPotentialFlows - the `EXECUTE sp_executesql @sql` statement is commented out. This is just in case someone were to copy/paste this SQL into SSMS without reading it first – Zach Smith Feb 03 '22 at 08:32
-
oh that's smart, thanks, i don't understand much of the code though, don't really know where to start – FluidMechanics Potential Flows Feb 03 '22 at 13:40
-
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'

- 89
- 2
- 9

- 2,350
- 6
- 31
- 57
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'

- 92
- 1
- 9
-
This worked like a charm are there any unintentional consequences that may arise from this? I just set up a clone of our prod database for some testing and used this to remove all the records from every table is there any possibility this can affect any other data? – d0rf47 Sep 23 '22 at 19:45
-
Sorry for the delay, but nothing happened to ower production tables, or QA tables. It's safe. – Helder Pereira Oct 11 '22 at 16:38
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.

- 142,592
- 28
- 206
- 200
-
seems OP is concerned about referential integrity and triggers; this case, your got best solution. I'm dropping my answer =) – Rubens Farias Dec 14 '09 at 09:31
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"

- 2,081
- 2
- 24
- 41
-
For one reason or another this mostly fails as it throws FK constraint errors. – Douglas Gaskell Nov 10 '18 at 02:46
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

- 1,345
- 12
- 16
--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;