【问题标题】:Cannot truncate table because it is being referenced by a FOREIGN KEY constraint?无法截断表,因为它被 FOREIGN KEY 约束引用?
【发布时间】:2010-09-20 05:03:58
【问题描述】:

使用MSSQL2005,如果先截断子表(外键关系的主键的表),是否可以截断带外键约束的表?

我知道我也可以

  • 使用不带 where 子句的 DELETE,然后使用 RESEED 标识(或)
  • 删除 FK,截断表,然后重新创建 FK。

我认为只要我在父表之前截断子表,我就可以不执行上述任何一个选项,但是我收到了这个错误:

无法截断表“TableName”,因为它被 FOREIGN KEY 约束引用。

【问题讨论】:

标签: sql-server sql-server-2005 tsql truncate foreign-keys


【解决方案1】:
DELETE FROM TABLENAME
DBCC CHECKIDENT ('DATABASENAME.dbo.TABLENAME', RESEED, 0)

请注意,如果您有数百万条以上的记录,这可能不是您想要的,因为它非常慢。

【讨论】:

  • 这是有用的,比禁用和启用约束更快的方法。
  • 这仅适用于数据较少的表。同意@Pure
  • 这对于完成架构测试非常有用
  • 我不建议你走这条路,因为你也可能会得到这个错误:DELETE 语句与 REFERENCE 约束冲突
  • 对我不起作用。仍然收到 DELETE 语句与 REFERENCE 约束冲突。
【解决方案2】:

正确;您不能截断具有 FK 约束的表。

通常我的流程是:

  1. 放弃约束
  2. 截断表格
  3. 重新创建约束。

(当然,一切都在交易中。)

当然,这仅适用于 孩子已经被截断的情况。 否则我会走不同的路线,完全取决于我的数据是什么样的。 (这里的变量太多了。)

原发帖人确定了为什么会这样;有关详细信息,请参阅this answer。

【讨论】:

  • “DELETE FROM”不会重置自动递增的列。截断可以。它们在功能上并不等同。
  • 截断通常正是您要删除大量数据时想要执行的操作。截断一百万行?十亿? 1 毫秒...所以,@M07,请不要说“从方法中删除更干净”,因为这不太准确。
  • 删除大数据后,用户必须收缩表和日志文件以回收磁盘空间。
  • 99% 的情况下都不建议使用魔法收缩按钮(或脚本)。
  • 你会怎么做呢?示例请求?
【解决方案3】:

因为TRUNCATE TABLE 是DDL command,它无法检查表中的记录是否被子表中的记录引用。

这就是为什么DELETE 有效而TRUNCATE TABLE 无效的原因:因为数据库能够确保它没有被其他记录引用。

【讨论】:

  • 感谢您的解释!恕我直言,这应该是公认的答案(而公认的答案也很好)。
  • 现在我知道为什么我不能截断引用另一个空表的空表。
【解决方案4】:

没有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)

作为存储过程

https://github.com/reduardo7/TableTruncate

请注意,如果您有数百万条以上的记录,这可能不是您想要的,因为它非常慢。

【讨论】:

  • 在 DELETE FROM 之后使用 reseed new value = 1 将从 ID 2 开始,而不是 1。来自 Technet (technet.microsoft.com/en-us/library/ms176057%28SQL.90%29.aspx) 如果自创建表以来没有向表中插入任何行,或者使用 TRUNCATE TABLE 语句删除了所有行,运行 DBCC CHECKIDENT 后插入的第一行使用 new_reseed_value 作为标识。否则,插入的下一行使用 new_reseed_value + 当前增量值。
  • @ZoranP。请参阅存储过程变体:github.com/reduardo7/TableTruncate
  • DBCC CHECKIDENT ([TableName], RESEED, 0) not 1
  • @TicoFortes 帖子已更新。请参阅存储过程变体
  • 这不是一个好方法。正如对这个问题的相同答案的 700 个其他版本所评论的那样。除非您的数据库处于简单恢复模式,以限制事务日志记录。
【解决方案5】:

上面提供的@denver_citizen 解决方案对我不起作用,但我喜欢它的精神,所以我修改了一些东西:

  • 将其设为存储过程
  • 更改了外键的填充和重新创建方式
  • 原始脚本会截断所有引用的表,当被引用的表有其他外键引用时,这可能会导致外键冲突错误。此脚本仅截断指定为参数的表。由用户以正确的顺序在所有表上多次调用此存储过程

