273

I'm trying to write a script that will completely empty a SQL Server database. This is what I have so far:

USE [dbname]
GO
EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all'
EXEC sp_msforeachtable 'DELETE ?'

When I run it in the Management Studio, I get:

Command(s) completed successfully.

but when I refresh the table list, they are all still there. What am I doing wrong?

Arulkumar
  • 12,966
  • 14
  • 47
  • 68
dixuji
  • 2,733
  • 3
  • 14
  • 4

17 Answers17

492

You can also delete all tables from database using only MSSMS UI tools (without using SQL script). Sometimes this way can be more comfortable (especially if it is performed occasionally)

I do this step by step as follows:

  1. Select 'Tables' on the database tree (Object Explorer)
  2. Press F7 to open Object Explorer Details view
  3. In this view select tables which have to be deleted (in this case all of them)
  4. Keep pressing Delete until all tables have been deleted (you repeat it as many times as amount of errors due to key constraints/dependencies)
Bronek
  • 10,722
  • 2
  • 45
  • 46
390

It doesn't work for me either when there are multiple foreign key tables.
I found that code that works and does everything you try (delete all tables from your database):

DECLARE @Sql NVARCHAR(500) DECLARE @Cursor CURSOR

SET @Cursor = CURSOR FAST_FORWARD FOR
SELECT DISTINCT sql = 'ALTER TABLE [' + tc2.TABLE_SCHEMA + '].[' +  tc2.TABLE_NAME + '] DROP [' + rc1.CONSTRAINT_NAME + '];'
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc1
LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc2 ON tc2.CONSTRAINT_NAME =rc1.CONSTRAINT_NAME

OPEN @Cursor FETCH NEXT FROM @Cursor INTO @Sql

WHILE (@@FETCH_STATUS = 0)
BEGIN
Exec sp_executesql @Sql
FETCH NEXT FROM @Cursor INTO @Sql
END

CLOSE @Cursor DEALLOCATE @Cursor
GO

EXEC sp_MSforeachtable 'DROP TABLE ?'
GO

You can find the post here. It is the post by Groker.

Justin Dearing
  • 14,270
  • 22
  • 88
  • 161
Gabriel GM
  • 6,391
  • 2
  • 31
  • 34
  • Why is it when you try to wrap that entire block of code in a IF statement using a BEGIN-END block it complains about the cursor? – Adam Jul 01 '15 at 20:25
  • 15
    I am getting error `Could not find stored procedure 'sp_MSForEachTable'.` – Korayem Apr 27 '16 at 04:29
  • Then you can loop through all tables manually. See Harpal's answer. – Gabriel GM Apr 27 '16 at 17:07
  • sp_MSForEachTable doesn't exist under Azure. Use @Bronek Answer instead – Byron Whitlock Aug 14 '16 at 04:37
  • 2
    This answer does not work if you have tables (with constraints) in a different schema than `dbo`. If you have custom schemas, you need to alter the `sql` to: `SELECT DISTINCT sql = 'ALTER TABLE [' + tc2.CONSTRAINT_SCHEMA + '].[' + tc2.TABLE_NAME + '] DROP [' + rc1.CONSTRAINT_NAME + ']'` – Asbjørn Ulsberg Nov 03 '16 at 08:59
  • Note that if you are using a case sensitive database then it needs to be `sp_MSforeachtable` instead of `sp_MSForEachTable`, and `SP_EXECUTESQL` should be `sp_executesql`. – Paul Wagland Dec 08 '16 at 13:47
  • 7
    `sp_MSforeachtable` is not available in Azure. Use @CountZero's answer instead. – Ogglas Jan 19 '18 at 08:58
  • 3
    Found this reference on the web (not mine): A Copy Of sp_MSforeachtable Stored Procedure For Azure, Uses sp_MSforeach_worker : https://gist.github.com/metaskills/893599. – João Vieira Aug 10 '18 at 11:05
101

In SSMS:

  • Right click the database
  • Go to "Tasks"
  • Click "Generate Scripts"
  • In the "Choose Objects" section, select "Script entire database and all database objects"
  • In the "Set Scripting Options" section, click the "Advanced" button
  • On "Script DROP and CREATE" switch "Script CREATE" to "Script DROP" and press OK
  • Then, either save to file, clipboard, or new query window.
  • Run script.

Now, this will drop everything, including the database. Make sure to remove the code for the items you don't want dropped. Alternatively, in the "Choose Objects" section, instead of selecting to script entire database just select the items you want to remove.

