TSQLを使用して、データベース内のすべてのテーブルをどのように切り捨てますか?


204

テストサイクルの開始時に新しいデータを再読み込みするデータベースのテスト環境があります。データベース全体の再構築には興味がありません。単にデータを「再設定」するだけです。

TSQLを使用してすべてのテーブルからすべてのデータを削除する最良の方法は何ですか?使用できるシステムストアドプロシージャ、ビューなどはありますか?各テーブルの切り捨てテーブルステートメントを手動で作成および維持したくないので、動的にしたいと思います。

回答:


188

SQL 2005の場合、

EXEC sp_MSForEachTable 'TRUNCATE TABLE ?'

2000年2005/2008 年のリンクを追加する。


62
外部キーを持つテーブルを切り捨てることはできないため、これは、テーブル間に外部キー制約がない(または無効になっている)場合にのみ機能します。
marcj 2008年

1
同意した..私は彼がテーブルのトランケートを特に要求したので、彼はすでに外部キーの問題を解決したと思った..
Gulzar Nazim

@ gulzar- sort--私はFKの処理方法について別の質問を投稿しましたが、あなたの答えはそれ自体のメリットに基づいています。
レイ

11
@サム:いいえ、それはしません!表のデータは無関係です。テーブルを参照する外部キー制約(無効なものも含む)がある限り、それを切り捨てることはできません。
TToni

3
「EXEC sp_MSForEachTable 'DROP TABLE?' うまく機能する:)(データベースのすべてのテーブルを喜ばせる)
kuncevic.dev '10

419

外部キー関係を持つテーブルからのデータの削除を処理するとき-これは基本的に適切に設計されたデータベースの場合です-すべての制約を無効にし、すべてのデータを削除してから制約を再度有効にすることができます

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

制約とトリガーの無効化の詳細はこちら

テーブルの一部にID列がある場合、それらを再シードすることができます

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

RESEEDの動作は、新しいテーブルと、以前にBOLから挿入されたデータがあったテーブルとでは異なることに注意してください。

DBCC CHECKIDENT( 'table_name'、RESEED、newReseedValue)

現在のID値はnewReseedValueに設定されます。作成後にテーブルに行が挿入されていない場合、DBCC CHECKIDENTの実行後に挿入された最初の行は、newReseedValueをIDとして使用します。それ以外の場合、挿入された次の行はnewReseedValue + 1を使用します。newReseedValueの値がID列の最大値より小さい場合、エラーメッセージ2627がテーブルへの後続の参照で生成されます。

制約を無効にすると切り捨てを使用できないという事実を指摘してくれたRobertに感謝します。制約を削除してから再作成する必要があります。


34
制約を無効にすると、FOREIGN KEY制約によって参照されるテーブルの切り捨ては許可されません。FK制約を削除する必要があります。これについて私が間違っている場合は返信してください。しかし、それらを落とさないようにする方法が見つかりませんでした。
ロバートクレイプール

1
このステートメントには、タイプミスの「テーブル」キーワードだけを含めないでください。EXEC sp_MSForEachTable "DELETE FROM TABLE?" 正しいバージョンは次のとおりです。EXECsp_MSForEachTable "DELETE FROM?"
Raghav、

4
2008以降のSSMSを使用している場合SET ROWCOUNT 0、デフォルトではアクションを500行に制限するため、スクリプトの最初に追加することをお勧めします。すべてのデータが実際に削除されるわけではないため、私が行ったようにイライラするエラーが発生します。
Sean Hanley、2011

1
これはうまくいきました。私の場合、削除ステートメントの前後にEXEC sp_msforeachtable "ALTER TABLE?Disable TRIGGER all"とEXEC sp_msforeachtable "ALTER TABLE?Enable TRIGGER all"も追加する必要がありました。
RobC 2014年

2
私の好きな答え。しかし、なぜ(すべての、コメンターでも)リテラルSQL文字列を二重引用符で囲むのですか?
bitoolean 2018

57

