2012-04-17 171 views
0

某人必須已經編寫了腳本才能從數據庫的所有表中刪除所有行。 使用DELETE命令不是一個選項,因爲它可能會在大型表上花費時間。 當然,在stackoverflow和其他地方有很多例子,但是它們不適用於使用外鍵的表。從數據庫的所有表中刪除所有行

基本上,腳本應該這樣做:

  • 存儲所有外鍵定義在臨時表
  • 刪除所有外鍵
  • 截斷所有表
  • 恢復外鍵

我想我有:

IF OBJECT_ID('tempdb..#ForeignKeys') IS NOT NULL 
    DROP TABLE #ForeignKeys; 

WITH ForeignKeys AS (
SELECT 
    QUOTENAME(SCHEMA_NAME(t.schema_id)) + '.' + QUOTENAME(t.name) AS ParentTable 
    , QUOTENAME(SCHEMA_NAME(rt.schema_id)) + '.' + QUOTENAME(rt.name) AS ReferenceTable 
    , QUOTENAME(f.name) AS ConstraintName 
    , STUFF(Parent.Cols, 1, 1, '') AS ParentColumns 
    , STUFF(Reference.Cols, 1, 1, '') AS ReferenceColumns 
    , REPLACE(f.update_referential_action_desc, '_', ' ') AS UpdateAction 
    , REPLACE(f.delete_referential_action_desc, '_', ' ') AS DeleteAction 
FROM 
    sys.tables AS t 
    LEFT JOIN sys.foreign_keys AS f 
     ON f.parent_object_id = t.object_id 
     AND f.type = 'F' 
    LEFT JOIN sys.tables AS rt 
     ON f.referenced_object_id = rt.object_id 
    CROSS APPLY 
    (
     SELECT 
      ',' + QUOTENAME(COL_NAME(fc.parent_object_id, fc.parent_column_id))AS [text()] 
     FROM 
      sys.foreign_key_columns AS fc 
     WHERE 
      fc.constraint_object_id = f.object_id 
     ORDER BY 
      fc.constraint_column_id 
     FOR XML PATH('') 
    ) Parent(Cols) 
    CROSS APPLY 
    (
     SELECT 
      ',' + QUOTENAME(COL_NAME(fc.referenced_object_id, fc.referenced_column_id)) AS [text()] 
     FROM 
      sys.foreign_key_columns AS fc 
     WHERE 
      fc.constraint_object_id = f.object_id 
     ORDER BY 
      fc.constraint_column_id 
     FOR XML PATH('') 
    ) Reference(Cols) 
) 
SELECT 
    ParentTable AS TableName 
    , 'ALTER TABLE ' + ParentTable + ' DROP CONSTRAINT ' + ConstraintName AS DropCmd 
    , 'TRUNCATE TABLE ' + ParentTable AS TruncateCmd 
    , 'ALTER TABLE ' + ParentTable + ' ADD CONSTRAINT ' + ConstraintName + ' FOREIGN KEY(' 
     + ParentColumns + ') REFERENCES ' + ReferenceTable + ' (' + ReferenceColumns 
     + ') ON UPDATE ' + UpdateAction 
     + ' ON DELETE ' + DeleteAction COLLATE SQL_Latin1_General_CP1_CI_AS AS CreateCmd 
INTO 
    #ForeignKeys 
FROM 
    ForeignKeys 
ORDER BY 
1; 

-- SELECT * FROM #ForeignKeys 

DECLARE @TableName SYSNAME 
DECLARE @Sql NVARCHAR(MAX) 

-- Drop all constraints 
DECLARE FkCursor CURSOR FOR 
SELECT 
    TableName 
    , DropCmd 
FROM 
    #ForeignKeys 
WHERE 
    DropCmd IS NOT NULL  

OPEN FkCursor 
FETCH NEXT FROM FkCursor INTO @TableName, @Sql 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    PRINT @TableName + ' : ' + @sql 
    EXEC sp_executesql @Sql 
    FETCH NEXT FROM FkCursor INTO @TableName, @Sql 
END 
CLOSE FkCursor 
DEALLOCATE FkCursor 

-- Truncate all tables 
DECLARE FkCursor CURSOR FOR 
SELECT 
    TableName 
    , TruncateCmd 
FROM 
    #ForeignKeys  

OPEN FkCursor 

FETCH NEXT FROM FkCursor INTO @TableName, @Sql 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    PRINT @TableName + ' : ' + @sql 
    EXEC sp_executesql @Sql 
    FETCH NEXT FROM FkCursor INTO @TableName, @Sql 
END 
CLOSE FkCursor 
DEALLOCATE FkCursor 

-- Create all foreign keys 
DECLARE FkCursor CURSOR FOR 
SELECT 
    TableName 
    , CreateCmd 
FROM 
    #ForeignKeys 
WHERE 
    CreateCmd IS NOT NULL  

OPEN FkCursor 
FETCH NEXT FROM FkCursor INTO @TableName, @Sql 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    PRINT @TableName + ' : ' + @sql 
    EXEC sp_executesql @Sql 
    FETCH NEXT FROM FkCursor INTO @TableName, @Sql 
END 
CLOSE FkCursor 
DEALLOCATE FkCursor 

DROP TABLE #ForeignKeys; 
+1

到目前爲止你寫了些什麼? – rvphx 2012-04-17 15:32:43

+4