Ben
  • 1,820
  • 2
  • 14
  • 25
  • 8
    If you don't want to drop the database (which in my case I don't as I'd then need to make a support call to get it created) then use 'Select specific database objects' and select all the object types that you do wish to drop. – d219 Jul 27 '18 at 22:38
  • 6
    This is the easiest way. – Asiri Dissanayaka Dec 27 '18 at 06:14
  • 7
    This should be the answer for sure! – Zac Taylor Oct 08 '19 at 22:56
  • For anyone looking for this option with SSMS 18, they've added the "Generate scripts..."-option directly in the right-click menu. – Fjurg May 03 '23 at 06:57
67

The accepted answer doesn't support Azure. It uses an undocumented stored procedure "sp_MSforeachtable". If you get an "azure could not find stored procedure 'sp_msforeachtable" error when running or simply want to avoid relying on undocumented features (which can be removed or have their functionality changed at any point) then try the below.

This version ignores the entity framework migration history table "__MigrationHistory" and the "database_firewall_rules" which is an Azure table you will not have permission to delete.

Lightly tested on Azure. Do check to make this this has no undesired effects on your environment.

DECLARE @sql NVARCHAR(2000)

WHILE(EXISTS(SELECT 1 from INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE='FOREIGN KEY'))
BEGIN
    SELECT TOP 1 @sql=('ALTER TABLE ' + TABLE_SCHEMA + '.[' + TABLE_NAME + '] DROP CONSTRAINT [' + CONSTRAINT_NAME + ']')
    FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
    WHERE CONSTRAINT_TYPE = 'FOREIGN KEY'
    EXEC(@sql)
    PRINT @sql
END

WHILE(EXISTS(SELECT * from INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME != '__MigrationHistory' AND TABLE_NAME != 'database_firewall_rules'))
BEGIN
    SELECT TOP 1 @sql=('DROP TABLE ' + TABLE_SCHEMA + '.[' + TABLE_NAME + ']')
    FROM INFORMATION_SCHEMA.TABLES
    WHERE TABLE_NAME != '__MigrationHistory' AND TABLE_NAME != 'database_firewall_rules'
    EXEC(@sql)
    PRINT @sql
END

Taken from:

https://edspencer.me.uk/2013/02/25/drop-all-tables-in-a-sql-server-database-azure-friendly/

http://www.sqlservercentral.com/blogs/sqlservertips/2011/10/11/remove-all-foreign-keys/

CountZero
  • 6,171
  • 3
  • 46
  • 59
50

delete is used for deleting rows from a table. You should use drop table instead.

EXEC sp_msforeachtable 'drop table [?]'
DaveShaw
  • 52,123
  • 16
  • 112
  • 141
  • That seemed to have fixed the problem of not having any errors, but now I'm running into constraint errors. Is the syntax of my `NOCHECK CONSTRAINT` line wrong? – dixuji Dec 09 '11 at 00:38
  • 1
    I used this on a quick 2 tables with FK's and it worked. EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all' – DaveShaw Dec 09 '11 at 00:47
  • 16
    This only worked for me after I removed the square brackets: EXEC sp_msforeachtable 'drop table ?'. – LPains Oct 22 '15 at 14:40
  • On SQL Server you need the brackets if any table name has any odd characters or spaces. I've not known a version of SQL Server that didn't support brackets around object names. – DaveShaw Oct 22 '15 at 14:54
  • On SQL Server 2012 (11.x) I also had to remove the square brackets. – Frieder Apr 02 '19 at 13:42
  • `sp_msforeachtable` [already adds the brackets](https://www.sqlshack.com/an-introduction-to-sp_msforeachtable-run-commands-iteratively-through-all-tables-in-a-database/) (at least in recent versions), so they should be removed from your code example. `EXEC sp_msforeachtable 'drop table ?'` is correct. – Heinzi Dec 15 '22 at 14:22
34

You are almost right, use instead:

EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all'
EXEC sp_msforeachtable 'DROP TABLE ?'

but second line you might need to execute more then once until you stop getting error:

Could not drop object 'dbo.table' because it is referenced by a FOREIGN KEY constraint.

Message:

Command(s) completed successfully.

means that all table were successfully deleted.

Michał Powaga
  • 22,561
  • 8
  • 51
  • 62
31
/* Drop all Primary Key constraints */
DECLARE @name VARCHAR(128)
DECLARE @constraint VARCHAR(254)
DECLARE @SQL VARCHAR(254)

SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME)

WHILE @name IS NOT NULL
BEGIN
    SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
    WHILE @constraint is not null
    BEGIN
        SELECT @SQL = 'ALTER TABLE [dbo].[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@constraint)+']'
        EXEC (@SQL)
        PRINT 'Dropped PK Constraint: ' + @constraint + ' on ' + @name
        SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND CONSTRAINT_NAME <> @constraint AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
    END
SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME)
END
GO

/* Drop all tables */
DECLARE @name VARCHAR(128)
DECLARE @SQL VARCHAR(254)

SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 ORDER BY [name])

