首页 文章

如何使用TSQL截断数据库中的所有表?

提问于
浏览
190

我有一个数据库的测试环境,我想在测试周期开始时用新数据重新加载 . 我对重建整个数据库不感兴趣 - 只需简单地“重新设置”数据 .

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

17 回答

  • 7

    对于SQL 2005,

    EXEC sp_MSForEachTable 'TRUNCATE TABLE ?'
    

    20002005/2008结合更多链接..

  • 6

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

    -- 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"
    

    有关禁用约束和触发器的更多信息here

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

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

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

    DBCC CHECKIDENT('table_name',RESEED,newReseedValue)当前标识值设置为newReseedValue . 如果自创建表以来没有向表插入任何行,则在执行DBCC CHECKIDENT后插入的第一行将使用newReseedValue作为标识 . 否则,插入的下一行将使用newReseedValue 1.如果newReseedValue的值小于标识列中的最大值,则将在对该表的后续引用上生成错误消息2627 .

    感谢Robert指出禁用约束不允许使用truncate的事实,必须删除约束,然后重新创建

  • 0

    这是数据库擦除脚本的国王 . 它将清除所有表并正确重新设置它们:

    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;
    

    享受,但要小心!

  • 2

    最简单的方法是

    • 打开SQL Management Studio

    • 导航到您的数据库

    • 右键单击并选择任务 - >生成脚本(图1)

    • 在"choose Objects"屏幕上,选择"select specific objects"选项并检查"tables"(图2)

    • 在下一个屏幕上,选择"advanced",然后将"Script DROP and CREATE"选项更改为"Script DROP and CREATE"(图3)

    • 选择将脚本保存到新的编辑器窗口或文件,并根据需要运行 .

    这将为您提供一个脚本,可以删除并重新创建所有表,而无需担心调试或是否包含所有内容 . 虽然这不仅仅是截断,但结果是相同的 . 请记住,自动递增主键将从0开始,而截断表将记住最后分配的值 . 如果您无法访问PreProd或Production环境中的Management studio,也可以从代码执行此操作 .

    1 .

    enter image description here

    2 .

    enter image description here

    3 .

    enter image description here

  • 42

    截断所有表只有在表之间没有任何外键关系时才会起作用,因为SQL Server不允许您使用外键截断表 .

    另一种方法是使用外键确定表并从中删除,然后可以在没有外键的情况下截断表 .

    有关详细信息,请参阅http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=65341http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=72957 .

  • 394

    我喜欢与MSSQL Server Deveploper或Enterprise一起使用的另一种选择是在创建空模式后立即创建数据库的快照 . 此时,您可以继续将数据库还原到快照 .

  • 0

    不要这样做!真的,不是一个好主意 .

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

    如果你真的想要截断它们(例如你可以BCP加载它们),那么你可以快速删除数据库并从头开始创建一个新的数据库,这将带来额外的好处,你可以确切地知道它在哪里 .

  • 3

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

    sp_MSForEachTable对我来说似乎有些错误(即与IF语句的行为不一致),这可能就是为什么它没有记录由MS .

    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
    
  • 3

    创建一个空的“模板”数据库,进行完整备份 . 需要刷新时,只需使用WITH REPLACE进行恢复 . 快速,简单,防弹 . 如果这里或那里的几个表需要一些基本数据(例如配置信息,或只是让你的应用程序运行的基本信息),它也会处理它 .

  • -1

    截断所有表最难的部分是删除和重新定义外键约束 .

    以下查询为@myTempTable中与每个表名相关的每个约束创建drop和create语句 . 如果您想为所有表生成这些表,您可以简单地使用信息模式来收集这些表名 .

    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)
    

    然后我只是复制出要运行的语句 - 但是通过一些开发工作,你可以使用游标动态运行它们 .

  • 4

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

  • 12

    这是一种方法...有可能有10个更好/更有效,但听起来这种情况很少发生,所以这里......

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

  • 0

    我不明白为什么清除数据会比删除和重新创建每个表的脚本更好 .

    那或者保留空数据库的备份并将其恢复到旧数据库

  • 2

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

  • 173

    运行注释掉的部分一次,使用要截断的表填充_TruncateList表,然后运行脚本的其余部分 . 如果你这么做的话,需要随时清理_ScriptLog表 .

    如果要执行所有表,只需将SELECT名称INTO #TruncateList FROM sys.tables放入,就可以修改它 . 但是,您通常不希望全部执行这些操作 .

    此外,这将影响数据库中的所有外键,如果它对您的应用程序来说太过钝,您也可以修改它 . 这不适合我的目的 .

    /*
    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
    
  • 50

    这有点晚了,但它可能对某人有所帮助 . 我有时会创建一个过程,使用T-SQL执行以下操作:

    • 将所有约束存储在临时表中

    • 删除所有约束

    • 截断除了某些表之外的所有表,这些表不需要截断

    • 重新创建所有约束 .

    我在我的博客上列出了它here

  • 0

    从INFORMATION_SCHEMA.TABLES中选择'从'TABLE_NAME删除TABLE_TYPE ='BASE TABLE'

    结果来了 .

    复制并粘贴查询窗口并运行该命令

相关问题