关于sql server:如何使用SQL截断数据库中的所有表?

How do you truncate all tables in a database using TSQL?

我有一个数据库的测试环境,我想在测试周期开始时用新数据重新加载它。我对重建整个数据库不感兴趣——只是简单地"重新设置"数据。

使用TSQL从所有表中删除所有数据的最佳方法是什么?是否有可以使用的系统存储过程、视图等?我不想手动为每个表创建和维护truncate table语句-我希望它是动态的。


当处理从具有外键关系的表中删除数据时——这基本上是任何正确设计的数据库的情况——我们可以禁用所有约束,删除所有数据,然后重新启用约束。

1
2
3
4
5
6
7
8
-- disable all constraints
EXEC sp_MSForEachTable"ALTER TABLE ? NOCHECK CONSTRAINT all"

-- delete data in all tables
EXEC sp_MSForEachTable"DELETE FROM ?"

-- enable all constraints
exec sp_MSForEachTable"ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"

有关在此处禁用约束和触发器的详细信息

如果某些表有标识列,我们可能需要重新设置它们

1
EXEC sp_MSForEachTable"DBCC CHECKIDENT ( '?', RESEED, 0)"

请注意,重设的行为在全新的表和之前从BOL插入了一些数据的表之间有所不同:

DBCC CHECKIDENT ('table_name', RESEED, newReseedValue)

The current identity value is set to
the newReseedValue. If no rows have
been inserted to the table since it
was created, the first row inserted
after executing DBCC CHECKIDENT will
use newReseedValue as the identity.
Otherwise, the next row inserted will
use newReseedValue + 1. If the value
of newReseedValue is less than the
maximum value in the identity column,
error message 2627 will be generated
on subsequent references to the table.

由于Robert指出禁用约束不允许使用truncate,因此必须删除约束,然后重新创建。


对于SQL 2005,

1
EXEC sp_MSForEachTable 'TRUNCATE TABLE ?'

为2000年和2005/2008年提供更多链接。


这是数据库擦除脚本之父。它将清除所有表并正确地重新设置它们:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
SET QUOTED_IDENTIFIER ON;
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? NOCHECK CONSTRAINT ALL'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? DISABLE TRIGGER ALL'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; DELETE FROM ?'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? CHECK CONSTRAINT ALL'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? ENABLE TRIGGER ALL'
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON';

IF NOT EXISTS (
    SELECT
        *
    FROM
        SYS.IDENTITY_COLUMNS
        JOIN SYS.TABLES ON SYS.IDENTITY_COLUMNS.Object_ID = SYS.TABLES.Object_ID
    WHERE
        SYS.TABLES.Object_ID = OBJECT_ID('?') AND SYS.IDENTITY_COLUMNS.Last_Value IS NULL
)
AND OBJECTPROPERTY( OBJECT_ID('?'), 'TableHasIdentity' ) = 1

    DBCC CHECKIDENT ('?', RESEED, 0) WITH NO_INFOMSGS;

享受,但要小心!