WHILE @name IS NOT NULL
BEGIN
    SELECT @SQL = 'DROP TABLE [dbo].[' + RTRIM(@name) +']'
    EXEC (@SQL)
    PRINT 'Dropped Table: ' + @name
    SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 AND [name] > @name ORDER BY [name])
END
GO
Harpal
  • 1,729
  • 17
  • 18
23

Short and sweet:

USE YOUR_DATABASE_NAME
-- Disable all referential integrity constraints
EXEC sp_MSforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
GO

-- Drop all PKs and FKs
declare @sql nvarchar(max)
SELECT @sql = STUFF((SELECT '; ' + 'ALTER TABLE ' + Table_Name  +'  drop constraint ' + Constraint_Name  from Information_Schema.CONSTRAINT_TABLE_USAGE ORDER BY Constraint_Name FOR XML PATH('')),1,1,'')
EXECUTE (@sql)
GO

-- Drop all tables
EXEC sp_MSforeachtable 'DROP TABLE ?'
GO
xx1xx
  • 1,834
  • 17
  • 16
11

Spot on!!

You can use below query to remove all the tables from database

EXEC sp_MSforeachtable @command1 = "DROP TABLE ?"

Happy coding !

Gajanan Kulkarni
  • 697
  • 6
  • 22
10

Seems the command should be without the square blanket

EXEC sp_msforeachtable 'drop table ?'
Jimmy Wong
  • 492
  • 4
  • 5
10

The fasted way is:

  1. New Database Diagrams
  2. Add all table
  3. Ctrl + A to select all
  4. Right Click "Remove from Database"
  5. Ctrl + S to save
  6. Enjoy
TuanDPH
  • 461
  • 5
  • 14
7

For me, the easiest way:

--First delete all constraints

DECLARE @sql NVARCHAR(MAX);
SET @sql = N'';

SELECT @sql = @sql + N'
ALTER TABLE ' + QUOTENAME(s.name) + N'.'
+ QUOTENAME(t.name) + N' DROP CONSTRAINT '
+ QUOTENAME(c.name) + ';'
FROM sys.objects AS c
INNER JOIN sys.tables AS t
ON c.parent_object_id = t.[object_id]
INNER JOIN sys.schemas AS s 
ON t.[schema_id] = s.[schema_id]
WHERE c.[type] IN ('D','C','F','PK','UQ')
ORDER BY c.[type];

EXEC sys.sp_executesql @sql;

-- Then drop all tables

exec sp_MSforeachtable 'DROP TABLE ?'
Jeffrey
  • 111
  • 1
  • 4
4

Azure SQL + tables (with constraints) in a different schema than dbo + ipv6_database_firewall_rules condition.

This is a little extension for https://stackoverflow.com/a/43128914/4510954 answer.

DECLARE @sql NVARCHAR(2000)

WHILE(EXISTS(SELECT 1 from INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE='FOREIGN KEY'))
BEGIN
    SELECT TOP 1 @sql=('ALTER TABLE ' + CONSTRAINT_SCHEMA + '.[' + TABLE_NAME + '] DROP CONSTRAINT [' + CONSTRAINT_NAME + ']')
    FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
    WHERE CONSTRAINT_TYPE = 'FOREIGN KEY'
    EXEC(@sql)
    PRINT @sql
END

WHILE(EXISTS(SELECT * from INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME != '__MigrationHistory' AND TABLE_NAME != 'database_firewall_rules' AND TABLE_NAME != 'ipv6_database_firewall_rules'))
BEGIN
    SELECT TOP 1 @sql=('DROP TABLE ' + CONSTRAINT_SCHEMA  + '.[' + TABLE_NAME + ']')
    FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
    WHERE TABLE_NAME != '__MigrationHistory' AND TABLE_NAME != 'database_firewall_rules'
    EXEC(@sql)
    PRINT @sql
END
ElConrado
  • 1,477
  • 4
  • 20
  • 46
3

How about dropping the entire database and then creating it again? This works for me.

DROP DATABASE mydb;
CREATE DATABASE mydb;
Chong Lip Phang
  • 8,755
  • 5
  • 65
  • 100
  • Don't you need to blast the mdf & ldf files in between? – ruffin Aug 27 '15 at 14:41
  • I am using a web host provider and I am not too sure about that. I think those files will be deleted automatically when you drop a database, unless you are offline. – Chong Lip Phang Aug 28 '15 at 05:17
  • 2
    It really depends on the circumstances. In my case, I don't have stored procedures and this method works fine for me. I am not going to write complex codes that span dozens of lines when two lines will do. I don't think my answer justifies a downvote as I am offering a suggestion to a specific group of users. – Chong Lip Phang Nov 13 '15 at 11:20
2

