T-SQL :: 截断或删除架构中的所有表

T-SQL :: TRUNCATE or DELETE all tables in schema

我需要 TRUNCATEDELETE 架构中的所有表。

我找到了 this code:

-- disable all constraints
EXEC sp_MSForEachTable @command1='ALTER TABLE ? NOCHECK CONSTRAINT all',@whereand='and Schema_Id=Schema_id(''Person'')'

-- delete data in all tables
Exec Sp_msforeachtable @command1='Truncate Table ?',@whereand='and Schema_Id=Schema_id(''Person'')'

-- enable all constraints
exec sp_MSForEachTable @command1='ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all',@whereand='and Schema_Id=Schema_id(''Person'')'

-- if some of the tables have identity columns we may want to reseed them
EXEC sp_MSForEachTable @command1='DBCC CHECKIDENT ( ''?'', RESEED, 0)',@whereand='and Schema_Id=Schema_id(''Person'')'

但是在 AdventureWorks 上它给了我:

Cannot truncate table 'Person.Address' because it is being referenced by a FOREIGN KEY constraint.

所以我找到了this alternative code:

DECLARE @STRSQL NVARCHAR(MAX);
DECLARE @TABLE NVARCHAR(128);
DECLARE @SCHEMA_NAME VARCHAR(50)

SET @SCHEMA_NAME = 'Person'
SET @STRSQL = '';

DECLARE @C1 CURSOR SET @C1 = CURSOR
FOR
SELECT TOP 2 TABLE_SCHEMA + '.' + TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = @SCHEMA_NAME

OPEN @C1

FETCH NEXT
FROM @C1
INTO @TABLE

WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT @TABLE

    SET @STRSQL = @STRSQL + 'DELETE FROM ' + @TABLE + ';'

    FETCH NEXT
    FROM @C1
    INTO @TABLE
END

CLOSE @C1

DEALLOCATE @C1

PRINT @STRSQL

EXEC sp_executesql @STRSQL

但是结果是一样的:

Person.Address
Person.AddressType
DELETE FROM Person.Address;DELETE FROM Person.AddressType;
Msg 547, Level 16, State 0, Line 1
The DELETE statement conflicted with the REFERENCE constraint "FK_BusinessEntityAddress_Address_AddressID". The conflict occurred in database "AdventureWorks2014", table "Person.BusinessEntityAddress", column 'AddressID'.
The statement has been terminated.
Msg 547, Level 16, State 0, Line 1
The DELETE statement conflicted with the REFERENCE constraint "FK_BusinessEntityAddress_AddressType_AddressTypeID". The conflict occurred in database "AdventureWorks2014", table "Person.BusinessEntityAddress", column 'AddressTypeID'.
The statement has been terminated.

如何 TRUNCATEDELETE 架构中的所有表?

您只需要在开头用“删除所有外键”脚本包装“从所有 tables 中删除”脚本,最后用“重新创建所有外键”脚本包装.我在这里展示了一种方法:

但是,我认为,与花费所有时间和精力一次从一个 table 中删除数据相比,只编写数据库和源代码管理中的空对象的脚本要干净得多。

无论如何尝试你正在做的事情(如果你截断你也不需要检查身份,我不确定我是否会使用像 sp_msforeachtable 这样的未记录和不受支持的程序,而且我也stay the heck away from INFORMATION_SCHEMA)。请在测试数据库上试试这个。

CREATE TABLE #x -- feel free to use a permanent table
(
  drop_script   nvarchar(max),
  create_script nvarchar(max)
);
  
DECLARE @drop   nvarchar(max) = N'',
        @create nvarchar(max) = N'';

-- drop is easy, just build a simple concatenated list from sys.foreign_keys:
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];

INSERT #x(drop_script) SELECT @drop;

-- create is a little more complex. We need to generate the list of 
-- columns on both sides of the constraint, even though in most cases
-- there is only one column.
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'./text()[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'./text()[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;

UPDATE #x SET create_script = @create;

PRINT @drop;
PRINT @create;

EXEC sys.sp_executesql @drop
-- clear out data etc. here

DECLARE @truncate nvarchar(max) = N'';
SELECT @truncate += N'TRUNCATE TABLE ' + QUOTENAME(s.name)
  + N'.' + QUOTENAME(t.name) + N';'
FROM sys.schemas AS s 
  INNER JOIN sys.tables AS t
  ON s.[schema_id] = t.[schema_id];

EXEC sys.sp_executesql @truncate;
EXEC sys.sp_executesql @create;

备注:

  • 这是未经测试的。尽我所能:在测试数据库上试试这个
  • 这意味着只执行一次,所以我没有删除 #temp table(如果事情不顺利,让它保持足够长的时间以进行故障排除可能很有用)
  • PRINT 不一定会向您显示将要执行的完整命令,因此它不是确定脚本是否正确的有效方法。它只是一个快速的眼球。如果你真的想查看整个命令,你需要 something a little more elaborate.
  • 这不处理索引视图,我敢肯定还有其他限制可能会阻止您截断某些 tables(我在考虑时间或始终使用 enclaves 或 in-mem 加密),但我会单独解决这些问题并保持截断,而不是通过使用更多日志密集型删除来“修复”它。

谢谢@AaronBertrand,我分叉了你很棒的查询以创建一个更适合我需要做的查询:

SELECT cs.name AS SchemaName
    ,ct.name AS TableName
    ,rt.name AS ColumnName
    ,fk.name AS ForeignKeyName
    ,fk.object_id AS ObjectID
    ,fk.parent_object_id AS ParentObjectID
    ,
    -- drop constraint 
    N'
ALTER TABLE ' + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name) + ' DROP CONSTRAINT ' + QUOTENAME(fk.name) + ';' AS Drop_Constraint_Script
    ,
    -- create constraint 
    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'') + ');' AS Create_Constraint_Script
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
ORDER BY 1
    ,2
    ,3