为了公众的利益,这里是更新的脚本:

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

【讨论】:

  • 这个答案值得更多投票!事实上,如果可以的话,我很乐意给你买啤酒,彼得 :)
  • 这对我今天快速清除一些大型数据表进行测试很有帮助,感谢您在这方面的优质工作。
  • 感谢您提供这段代码。但请注意,您应该添加一个额外的逻辑来检查禁用的 FK。否则,您将启用当前禁用的约束。
  • 我根据@AndreFigueiredo 的建议制作了一个版本。我把它放在 Gitlab 上:gitlab.com/ranolfi/truncate-referenced-table。随意将代码合并到您的答案中。
  • 这很好,但请注意,如果您的表不在默认 (dbo) 架构中,它将无法工作。
【解决方案6】:

在使用 delete 语句删除该表中的所有行后使用以下命令

delete from tablename

DBCC CHECKIDENT ('tablename', RESEED, 0)

编辑:更正 SQL Server 的语法

【讨论】:

  • TRUNCATE 避免了日志,并且对于大型表来说比DELETE 快​​得多。因此,这不是真正的等效解决方案。
  • 这个答案与 一年 之前给出的 that one 有何不同?
【解决方案7】:

好吧,因为我没有找到我使用的非常简单解决方案的示例,即:

  1. 删除外键;
  2. 截断表
  3. 重新创建外键

这里是:

1) 查找导致失败的外键名称(例如:FK_PROBLEM_REASON,字段为ID,来自表TABLE_OWNING_CONSTRAINT) 2)从表中删除该键:

ALTER TABLE TABLE_OWNING_CONSTRAINT DROP CONSTRAINT FK_PROBLEM_REASON

3) 截断通缉表

TRUNCATE TABLE TABLE_TO_TRUNCATE

4) 将密钥重新添加到第一个表中:

ALTER TABLE TABLE_OWNING_CONSTRAINT ADD CONSTRAINT FK_PROBLEM_REASON FOREIGN KEY(ID) REFERENCES TABLE_TO_TRUNCATE (ID)

就是这样。

【讨论】:

  • 如果您有多个带有外键引用的表,这将不起作用。您必须在整个数据库中删除大量外键限制。
  • 我收到Msg 3728, Level 16, State 1, Line 1 'FK_User_UserTypeID' is not a constraint. Msg 3727, Level 16, State 0, Line 1 Could not drop constraint. See previous errors.
【解决方案8】:

该过程正在删除外键约束并截断表 然后按照以下步骤添加约束。

    SET FOREIGN_KEY_CHECKS = 0; 

    truncate table "yourTableName";

    SET FOREIGN_KEY_CHECKS = 1;

【讨论】:

  • 这个问题是关于 MS SQL Server,它没有 FOREIGN_KEY_CHECKS 设置
  • 我认为这适用于 MySQL,但不适用于 MS SQL Server
  • 这个答案应该被删除。它与所讨论的系统无关...... MS SQL Server。这只会导致混乱。
【解决方案9】:

你可以按照这个步骤, 通过reseeding table可以删除表的数据。

delete from table_name
dbcc checkident('table_name',reseed,0)

如果出现一些错误,那么您必须重新设置主表的种子。

【讨论】:

  • 请记住,即使这很好用,事务日志也会增加表中的记录数,而“截断表”只会在事务日志中放置一条记录。对于大多数表来说没什么大不了的,但如果有数百万行以上,那么这可能是一个问题。
【解决方案10】:

这是我为了自动化这个过程而编写的一个脚本。希望对你有帮助。

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'

【讨论】:

  • 小心。我还会在脚本的键上添加引用操作,否则您将丢失级联设置。
  • 这对我不起作用,但我喜欢它的精神,所以我修改了一些东西:使它成为一个存储过程改变了外键的填充方式并重新创建了原始脚本截断所有引用的表,当引用的表不能被截断时,这可能是错误的,因为它也有外键引用。在这个版本中,只有指定为参数的表会被截断,所有引用的表都应该在调用这个脚本之前手动截断我在这里发布了更新的 tolution 到这个线程stackoverflow.com/a/13249209/157591
  • @alphadogg 有什么方法可以找到这些引用操作吗?我一直在互联网上四处寻找,似乎找不到它们。如果您愿意,我可以将其作为正式问题发布。
  • 未来访问者请注意:它位于sys.foreign_keys 表中。 (Reference)
  • @Michael:你也可以使用 INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS (msdn.microsoft.com/en-us/library/ms179987.aspx)
