我有一个数据库的测试环境,我想在测试周期开始时用新数据重新加载该数据库。我对重建整个数据库不感兴趣——只是简单地“重新设置”数据。
使用TSQL从所有表中删除所有数据的最佳方法是什么?是否有可以使用的系统存储过程、视图等?我不想为每个表手动创建和维护截断表语句-我更希望它是动态的。
我有一个数据库的测试环境,我想在测试周期开始时用新数据重新加载该数据库。我对重建整个数据库不感兴趣——只是简单地“重新设置”数据。
使用TSQL从所有表中删除所有数据的最佳方法是什么?是否有可以使用的系统存储过程、视图等?我不想为每个表手动创建和维护截断表语句-我更希望它是动态的。
当前回答
这是数据库擦除脚本之王。它将清除所有表并正确地重新播种:
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;
享受吧,但要小心!
其他回答
运行一次注释掉的部分,用希望截断的表填充_TruncateList表,然后运行脚本的其余部分。如果您经常这样做,_ScriptLog表将需要随着时间的推移被清理。
如果你想做所有的表,你可以修改这个,只要把SELECT name放入#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
不要这样做!真的,这不是个好主意。
如果知道要截断哪些表,可以创建一个存储过程来截断它们。您可以修复顺序以避免外键问题。
如果您真的想要截断它们(例如,您可以BCP加载它们),那么您可以很快地删除数据库并从头创建一个新的数据库,这将带来额外的好处,即您可以确切地知道您所处的位置。
当处理从具有外键关系的表中删除数据时(这基本上是任何设计良好的数据库的情况),我们可以禁用所有约束,删除所有数据,然后重新启用约束
-- 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"
这里有更多关于禁用约束和触发器的信息
如果某些表有标识列,我们可能需要重新播种它们
EXEC sp_MSForEachTable "DBCC CHECKIDENT ( '?', RESEED, 0)"
请注意,RESEED的行为在全新的表和之前从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指出禁用约束不允许使用截断的事实,约束必须被删除,然后重新创建
这是数据库擦除脚本之王。它将清除所有表并正确地重新播种:
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;
享受吧,但要小心!
我不明白为什么清除数据会比删除并重新创建每个表的脚本更好。
或者备份你的空数据库,并在旧的数据库上恢复它