【问题标题】:Delete all data in SQL Server database删除 SQL Server 数据库中的所有数据
【发布时间】:2011-04-10 21:30:40
【问题描述】:

如何从我的数据库的所有表中删除所有记录?我可以使用一条 SQL 命令来完成,还是需要一张表执行一条 SQL 命令?

【问题讨论】:

    标签: sql sql-server delete-row multi-table-delete


    【解决方案1】:

    结合现有答案中的所有优秀技巧以及更多技巧,我编写了这个脚本。它更全面一些,应该更有效率。

    在删除步骤之前的脚本:

    • 禁用触发器(如果您有任何 on delete 时尤其重要 触发器)
    • 禁用约束检查
    • 禁用非聚集索引(否则它们会被逐行删除 和桌子)

    对于删除步骤,它会在可能的情况下截断(更快),或者使用 tabblock 提示删除(tablock 只会对堆表有帮助,因为无论如何我们都会缩小文件,所以它可能不会在此处添加任何内容)。

    在删除步骤之后,脚本将:

    • 重建/启用所有索引(无论如何都是空的)
    • 启用约束检查
    • 启用触发器
    • 重新播种身份列
    • 收缩数据库文件

    从数据库中删除所有数据:

    use [your_database]
    go
    
    exec sp_MSforeachtable 'alter table ? disable trigger all'
    go
    
    exec sp_MSforeachtable 'alter table ? nocheck constraint all'
    go
    
    -- Disable enabled nonclustered indices
    declare @script nvarchar(max)
    declare cr cursor fast_forward read_only for
    select 'alter index ' + quotename(i.name) + ' on ' + quotename(schema_name(t.schema_id))+'.'+ quotename(t.name) + ' disable'
    from sys.indexes i inner join sys.tables t on i.object_id = t.object_id
    where i.type_desc = 'nonclustered' and i.name is not null and i.is_disabled = 0;
    open cr
    fetch next from cr into @script
    while @@fetch_status = 0
    begin
        execute sp_executesql @script 
        fetch next from cr into @script
    end
    close cr
    deallocate cr
    go
    
    exec sp_MSforeachtable 'set quoted_identifier on; if objectproperty(object_id(''?''), ''TableHasForeignRef'') = 1 delete from ? with (tablock) else truncate table ?'
    go
    
    exec sp_MSforeachtable 'set quoted_identifier on; alter index all on ? rebuild';
    go
    
    exec sp_MSforeachtable 'alter table ? with check check constraint all'
    go
    
    exec sp_MSforeachtable 'alter table ? enable trigger all'
    go
    
    -- Re-seed identity columns
    exec sp_MSforeachtable 'if objectproperty(object_id(''?''), ''TableHasIdentity'') = 1 dbcc checkident(''?'', reseed, 0)'
    go
    
    -- Shrink the database files
    declare @db_name nvarchar(200) = db_name()
    dbcc shrinkdatabase (@db_name, 0);  
    go 
    

    【讨论】:

      【解决方案2】:

      为自己节省一些时间/空间,并尽可能使用 TRUNCATE 而不是 DELETE, 如果您拥有庞大的数据库,则不会使您的日志文件膨胀。

      EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK 约束所有' 去吧

      执行 sp_MSForEachTable ' IF OBJECTPROPERTY(object_id(''?''), ''TableHasForeignRef'') = 1 从中删除? 别的 截断表?'

      EXEC sp_MSForEachTable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL' 去吧

      【讨论】:

        【解决方案3】:

        作为替代答案,如果您使用 Visual Studio SSDT 或 Red Gate Sql Compare,您可以简单地运行模式比较,编写脚本,删除旧数据库(可能先进行备份,以防万一您将需要该数据),然后使用比较工具创建的脚本创建一个新数据库。虽然在非常小的数据库上这可能需要更多的工作,但在非常大的数据库上,简单地删除数据库然后处理数据库上可能存在的不同触发器和约束会更快。

        【讨论】:

          【解决方案4】:

          可以,一行代码就可以删除

          SELECT 'TRUNCATE TABLE ' + d.NAME + ';' 
          FROM   sys.tables d 
          WHERE  type = 'U' 
          

          【讨论】:

          • 这给了我一个新表,每个表都有一个截断语句。它实际上并没有删除任何东西,不幸的是它首先解决了删除约束的问题。太糟糕了,我希望得到这样的答案,而不使用 sp_MSForEachTable(对我来说不存在,Azure SQL Server)!
          • 是的。真的。它为所有表创建截断脚本。使用该脚本删除表数据。
          • 此解决方案仅在没有任何关系的情况下有效,因为它无法保证以正确的顺序删除表。此外,如果删除数据有任何触发因素,这可能会造成意想不到的后果。
          【解决方案5】:

          下面是我用来从 SQL Server 数据库中删除所有数据的脚本

          ------------------------------------------------------------
          /* Use database */ 
          -------------------------------------------------------------
          
          use somedatabase;
          
          GO
          
          ------------------------------------------------------------------
          /* Script to delete an repopulate the base [init database] */
          ------------------------------------------------------------------
          
          -------------------------------------------------------------
          /* Procedure delete all constraints */ 
          -------------------------------------------------------------
          
          IF EXISTS (SELECT name  
                     FROM  sysobjects 
                     WHERE name = 'sp_DeleteAllConstraints' AND type = 'P')
              DROP PROCEDURE dbo.sp_DeleteAllConstraints
          GO
          
          CREATE PROCEDURE sp_DeleteAllConstraints
          AS
              EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
              EXEC sp_MSForEachTable 'ALTER TABLE ? DISABLE TRIGGER ALL'
          GO
          
          -----------------------------------------------------
          /* Procedure delete all data from the database */ 
          -----------------------------------------------------
          
          IF EXISTS (SELECT name  
                     FROM  sysobjects 
                     WHERE name = 'sp_DeleteAllData' AND type = 'P')
              DROP PROCEDURE dbo.sp_DeleteAllData
          GO
          
          CREATE PROCEDURE sp_DeleteAllData
          AS
              EXEC sp_MSForEachTable 'DELETE FROM ?'
          GO
          
          -----------------------------------------------
          /* Procedure enable all constraints */ 
          -----------------------------------------------
          
          IF EXISTS (SELECT name  
                     FROM  sysobjects 
                     WHERE name = 'sp_EnableAllConstraints' AND type = 'P')
              DROP PROCEDURE dbo.sp_EnableAllConstraints
          GO
          -- ....
          -- ....
          -- ....
          

          【讨论】:

            【解决方案6】:
            EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
            
            EXEC sp_MSForEachTable 'ALTER TABLE ? DISABLE TRIGGER ALL'
            
            EXEC sp_MSForEachTable 'DELETE FROM ?'
            
            EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
            
            EXEC sp_MSForEachTable 'ALTER TABLE ? ENABLE TRIGGER ALL'
            
            EXEC sp_MSFOREACHTABLE 'SELECT * FROM ?'
            
            GO
            

            【讨论】:

              【解决方案7】:

              SQLMenace 的解决方案对我有用,只是对删除数据的方式稍作调整 - DELETE FROM 而不是 TRUNCATE

              -- disable referential integrity
              EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL' 
              GO 
              
              EXEC sp_MSForEachTable 'DELETE FROM ?' 
              GO 
              
              -- enable referential integrity again 
              EXEC sp_MSForEachTable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL' 
              GO
              

              【讨论】:

              • 在 DELETE FROM 之后执行 EXEC sp_MSForEachTable 'DBCC CHECKIDENT(''?'', RESEED, 0)' 将所有标识列重置回 0 也可能有意义。
              • 当您发现 6 行代码替换了 100 条删除语句时,这总是一个好的开始!此方法在 SQL 2014 Express 上有效。
              • 别忘了禁用触发器
              • 我遇到了错误 - DELETE failed because the following SET options have incorrect settings: 'QUOTED_IDENTIFIER'...。为我工作:EXEC sp_MSForEachTable 'SET QUOTED_IDENTIFIER ON; DELETE FROM ?'
              • 在我这样做之前,并且对 SQL Server 没有完全信心,我注意到答案没有任何关于哪个数据库的指示。我的 SQL 服务器有很多数据库,我怎么能确信它只适用于我想要的数据库? (我肯定不会只是试一试,看看会发生什么!!!)
              【解决方案8】:
              1. 首先你必须禁用所有的触发器:

                sp_msforeachtable 'ALTER TABLE ? DISABLE TRIGGER all';
                
              2. 运行这个脚本:(取自post谢谢@SQLMenace)

                SET NOCOUNT ON
                GO
                
                SELECT 'USE [' + db_name() +']';
                ;WITH a AS 
                (
                     SELECT 0 AS lvl, 
                            t.object_id AS tblID 
                     FROM sys.TABLES t
                     WHERE t.is_ms_shipped = 0
                       AND t.object_id NOT IN (SELECT f.referenced_object_id 
                                               FROM sys.foreign_keys f)
                
                     UNION ALL
                
                     SELECT a.lvl + 1 AS lvl, 
                            f.referenced_object_id AS tblId
                     FROM a
                     INNER JOIN sys.foreign_keys f ON a.tblId = f.parent_object_id 
                                                   AND a.tblID <> f.referenced_object_id
                )
                SELECT 
                    'Delete from ['+ object_schema_name(tblID) + '].[' + object_name(tblId) + ']' 
                FROM a
                GROUP BY tblId 
                ORDER BY MAX(lvl),1
                

              此脚本将按正确顺序生成DELETE 语句。从引用的表开始,然后引用那些

              1. 复制DELETE FROM 语句并运行一次

              2. 启用触发器

                sp_msforeachtable 'ALTER TABLE ? ENABLE TRIGGER all'
                
              3. 提交更改:

                begin transaction
                commit;
                

              【讨论】:

              • 这对我不起作用,递归查询以循环结束。也许是因为自尊。
              【解决方案9】:

              我知道这已经晚了,但我同意 AlexKuznetsov 为数据库编写脚本的建议,而不是经历从表中清除数据的麻烦。如果TRUNCATE 解决方案不起作用,并且您恰好有大量数据,则发出(记录)DELETE 语句可能需要很长时间,并且您将留下尚未重新植入的标识符(即将INSERT 语句插入到具有IDENTITY 列的表中会得到一个ID 50000 而不是ID 1)。

              要编写整个数据库的脚本,在 SSMS 中,右键单击数据库,然后选择 TASKS -> Generate scripts

              单击Next 跳过向导打开屏幕,然后选择要编写脚本的对象:

              Set scripting options 屏幕中,您可以选择脚本设置,例如是为所有对象生成 1 个脚本,还是为各个对象生成单独的脚本,以及是以 Unicode 还是 ANSI 保存文件:

              向导将显示一个摘要,您可以使用它来验证一切是否符合要求,然后单击“完成”关闭。

              【讨论】:

              • 小心,如果你不去“高级”按钮,默认情况下你会丢失索引之类的东西。
              【解决方案10】:
              /* Drop all non-system stored procs */
              DECLARE @name VARCHAR(128)
              DECLARE @SQL VARCHAR(254)
              
              SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'P' AND category = 0 ORDER BY [name])
              
              WHILE @name is not null
              BEGIN
                  SELECT @SQL = 'DROP PROCEDURE [dbo].[' + RTRIM(@name) +']'
                  EXEC (@SQL)
                  PRINT 'Dropped Procedure: ' + @name
                  SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'P' AND category = 0 AND [name] > @name ORDER BY [name])
              END
              GO
              
              /* Drop all views */
              DECLARE @name VARCHAR(128)
              DECLARE @SQL VARCHAR(254)
              
              SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'V' AND category = 0 ORDER BY [name])
              
              WHILE @name IS NOT NULL
              BEGIN
                  SELECT @SQL = 'DROP VIEW [dbo].[' + RTRIM(@name) +']'
                  EXEC (@SQL)
                  PRINT 'Dropped View: ' + @name
                  SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'V' AND category = 0 AND [name] > @name ORDER BY [name])
              END
              GO
              
              /* Drop all functions */
              DECLARE @name VARCHAR(128)
              DECLARE @SQL VARCHAR(254)
              
              SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] IN (N'FN', N'IF', N'TF', N'FS', N'FT') AND category = 0 ORDER BY [name])
              
              WHILE @name IS NOT NULL
              BEGIN
                  SELECT @SQL = 'DROP FUNCTION [dbo].[' + RTRIM(@name) +']'
                  EXEC (@SQL)
                  PRINT 'Dropped Function: ' + @name
                  SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] IN (N'FN', N'IF', N'TF', N'FS', N'FT') AND category = 0 AND [name] > @name ORDER BY [name])
              END
              GO
              
              /* Drop all Foreign 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 = '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
              
              /* 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
              

              【讨论】:

              • 有趣的脚本,它不使用 Azure 上缺少的未经验证的存储过程“sp_MSForEachTable”。但是,如果您在 [dbo] 以外的其他模式上有对象,则需要进行调整。
              • 请使用gist.github.com/metaskills/893599在Azure中创建sp_MSForEachTable
              【解决方案11】:

              将数据库中的所有对象编写脚本并创建一个空的对象来删除或截断表通常要快得多。

              【讨论】:

                【解决方案12】:

                通常我只会使用未记录的 proc sp_MSForEachTable

                -- disable referential integrity
                EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL' 
                GO 
                
                EXEC sp_MSForEachTable 'TRUNCATE TABLE ?' 
                GO 
                
                -- enable referential integrity again 
                EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL' 
                GO
                

                另请参阅:Delete all data in database (when you have FKs)

                【讨论】:

                • 我认为这行不通。看起来 Kalen Delaney 无意中促成了这个想法。 Here she clarifies "你必须删除引用约束才能截断表。"
                • Martin 我 2 秒前刚刚在 Adventureworks DB 中运行它没有问题
                • 这里绝对不适合我。 create database testing; GO use testing; create table t1 (i int primary key) create table t2(i int primary key,p int references t1)
                • 这不起作用,尽管被标记为答案。对外键设置 nocheck 约束不允许您在这些表上运行截断命令。您仍然会收到阻止您截断的错误。
                • 由于存在外键,这不起作用。我仍然不明白为什么它被接受为答案:/
                猜你喜欢
                • 2018-01-15
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2023-03-10
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多