【解决方案11】:

@denver_citizen 和 @Peter Szanto 的答案对我来说不太适用,但我修改了它们以说明:

  1. 复合键
  2. 删除和更新操作
  3. 重新添加时检查索引
  4. dbo 以外的架构
  5. 一次多个表
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;

【讨论】:

    【解决方案12】:

    如果不删除约束,则无法截断表。禁用也不起作用。你需要放弃一切。我制作了一个脚本,删除所有约束,然后重新创建。

    确保将其包装在事务中;)

    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
    

    【讨论】:

      【解决方案13】:

      如果我理解正确,您想要做的是为涉及集成测试的数据库设置一个干净的环境。

      我在这里的方法是删除整个架构并稍后重新创建它。

      原因:

      1. 您可能已经有一个“创建模式”脚本。重复使用它进行测试隔离很容易。
      2. 创建架构非常快。
      3. 使用这种方法,很容易设置您的脚本,让每个夹具创建一个新模式(使用临时名称),然后您可以开始并行运行测试夹具,使测试中最慢的部分套件速度更快。

      【讨论】:

      • 我想“截断”所有架构,而不是删除它。我想在集成测试的设置方法中做到这一点。从集成测试中调用数据库创建脚本......不是我要使用的第一个解决方案。
      【解决方案14】:

      在网上其他地方找到

      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'
      

      【讨论】:

      【解决方案15】:

      truncate 对我不起作用,delete + 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
      

      【讨论】:

        【解决方案16】:

        我编写了以下方式并尝试将它们参数化,因此您可以在Query document中运行它们或轻松使用它们制作有用的SP。

        A) 删除

        如果您的表没有数百万条记录这很好用并且没有任何 Alter 命令:

        ---------------------------------------------------------------
        ------------------- 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)
        
        • 在我上面的回答中,解决问题中提到的问题的方法是基于@s15199danswer。

        B) 截断

        如果您的表有数百万条记录,或者您的代码中的 Alter command 没有任何问题,那么请使用这个:

        --   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
        
        • 在我上面的回答中,解决问题中提到的问题的方法是基于 @LauroWolffValenteSobrinho answer。

        • 如果您有多个 CONSTRAINT,那么您应该像我一样将其代码附加到上述查询中

        • 您还可以更改上述代码库@SerjSagan answer 以禁用启用约束

        【讨论】:

          【解决方案17】:

          唯一的方法是在截断之前删除外键。并且在截断数据后,您必须重新创建索引。

          以下脚本生成删除所有外键约束所需的 SQL。

          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
          

          接下来,以下脚本会生成重新创建外键所需的 SQL。

          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
          

          运行生成的脚本删除所有外键,截断表,然后运行生成的脚本重新创建所有外键。

          查询来自here。

          【讨论】:

            【解决方案18】:

            这是我对这个问题的解决方案。我用它来改变PK,但想法相同。希望这会有用)

            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'
            

            【讨论】:

              【解决方案19】:

              对于MS SQL,至少是较新的版本,您可以使用如下代码禁用约束:

              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
              

              【讨论】:

              • 我认为我们在上面确定了这不起作用?也许它适用于较新的版本?
              • Fwiw,这在 OP 版本 (2005) 中不起作用,在其后续版本 (MSSQL2008) 中也不起作用。
              【解决方案20】:

              即使有 FK 约束,以下内容也适用于我,并结合以下答案仅删除指定的表:


              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;
              

              注意:

              我认为按照您希望它们删除的顺序声明表仍然有帮助(即首先杀死依赖项)。如this answer 中所见,您可以用

              替换所有表,而不是循环特定名称
              EXEC sp_MSForEachTable 'DELETE FROM ?; DBCC CHECKIDENT (''?'',RESEED, 0);';
              

              【讨论】:

              • 并没有真正尝试过其他脚本,因为每个人都说当你有外键时它们不起作用。所以我试了这个,这个对我有用。
              • DELETE 不与TRUNCATE 相同。这将填满您的交易日志。
              • @Dan,可能是个好点;正如我提到的,我只是在这里结合了其他答案......
              • @drzaus 它适用于小型/中型表,但由于删除命令填满了事务日志,导致硬盘填满,我的生产 SQL 服务器脱机。至少,在大表上尝试此操作之前,请确保您的事务日志具有最大大小。
              【解决方案21】:

              如果这些答案都不像我的情况那样有效,请执行以下操作:

              1. 删除约束
              2. 设置所有值以允许空值
              3. 截断表
              4. 添加已删除的约束。

              祝你好运!

              【讨论】:

              • 任何关于它的 sql 示例?
              【解决方案22】:

              删除然后重置自动增量:

              delete from tablename;
              

              然后

              ALTER TABLE tablename AUTO_INCREMENT = 1;
              

              【讨论】:

              • 为什么AUTO_INCREMENT说('AUTO_INCREMENT'附近的语法不正确。?
              【解决方案23】:

              在 SSMS 中,我打开了显示密钥的图表。删除密钥并截断文件后,我刷新然后将注意力重新集中在图表上,并通过清除然后恢复身份框来创建更新。保存图表会弹出一个保存对话框,而不是“在您工作时在数据库中进行了更改”对话框,单击“是”恢复了密钥,从图表中的锁定副本恢复它。

              【讨论】:

                【解决方案24】:

                如果您以任何频率执行此操作,甚至是按计划执行,我会绝对、明确地永远不会使用 DML 语句。 写入事务日志的成本只是把整个数据库设置成SIMPLE恢复模式截断一张表是很可笑的。

                不幸的是,最好的方法是艰难或费力的方法。那就是:

                • 删除约束
                • 截断表
                • 重新创建约束

                我这样做的过程包括以下步骤:

                1. 在 SSMS 中右键单击有问题的表,然后选择 View Dependencies
                2. 记下引用的表格(如果有)
                3. 返回对象资源管理器,展开 Keys 节点并记下外键(如果有)
                4. 开始编写脚本(删除/截断/重新创建)

                这种性质的脚本应该在 begin tran 和 commit tran 块内完成。

                【讨论】:

                  【解决方案25】:

                  这是使用实体框架的人的示例

                  • 要重置的表:Foo

                  • 另一个依赖于的表:Bar

                  • 表上的约束列Foo : FooColumn

                  • 表上的约束列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);
                     }
                    

                  【讨论】:

                    【解决方案26】:

                    你可以试试DELETE FROM &lt;your table &gt;;。

                    服务器会显示限制的名称和表,删除该表你可以删除你需要的。

                    【讨论】:

                    • 阅读他关于这个问题的第二句话。他知道他能做到,但这不是他想要的
                    【解决方案27】:

                    我刚刚发现,只要您首先禁用 child 表上的约束,就可以在父表上使用 TRUNCATE 表,并在子表上使用外键约束。 例如

                    子表上的外键CONSTRAINT child_par_ref,引用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;
                    

                    【讨论】:

                    【解决方案28】:

                    最简单的方法:
                    1 - 进入 phpmyadmin
                    2 - 单击左列中的表名
                    3 - 点击操作(顶部菜单)
                    4 - 单击“清空表 (TRUNCATE)
                    5 - 禁用“启用外键检查”框
                    6 - 完成!

                    图片教程链接
                    Tutorial: http://www.imageno.com/wz6gv1wuqajrpic.html
                    (对不起,我没有足够的声望在这里上传图片:P)

                    【讨论】:

                    • OP 声明 MSSQL。您给出了 MySQL 独有的答案。
                    【解决方案29】:
                    SET FOREIGN_KEY_CHECKS=0;
                    TRUNCATE table1;
                    TRUNCATE table2;
                    SET FOREIGN_KEY_CHECKS=1;
                    

                    参考 - truncate foreign key constrained table

                    在 MYSQL 中为我工作

                    【讨论】:

                    • 除了指定的版本,这个还有什么问题吗?会推荐使用它,还是完全避免使用它?
                    • @AndyIbanez MySQL 是与 MSSQL 完全不同的产品,而不是不同版本的 MSSQL。
                    • 它的正确答案不知道为什么大家都给否定
                    猜你喜欢
                    • 1970-01-01
                    • 2014-10-05
                    • 2014-03-20
                    • 2019-10-05
                    • 2016-11-29
                    • 2018-08-08
                    • 1970-01-01
                    • 2023-03-22
                    • 2017-12-02
                    相关资源
                    最近更新 更多