如果您有所有表的創建腳本,爲什麼不刪除所有表(或數據庫),然後重新運行創建腳本? – 2012-04-17 15:33:17

+0

刪除對FK引用的表格不起作用。對於你沒有被FK引用的表,然後轉向。定義年齡。我有超過100 GB的數據庫,我有一個腳本清除所有行使用截斷和刪除像20分鐘。 – Paparazzi 2012-04-17 15:55:29

回答

4
DECLARE @drop NVARCHAR(MAX), @truncate NVARCHAR(MAX), @create NVARCHAR(MAX); 

SELECT @drop = N'', @truncate = N'', @create = N''; 

;WITH x AS 
(
    SELECT id = f.[object_id], 
     cname = QUOTENAME(f.name), 
     ctable = QUOTENAME(OBJECT_SCHEMA_NAME(f.parent_object_id)) 
     + '.' + QUOTENAME(OBJECT_NAME(f.parent_object_id)), 
     ccol = QUOTENAME(COL_NAME(fc.parent_object_id,fc.parent_column_id)), 
     rtable = QUOTENAME(OBJECT_SCHEMA_NAME(f.referenced_object_id)) 
     + '.' + QUOTENAME(OBJECT_NAME(f.referenced_object_id)), 
     rcol = QUOTENAME(COL_NAME(fc.referenced_object_id,fc.referenced_column_id)), 
     ou = f.update_referential_action_desc COLLATE SQL_Latin1_General_CP1_CI_AS, 
     od = f.delete_referential_action_desc COLLATE SQL_Latin1_General_CP1_CI_AS 
    FROM sys.foreign_keys AS f 
    INNER JOIN sys.foreign_key_columns AS fc 
    ON f.[object_id] = fc.constraint_object_id 
    -- where clause to leave out certain tables here 
), 
y AS 
(
    SELECT 
    d = CHAR(13) + CHAR(10) + 'ALTER TABLE ' + ctable + ' DROP CONSTRAINT ' + cname + ';', 
    c = CHAR(13) + CHAR(10) + 'ALTER TABLE ' + ctable + ' ADD CONSTRAINT ' + cname 
     + ' FOREIGN KEY (' + STUFF((SELECT ',' + ccol FROM x AS x2 
     WHERE x2.id = x.id FOR XML PATH('')), 1, 1, '') 
     + ') REFERENCES ' + rtable + '(' + STUFF((SELECT ',' + rcol FROM x AS x3 
     WHERE x3.id = x.id FOR XML PATH('')), 1, 1, '') + ')' 
    + CASE WHEN od <> 'NO_ACTION' THEN 
     ' ON DELETE ' + REPLACE(od, 'SET_', 'SET ') ELSE '' END 
    + CASE WHEN ou <> 'NO_ACTION' THEN 
     ' ON UPDATE ' + REPLACE(ou, 'SET_', 'SET ') ELSE '' END 
    FROM x 
) 
SELECT 
    @drop = @drop + d, 
    @create = @create + c 
FROM y GROUP BY d,c; 

SELECT @truncate = @truncate + CHAR(13) + CHAR(10) + 'TRUNCATE TABLE ' 
    + QUOTENAME(SCHEMA_NAME(schema_id)) + '.' + QUOTENAME(name) + ';' 
    FROM sys.tables 
    -- where clause to leave out certain tables here 
; 

-- use results to text. Note that for 200 tables you won't be able to 
-- manually inspect the entire script in Management Studio because it 
-- will only show a certain number of characters depending on settings. 

SELECT @drop; 
SELECT @truncate; 
SELECT @create; 

-- when you are happy, uncomment these: 

--EXEC sp_executesql @drop; 
--EXEC sp_executesql @truncate; 
--EXEC sp_executesql @create; 
+0

我想我已經找到了類似的解決方案,但是如果你有外鍵的開啓(更新|刪除設置(默認| NULL)'或者帶空格的列,你將會遇到問題 – psadac 2012-04-17 17:45:41

+0

當然,如果你用空格命名列。 :添加QUOTENAME(上面已經修正)現在如果你命名你的FK約束表TABLE?有各種各樣的邊緣情況,你可以花上幾個小時來應對,但是你想要一個100%的防彈解決方案還是隻是一個普遍的想法,你可以完美的,如果有幾個非典型的東西遺漏,你已經清楚地知道? – 2012-04-17 17:49:56

+0

列名空間不是人的選擇,你可以想象。但是你是對的,這將是很難有一些「獨白」,我用QUOTENAME擊倒。 – psadac 2012-04-17 19:01:14

0

右鍵單擊對象(在對象資源管理器中),然後單擊腳本作爲 - >拖放到。使用與 - > Create to相同的方法和腳本。這應該爲您提供Dropping的腳本以及創建數據庫中的所有對象。按照你喜歡的順序運行它們。

或者如果你有很多的表和對象,你可以右鍵點擊數據庫 - >去任務,然後點擊生成腳本。 enter image description here

+0

哇,如果有500張桌子,這根本就不是很有成效,而外鍵意味着你將不得不做很多工作來確定正確的順序。 – 2012-04-17 15:38:54

+0

葉普。但是我們知道他是否有500張桌子? – rvphx 2012-04-17 15:39:27

+0

即使有10個,這是很多手動指向和點擊,並且很容易跳過表格。 – 2012-04-17 15:40:01