最简单的方法是

  • 打开SQL Management Studio
  • 导航到数据库
  • 右键单击并选择"任务"->"生成脚本"(图1)
  • 在"选择对象"屏幕上,选择"选择特定对象"选项并选中"表"(图2)。
  • 在下一个屏幕上,选择"高级",然后将"脚本删除并创建"选项更改为"脚本删除并创建"(图3)
  • 选择将脚本保存到新的编辑器窗口或文件,并根据需要运行。
  • 这将为您提供一个脚本,该脚本可以删除并重新创建所有表,而无需担心调试或是否包含了所有内容。虽然这不仅仅是一个截断,但结果是相同的。请记住,自动递增的主键将从0开始,而不是截断的表,它将记住最后分配的值。如果在预处理或生产环境中没有访问ManagementStudio的权限,也可以从代码中执行此操作。

    1。

    enter image description here

    2。

    enter image description here

    三。

    enter image description here


    只有当表之间没有任何外键关系时,截断所有表才有效,因为SQL Server不允许您截断具有外键的表。

    另一种方法是确定带有外键的表,并首先从这些表中删除,然后可以截断不带外键的表。

    请参阅http://www.sqlteam.com/forums/topic.asp?topic_id=65341和http://www.sqlteam.com/forums/topic.asp?更多详情,请参见主题"ID=72957"。


    我喜欢与mssql server deveploper或enterprise一起使用的另一个选项是在创建空模式后立即创建数据库的快照。此时,您可以继续将数据库还原回快照。


    不要这样!真的,不是个好主意。

    如果知道要截断哪些表,请创建一个截断它们的存储过程。您可以修改订单以避免外键问题。

    如果您真的想全部截断它们(例如,您可以bcp加载它们),那么您将很快删除数据库并从头创建一个新的数据库,这将有额外的好处,您可以确切地知道自己在哪里。


    如果要在删除/截断同一数据库中其他表中的数据时将数据保留在特定表(即静态查阅表)中,则需要一个循环,其中包含异常。当我偶然发现这个问题时,这就是我在寻找的。

    在我看来,sp msforeachtable似乎有问题(即,与if语句的行为不一致),这可能是MS未记录的原因。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    declare @LastObjectID int = 0
    declare @TableName nvarchar(100) = ''
    set @LastObjectID = (select top 1 [object_id] from sys.tables where [object_id] > @LastObjectID order by [object_id])
    while(@LastObjectID is not null)
    begin
        set @TableName = (select top 1 [name] from sys.tables where [object_id] = @LastObjectID)

        if(@TableName not in ('Profiles', 'ClientDetails', 'Addresses', 'AgentDetails', 'ChainCodes', 'VendorDetails'))
        begin
            exec('truncate table [' + @TableName + ']')
        end

        set @LastObjectID = (select top 1 [object_id] from sys.tables where [object_id] > @LastObjectID order by [object_id])
    end

    创建一个空的"模板"数据库,进行完整备份。当需要刷新时,只需使用WITHREPLACE恢复即可。快速,简单,防弹。如果这里或那里的几个表需要一些基础数据(例如配置信息,或者只是让应用运行的基本信息),它也会处理这些。


    截断所有表最困难的部分是删除和重新加载外键约束。

    下面的查询为@my诱人的每个表名相关的每个约束创建drop&create语句。如果要为所有表生成这些表,可以简单地使用信息模式来收集这些表名。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    DECLARE @myTempTable TABLE (tableName varchar(200))
    INSERT INTO @myTempTable(tableName) VALUES
    ('TABLE_ONE'),
    ('TABLE_TWO'),
    ('TABLE_THREE')


    -- DROP FK Contraints
    SELECT 'alter table '+quotename(schema_name(ob.schema_id))+
      '.'+quotename(object_name(ob.object_id))+ ' drop constraint ' + quotename(fk.name)
      FROM sys.objects ob INNER JOIN sys.foreign_keys fk ON fk.parent_object_id = ob.object_id
      WHERE fk.referenced_object_id IN
          (
             SELECT so.object_id
             FROM sys.objects so JOIN sys.schemas sc
             ON so.schema_id = sc.schema_id
             WHERE so.name IN (SELECT * FROM @myTempTable)  AND sc.name=N'dbo'  AND type in (N'U'))


     -- CREATE FK Contraints
     SELECT 'ALTER TABLE [PIMSUser].[dbo].[' +cast(c.name as varchar(255)) + '] WITH NOCHECK ADD CONSTRAINT ['+ cast(f.name as varchar(255)) +'] FOREIGN KEY (['+ cast(fc.name as varchar(255)) +'])
          REFERENCES [PIMSUser].[dbo].['+ cast(p.name as varchar(255)) +'] (['+cast(rc.name as varchar(255))+'])'
    FROM  sysobjects f
          INNER JOIN sys.sysobjects c ON f.parent_obj = c.id
          INNER JOIN sys.sysreferences r ON f.id = r.constid
          INNER JOIN sys.sysobjects p ON r.rkeyid = p.id
          INNER JOIN sys.syscolumns rc ON r.rkeyid = rc.id and r.rkey1 = rc.colid
          INNER JOIN sys.syscolumns fc ON r.fkeyid = fc.id and r.fkey1 = fc.colid
    WHERE
          f.type = '
    F'
          AND
          cast(p.name as varchar(255)) IN (SELECT * FROM @myTempTable)

    然后,我只需复制出要运行的语句——但是通过一些开发人员的努力,您可以使用光标动态地运行它们。


    这是一种方法…可能还有10个更好/更有效的,但听起来这是非常罕见的,所以这里……

    sysobjects获取tables的列表,然后用光标循环这些列表,为每个iteration调用sp_execsql('truncate table ' + @table_name)


    编写数据库脚本要容易得多(甚至更快),然后从脚本中删除并创建它。


    现在有点晚了,但可能会有帮助。我使用T-SQL创建了一个有时返回的过程,它执行以下操作:

  • 将所有约束存储在临时表中
  • 删除所有约束
  • 截断除某些不需要截断的表以外的所有表
  • 重新创建所有约束。
  • 我把它列在我的博客上了


    我不明白为什么清除数据比删除并重新创建每个表的脚本要好。

    或者备份一个空数据库,然后在旧数据库上恢复它


    在截断表之前,必须删除所有外键。使用此脚本生成最终脚本以删除和重新创建数据库中的所有外键。请将@action变量设置为'create'或'drop'。


    运行注释掉的部分一次,用您想要截断的表填充_truncatelist表,然后运行脚本的其余部分。如果您经常这样做,随着时间的推移,需要清理脚本日志表。

    如果要执行所有表,可以修改此项,只需将select name放入sys.tables中的truncatelist。但是,你通常不想全部做。

    另外,这也会影响数据库中的所有外键,如果对应用程序来说,这一点过于生硬,您也可以修改它。这不是为了我的目的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    /*
    CREATE TABLE _ScriptLog
    (
        ID Int NOT NULL Identity(1,1)
        , DateAdded DateTime2 NOT NULL DEFAULT GetDate()
        , Script NVarChar(4000) NOT NULL
    )

    CREATE UNIQUE CLUSTERED INDEX IX_ScriptLog_DateAdded_ID_U_C ON _ScriptLog
    (
        DateAdded
        , ID
    )

    CREATE TABLE _TruncateList
    (
        TableName SysName PRIMARY KEY
    )
    */

    IF OBJECT_ID('TempDB..#DropFK') IS NOT NULL BEGIN
        DROP TABLE #DropFK
    END

    IF OBJECT_ID('TempDB..#TruncateList') IS NOT NULL BEGIN
        DROP TABLE #TruncateList
    END

    IF OBJECT_ID('TempDB..#CreateFK') IS NOT NULL BEGIN
        DROP TABLE #CreateFK
    END

    SELECT Scripts = 'ALTER TABLE ' + '[' + OBJECT_NAME(f.parent_object_id)+ ']'+
    '
    DROP  CONSTRAINT ' + '[' + f.name  + ']'
    INTO #DropFK
    FROM .sys.foreign_keys AS f
    INNER JOIN .sys.foreign_key_columns AS fc
    ON f.OBJECT_ID = fc.constraint_object_id

    SELECT TableName
    INTO #TruncateList
    FROM _TruncateList

    SELECT Scripts = '
    ALTER TABLE ' + const.parent_obj + '
        ADD CONSTRAINT ' + const.const_name + ' FOREIGN KEY (
                ' + const.parent_col_csv + '
                ) REFERENCES ' + const.ref_obj + '(' + const.ref_col_csv + ')
    '
    INTO #CreateFK
    FROM (
        SELECT QUOTENAME(fk.NAME) AS [const_name]
            ,QUOTENAME(schParent.NAME) + '
    .' + QUOTENAME(OBJECT_name(fkc.parent_object_id)) AS [parent_obj]
            ,STUFF((
                    SELECT '
    ,' + QUOTENAME(COL_NAME(fcP.parent_object_id, fcp.parent_column_id))
                    FROM sys.foreign_key_columns AS fcP
                    WHERE fcp.constraint_object_id = fk.object_id
                    FOR XML path('
    ')
                    ), 1, 1, '
    ') AS [parent_col_csv]
            ,QUOTENAME(schRef.NAME) + '
    .' + QUOTENAME(OBJECT_NAME(fkc.referenced_object_id)) AS [ref_obj]
            ,STUFF((
                    SELECT '
    ,' + QUOTENAME(COL_NAME(fcR.referenced_object_id, fcR.referenced_column_id))
                    FROM sys.foreign_key_columns AS fcR
                    WHERE fcR.constraint_object_id = fk.object_id
                    FOR XML path('
    ')
                    ), 1, 1, '
    ') AS [ref_col_csv]
        FROM sys.foreign_key_columns AS fkc
        INNER JOIN sys.foreign_keys AS fk ON fk.object_id = fkc.constraint_object_id
        INNER JOIN sys.objects AS oParent ON oParent.object_id = fkc.parent_object_id
        INNER JOIN sys.schemas AS schParent ON schParent.schema_id = oParent.schema_id
        INNER JOIN sys.objects AS oRef ON oRef.object_id = fkc.referenced_object_id
        INNER JOIN sys.schemas AS schRef ON schRef.schema_id = oRef.schema_id
        GROUP BY fkc.parent_object_id
            ,fkc.referenced_object_id
            ,fk.NAME
            ,fk.object_id
            ,schParent.NAME
            ,schRef.NAME
        ) AS const
    ORDER BY const.const_name

    INSERT INTO _ScriptLog (Script)
    SELECT Scripts
    FROM #CreateFK

    DECLARE @Cmd NVarChar(4000)
        , @TableName SysName

    WHILE 0 < (SELECT Count(1) FROM #DropFK) BEGIN
        SELECT TOP 1 @Cmd = Scripts
        FROM #DropFK

        EXEC (@Cmd)

        DELETE #DropFK WHERE Scripts = @Cmd
    END

    WHILE 0 < (SELECT Count(1) FROM #TruncateList) BEGIN
        SELECT TOP 1 @Cmd = N'
    TRUNCATE TABLE ' +  TableName
            , @TableName = TableName
        FROM #TruncateList

        EXEC (@Cmd)

        DELETE #TruncateList WHERE TableName = @TableName
    END

    WHILE 0 < (SELECT Count(1) FROM #CreateFK) BEGIN
        SELECT TOP 1 @Cmd = Scripts
        FROM #CreateFK

        EXEC (@Cmd)

        DELETE #CreateFK WHERE Scripts = @Cmd
    END


    选择'delete from'+tableu name from informationu schema.tables where tableu type='base table'

    结果如何。

    在查询窗口上复制和粘贴并运行命令