For Temporal Tables it is a bit more complicated due to the fact there may be some foreign keys and also exception:

Drop table operation failed on table XXX because it is not a supported operation on system-versioned temporal tables

What you can use is:

-- Disable constraints (foreign keys)
EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
GO

-- Disable system versioning (temporial tables)
EXEC sp_MSForEachTable '
 IF OBJECTPROPERTY(object_id(''?''), ''TableTemporalType'') = 2
  ALTER TABLE ? SET (SYSTEM_VERSIONING = OFF)
'
GO

-- Removing tables
EXEC sp_MSForEachTable 'DROP TABLE ?'
GO
J.Wincewicz
  • 849
  • 12
  • 19
2

sp_msforeachtable is not available in Azure SQL

For Azure SQL:

This query will drop Foreign Key constraints

DECLARE @Name VARCHAR(200)
DECLARE @Constraint VARCHAR(300)
DECLARE @SQL VARCHAR(300)

SELECT @Name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME)

WHILE @Name is not null
BEGIN
    SELECT @Constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND TABLE_NAME = @Name ORDER BY CONSTRAINT_NAME)
    WHILE @Constraint IS NOT NULL
    BEGIN
        SELECT @SQL = 'ALTER TABLE [dbo].[' + RTRIM(@Name) +'] DROP CONSTRAINT [' + RTRIM(@Constraint) +']'
        EXEC (@SQL)
        PRINT 'Dropped FK Constraint: ' + @Constraint + ' on ' + @Name
        SELECT @Constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND CONSTRAINT_NAME <> @Constraint AND TABLE_NAME = @Name ORDER BY CONSTRAINT_NAME)
    END
SELECT @Name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME)
END
GO

This will drop all the tables from the database

DECLARE @Name VARCHAR(200)
DECLARE @SQL VARCHAR(300)

SELECT @Name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 ORDER BY [name])

WHILE @Name IS NOT NULL
BEGIN
    SELECT @SQL = 'DROP TABLE [dbo].[' + RTRIM(@name) +']' /*here you can change schema if it is different from dbo*/
    EXEC (@SQL)
    PRINT 'Dropped Table: ' + @Name
    SELECT @Name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 AND [name] > @Name ORDER BY [name])
END
GO
Talha Tayyab
  • 8,111
  • 25
  • 27
  • 44
1

I know this is an old post now but I have tried all the answers on here on a multitude of databases and I have found they all work sometimes but not all of the time for various (I can only assume) quirks of SQL Server.

Eventually I came up with this. I have tested this everywhere (generally speaking) I can and it works (without any hidden store procedures).

For note mostly on SQL Server 2014. (but most of the other versions I tried it also seems to worked fine).

I have tried while loops and nulls etc etc, cursors and various other forms but they always seem to fail on some databases but not others for no obvious reason.

Getting a count and using that to iterate always seems to work on everything Ive tested.

USE [****YOUR_DATABASE****]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

-- Drop all referential integrity constraints --
-- Drop all Primary Key constraints.          --

DECLARE @sql  NVARCHAR(296)
DECLARE @table_name VARCHAR(128)

DECLARE @constraint_name VARCHAR(128)
SET @constraint_name = ''

DECLARE @row_number INT

SELECT @row_number = Count(*) FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc1
LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc2 ON tc2.CONSTRAINT_NAME = rc1.CONSTRAINT_NAME

WHILE @row_number > 0
BEGIN
    BEGIN
        SELECT TOP 1 @table_name = tc2.TABLE_NAME, @constraint_name = rc1.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc1
        LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc2 ON tc2.CONSTRAINT_NAME = rc1.CONSTRAINT_NAME
        AND rc1.CONSTRAINT_NAME > @constraint_name
        ORDER BY rc1.CONSTRAINT_NAME
        SELECT @sql = 'ALTER TABLE [dbo].[' + RTRIM(@table_name) +'] DROP CONSTRAINT [' + RTRIM(@constraint_name)+']'
        EXEC (@sql)
        PRINT 'Dropped Constraint: ' + @constraint_name + ' on ' + @table_name
        SET @row_number = @row_number - 1
    END
END
GO

-- Drop all tables --

DECLARE @sql  NVARCHAR(156)
DECLARE @name VARCHAR(128)
SET @name = ''

DECLARE @row_number INT

SELECT @row_number = Count(*) FROM sysobjects WHERE [type] = 'U' AND category = 0

WHILE @row_number > 0
BEGIN
    SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 AND [name] > @name ORDER BY [name])
    SELECT @sql = 'DROP TABLE [dbo].[' + RTRIM(@name) +']'
    EXEC (@sql)
    PRINT 'Dropped Table: ' + @name
    SET @row_number = @row_number - 1
END
GO
William Humphreys
  • 1,206
  • 1
  • 14
  • 38