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; |
享受,但要小心!
最简单的方法是
这将为您提供一个脚本,该脚本可以删除并重新创建所有表,而无需担心调试或是否包含了所有内容。虽然这不仅仅是一个截断,但结果是相同的。请记住,自动递增的主键将从0开始,而不是截断的表,它将记住最后分配的值。如果在预处理或生产环境中没有访问ManagementStudio的权限,也可以从代码中执行此操作。
1。
2。
三。
只有当表之间没有任何外键关系时,截断所有表才有效,因为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个更好/更有效的,但听起来这是非常罕见的,所以这里……
从
编写数据库脚本要容易得多(甚至更快),然后从脚本中删除并创建它。
现在有点晚了,但可能会有帮助。我使用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'
结果如何。
在查询窗口上复制和粘贴并运行命令