これが、データベースワイプスクリプトの王様です。すべてのテーブルがクリアされ、正しく再シードされます。

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
残念ながら、sp_MSforeachtableはSET QUOTED_IDENTITY OFF本体(link)にあるため、計算された列がある場合、上記のコマンドは失敗します。更新:修正は「SET QUOTED_IDENTIFIERS on;」を追加することです。このエラーが発生する各ステートメントの先頭に(ここで説明したよう
マーキー2013

1
これは私のアイデンティティを再シードしなかったようです
totooooo

48

これを行う最も簡単な方法は、

  1. SQL Management Studioを開く
  2. データベースに移動する
  3. 右クリックして[タスク]-> [スクリプトの生成]を選択します(図1)。
  4. 「オブジェクトの選択」画面で、「特定のオブジェクトを選択する」オプションを選択し、「テーブル」をチェックします(写真2)
  5. 次の画面で、[詳細]を選択し、[スクリプトのドロップと作成]オプションを[スクリプトのドロップと作成]に変更します(図3)。
  6. スクリプトを新しいエディターウィンドウまたはファイルに保存し、必要に応じて実行することを選択します。

これにより、デバッグやすべてを含めたかどうかを心配する必要なく、すべてのテーブルを削除して再作成するスクリプトが得られます。これは単に切り捨てるだけではありませんが、結果は同じです。最後に割り当てられた値を記憶する切り捨てられたテーブルとは対照的に、自動インクリメントの主キーは0から始まることに注意してください。PreProdまたはProduction環境のManagement Studioにアクセスできない場合は、コードからこれを実行することもできます。

1。

ここに画像の説明を入力してください

2。

ここに画像の説明を入力してください

3。

ここに画像の説明を入力してください


1
非常に複雑なスキーマを持つデータベースにこれを使用する場合は注意が必要です。本番DBの開発コピーで試してみたところ、スキーマが破壊され、完全な再デプロイが必要になりました。
Techrocket9

1
保存したいすべてのものをスクリプト化する必要があります
ケンパチ船長

13

SQL Serverでは外部キーを使用してテーブルを切り捨てることができないため、すべてのテーブルの切り捨ては、テーブル間に外部キーの関係がない場合にのみ機能します。

これに代わる方法は、外部キーを持つテーブルを特定し、それらから最初に削除することです。その後、外部キーのないテーブルを後で切り捨てることができます。

詳細については、http://www.sqlteam.com/forums/topic.asp?TOPIC_ID = 65341およびhttp://www.sqlteam.com/forums/topic.asp?TOPIC_ID=72957を参照してください。


1
いい視点ね。考えていませんでした。最初にすべての制約を無効にし、データが削除されたら、それらを再度有効にできる場合があります。
レイ

7

MSSQL Server DeveploperまたはEnterpriseで使用したい別のオプションは、空のスキーマを作成した直後にデータベースのスナップショットを作成することです。その時点で、データベースをスナップショットに復元し続けることができます。


残念ながら、毎回すべてのFULLTEXTインデックスが失われます
Chris KL

6

これを行わないでください!本当に、良い考えではありません。

切り捨てるテーブルがわかっている場合は、それらを切り捨てるストアドプロシージャを作成します。外部キーの問題を回避するために順序を修正できます。

本当にそれらすべてを切り捨てたい場合(たとえば、BCPをロードできるようにするため)、データベースを削除して新しいデータベースを最初から作成するのと同じくらい迅速に処理できます。


ここで素敵な代替アプローチ。
サム

3
このアプローチの問題は、テーブルとデータベースを削除すると、異なるログインとスキーマに与えられたすべての権限が失われることです。テーブルをたくさん持つ大規模なデータベースでは、それを再作成するのは面倒です。
Punit Vora 2016年

4

同じデータベース内の他のテーブルのデータを削除または切り捨てるときに、特定のテーブル(つまり、静的ルックアップテーブル)にデータを保持したい場合は、例外を含むループが必要です。これは私がこの質問に出くわしたときに探していたものです。

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

4

すべてのテーブルを切り捨てる最も難しい部分は、外部キー制約を削除して再追加することです。

次のクエリは、@ 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)

次に、実行するステートメントをコピーします。ただし、少し工夫すれば、カーソルを使用して動的に実行できます。


3

データベースのスクリプトを作成し、それをスクリプトから削除して作成する方がはるかに簡単(そして場合によってはさらに高速)です。


3

空の「テンプレート」データベースを作成し、完全バックアップを取ります。更新する必要がある場合は、WITH REPLACEを使用して復元してください。高速、シンプル、防弾。そして、ここにいくつかのテーブルがいくつかの基本データ(たとえば、構成情報、またはアプリを実行するための単なる基本情報)を必要とする場合、それも処理します。


2

これはそのための1つの方法です。他にも10種類の方法があり、より効率的で効率的です。ただし、これは非常にまれにしか行われないようです。

tablesfromのリストを取得sysobjectsし、カーソルでループして、sp_execsql('truncate table ' + @table_name)それぞれを呼び出しますiteration


これを行うsqlの投稿を追加しました:)これも私が探していたものでした。
Chris Smith、

1

コメント化されたセクションを1回実行し、_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

0

各テーブルを削除して再作成するスクリプトよりもデータをクリアする方が良い理由はわかりません。

それか、空のDBのバックアップを保持して、古いDBに復元します


2
その理由は、ディスク上のデータベースファイルやログなどを削除して再作成するオーバーヘッドが非常に遅いためです。適切な単体テストの実行中にデータベースを1,000回ワイプすることを考えてください。
Chris KL、

0

テーブルを切り捨てる前に、すべての外部キーを削除する必要があります。このスクリプト を使用して、データベース内のすべての外部キーを削除および再作成する最終的なスクリプトを生成します。@action変数を「CREATE」または「DROP」に設定してください。


0

「から削除」を選択します+ TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_TYPE = 'BASE TABLE'

結果が来るところ。

クエリウィンドウにコピーして貼り付け、コマンドを実行する


0

少し遅いですが、誰かを助けるかもしれません。T-SQLを使用して次の処理を行うプロシージャを作成しました。

  1. すべての制約を一時テーブルに保存する
  2. すべての制約を削除
  3. 一部のテーブルを除くすべてのテーブルを切り捨てます。切り捨ては不要です。
  4. すべての制約を再作成します。

こちらのブログに掲載しまし

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.