T-SQLを使用して外部キー制約を一時的に無効にするにはどうすればよいですか?


824

SQL Serverでは、外部キー制約の無効化と有効化がサポートされていますか?または、私の唯一のオプションは、拘束をdropしてからcreate拘束することですか?


128
「なぜ」と尋ねる人のために、これを実行する必要があります。これは、データのロード方法を維持および指定する必要なく、複数のテーブルからテストデータを削除およびロードできるようにするテスト環境用です。このシナリオでは、データの整合性はそれほど重要ではありません。
レイ

8
注-テーブルを切り捨てる場合は、実際に制約を削除する必要があります。
OutstandingBill

@OutstandingBillどうやら、これはTRUNCATEで機能します。
jpaugh

1
本番環境で誰もがそれを疑問視するのは奇妙に思えます。非常に一般的な使用例は、一括挿入です。自己参照テーブルがある場合、親行が常に子の前に挿入されるように一括挿入を並べ替えることが非常に難しい場合があるため、制約を無効にして一括挿入を有効にし、制約を有効にします。
Auspex

回答:


1126

データベースのすべての制約を無効にする場合は、次のコードを実行してください。

-- disable all constraints
EXEC sp_MSforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"

それらを再びオンにするには、次のコマンドを実行します(もちろん、印刷はオプションであり、表をリストするだけです)。

-- enable all constraints
exec sp_MSforeachtable @command1="print '?'", @command2="ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"

あるデータベースから別のデータベースにデータを入力するときに便利です。制約を削除するよりもはるかに優れたアプローチです。あなたが言ったように、それはデータベース内のすべてのデータを削除してそれを再作成するときに便利です(たとえば、テスト環境で)。

すべてのデータを削除する場合は、この解決策が役立つことがあります。

また、すべてのトリガーを無効にすると便利な場合もあります。完全なソリューションはここで確認できます


9
"ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"「CHECK」は1つだけあるべきですか?
CrazyPyro

27
@CrazyPyro-両方は必要ありません
kristof、2011年

32
@CrazyPyro:両方が実際に必要です。これは、最初のCHECKがWITHに属し、2番目のCHECKがCONSTRAINTに属しているためです(制約のタイプです)。最初のCHECKは、制約をアクティブ化するときにデータの整合性をチェックすることを保証します。それを望まない場合は、WITH NOCHECKと書くことができます。実際のデータを気にしない特定のテスト状況では、クエリで何か操作できるようにいくつかのデータがある場合に役立ちます。
Valentino Vranken、2012年

8
2番目のコマンドでこの結果が得られるのは悪いことですか?「ALTER TABLEステートメントはFOREIGN KEY制約と競合しました...」
Devil's Advocate

34
制約が無効になっていても、TRUNCATE TABLEは機能しないことに注意してください。そのためには、制約を削除する必要があります。それ以外の場合は、FROM DELETEを使用していますが、考慮に違いを取る:mssqltips.com/sqlservertip/1080/...
ジェームズ・マコーマック

404

http://www.sqljunkies.com/WebLog/roman/archive/2005/01/30/7037.aspx

-- Disable all table constraints

ALTER TABLE MyTable NOCHECK CONSTRAINT ALL

-- Enable all table constraints

ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT ALL

-- Disable single constraint

ALTER TABLE MyTable NOCHECK CONSTRAINT MyConstraint

-- Enable single constraint

ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT MyConstraint

29
良い結果ですが、外部キー制約を削除しないとテーブルを切り捨てることはできないことに注意してください
Steven A. Lowe

1
また、制約をオンに戻してデータ整合性チェックを行うと、データが失敗する可能性があり、そのような問題の修正は、失敗したデータが長い文字列の最後にある場合、悪夢になる可能性があるリンクされた制約。
Jimoc 2008年

1
制約をオンに戻すときにも、2番目のチェックが必要です。それ以外の場合、現状のままで、コードは制約を1回だけチェックし、オンにしない。
ps2goat 2013

3
はい、2012年には「チ​​ェックチェックあり」が必要です。編集は拒否されましたか?MSリンク
crokusek 2014年

1
制約を再度有効にするためにここで使用するステートメントには、WITH CHECK句がありません。これはかなり大きな欠陥です。詳細については私の回答を参照してください-stackoverflow.com/a/35427150/81595
Scott Munro、

37

制約を無効にするには、NOCHECKALTERを使用するテーブルを使用します

ALTER TABLE [TABLE_NAME] NOCHECK CONSTRAINT [ALL|CONSTRAINT_NAME]

ダブルチェックを使用する必要があるようにするには:

ALTER TABLE [TABLE_NAME] WITH CHECK CHECK CONSTRAINT [ALL|CONSTRAINT_NAME]
  • ダブルチェックチェックに注意してください有効にするときに。
  • ALLは、テーブル内のすべての制約を意味します。

完了したら、ステータスを確認する必要がある場合は、このスクリプトを使用して制約ステータスをリストします。非常に役立ちます:

    SELECT (CASE 
        WHEN OBJECTPROPERTY(CONSTID, 'CNSTISDISABLED') = 0 THEN 'ENABLED'
        ELSE 'DISABLED'
        END) AS STATUS,
        OBJECT_NAME(CONSTID) AS CONSTRAINT_NAME,
        OBJECT_NAME(FKEYID) AS TABLE_NAME,
        COL_NAME(FKEYID, FKEY) AS COLUMN_NAME,
        OBJECT_NAME(RKEYID) AS REFERENCED_TABLE_NAME,
        COL_NAME(RKEYID, RKEY) AS REFERENCED_COLUMN_NAME
   FROM SYSFOREIGNKEYS
ORDER BY TABLE_NAME, CONSTRAINT_NAME,REFERENCED_TABLE_NAME, KEYNO 

主キーを表示しませんか?以下のために外部キーSYSFOREIGNKEYS システムビューはmsdn.microsoft.com/en-us/library/ms177604.aspx sys.sysforeignkeys
Kiquenet

挿入で主キーを無効にしようとしている場合、主キーを確認するだけであれば(SET IDENTITY_INSERT)を使用することをお勧めします。sys.keyesをsys.indexes.is_primary_keyで試すことができます
Diego Mendes

29

最善のオプションは、外部キー制約を削除および作成することです。

この投稿で「現状のまま」機能する例は見つかりませんでした。外部キーが異なるスキーマを参照している場合は機能せず、外部キーが複数の列を参照している場合は機能しません。このスクリプトでは、外部キーごとに複数のスキーマと複数の列の両方が考慮されます。

「ADD CONSTRAINT」ステートメントを生成するスクリプトは次のとおりです。複数の列の場合、カンマで区切ります(DROPステートメントを実行する前に、この出力を必ず保存してください)。

PRINT N'-- CREATE FOREIGN KEY CONSTRAINTS --';

SET NOCOUNT ON;
SELECT '
PRINT N''Creating '+ const.const_name +'...''
GO
ALTER TABLE ' + const.parent_obj + '
    ADD CONSTRAINT ' + const.const_name + ' FOREIGN KEY (
            ' + const.parent_col_csv + '
            ) REFERENCES ' + const.ref_obj + '(' + const.ref_col_csv + ')
GO'
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

「DROP CONSTRAINT」ステートメントを生成するスクリプトは次のとおりです。

PRINT N'-- DROP FOREIGN KEY CONSTRAINTS --';

SET NOCOUNT ON;

SELECT '
PRINT N''Dropping ' + fk.NAME + '...''
GO
ALTER TABLE [' + sch.NAME + '].[' + OBJECT_NAME(fk.parent_object_id) + ']' + ' DROP  CONSTRAINT ' + '[' + fk.NAME + ']
GO'
FROM sys.foreign_keys AS fk
INNER JOIN sys.schemas AS sch ON sch.schema_id = fk.schema_id
ORDER BY fk.NAME

5
制約を無効にして再度有効にするよりも優れている理由を説明できますか?
Mahmoodvcs 2014年

素晴らしいスクリプトです。同様の代替アプローチについては、mssqltips.com
Matt Browne

11

SQL-92標準では、制約をDEFERRABLEとして宣言して、トランザクションのスコープ内で(暗黙的または明示的に)遅延させることができます。悲しいことに、SQL ServerにはまだこのSQL-92機能がありません。

私にとって、制約をNOCHECKに変更することは、データベース構造をその場で変更することと同じです-制約を削除することは確かです-そして避けるべきことです(例えば、ユーザーはより高い特権を必要とします)。


11
   --Drop and Recreate Foreign Key Constraints

SET NOCOUNT ON

DECLARE @table TABLE(
   RowId INT PRIMARY KEY IDENTITY(1, 1),
   ForeignKeyConstraintName NVARCHAR(200),
   ForeignKeyConstraintTableSchema NVARCHAR(200),
   ForeignKeyConstraintTableName NVARCHAR(200),
   ForeignKeyConstraintColumnName NVARCHAR(200),
   PrimaryKeyConstraintName NVARCHAR(200),
   PrimaryKeyConstraintTableSchema NVARCHAR(200),
   PrimaryKeyConstraintTableName NVARCHAR(200),
   PrimaryKeyConstraintColumnName NVARCHAR(200)    
)

INSERT INTO @table(ForeignKeyConstraintName, ForeignKeyConstraintTableSchema, ForeignKeyConstraintTableName, ForeignKeyConstraintColumnName)
SELECT 
   U.CONSTRAINT_NAME, 
   U.TABLE_SCHEMA, 
   U.TABLE_NAME, 
   U.COLUMN_NAME 
FROM 
   INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
      INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
         ON U.CONSTRAINT_NAME = C.CONSTRAINT_NAME
WHERE
   C.CONSTRAINT_TYPE = 'FOREIGN KEY'

UPDATE @table SET
   PrimaryKeyConstraintName = UNIQUE_CONSTRAINT_NAME
FROM 
   @table T
      INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS R
         ON T.ForeignKeyConstraintName = R.CONSTRAINT_NAME

UPDATE @table SET
   PrimaryKeyConstraintTableSchema  = TABLE_SCHEMA,
   PrimaryKeyConstraintTableName  = TABLE_NAME
FROM @table T
   INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
      ON T.PrimaryKeyConstraintName = C.CONSTRAINT_NAME

UPDATE @table SET
   PrimaryKeyConstraintColumnName = COLUMN_NAME
FROM @table T
   INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
      ON T.PrimaryKeyConstraintName = U.CONSTRAINT_NAME

--SELECT * FROM @table

--DROP CONSTRAINT:
SELECT
   '
   ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + '] 
   DROP CONSTRAINT ' + ForeignKeyConstraintName + '

   GO'
FROM
   @table

--ADD CONSTRAINT:
SELECT
   '
   ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + '] 
   ADD CONSTRAINT ' + ForeignKeyConstraintName + ' FOREIGN KEY(' + ForeignKeyConstraintColumnName + ') REFERENCES [' + PrimaryKeyConstraintTableSchema + '].[' + PrimaryKeyConstraintTableName + '](' + PrimaryKeyConstraintColumnName + ')

   GO'
FROM
   @table

GO

ハムリン、私はあなたに同意します。SSISを使用してデータを転送する場合、またはデータを複製する場合は、一時的に外部キー制約を無効にするか削除してから、再度有効にするか再作成する必要があります。これらの場合、参照整合性はソースデータベースで既に維持されているため、参照整合性は問題になりません。したがって、この問題については安心してください。


このスクリプトは「ALTER」コマンドを生成するのに最適ですが、SPでこれらのコマンドを実行/実行するにはどうすればよいですか?
BlueChippy 2012年

1
外部キーのいずれかが複数列である場合、これは機能しないと思います
Zar Shardan

これは、非常に長いテーブル/キー名のすべての文字も生成しませんでした。
Joshua Drake

11
SET NOCOUNT ON

DECLARE @table TABLE(
   RowId INT PRIMARY KEY IDENTITY(1, 1),
   ForeignKeyConstraintName NVARCHAR(200),
   ForeignKeyConstraintTableSchema NVARCHAR(200),
   ForeignKeyConstraintTableName NVARCHAR(200),
   ForeignKeyConstraintColumnName NVARCHAR(200),
   PrimaryKeyConstraintName NVARCHAR(200),
   PrimaryKeyConstraintTableSchema NVARCHAR(200),
   PrimaryKeyConstraintTableName NVARCHAR(200),
   PrimaryKeyConstraintColumnName NVARCHAR(200),
   UpdateRule NVARCHAR(100),
   DeleteRule NVARCHAR(100)   
)

INSERT INTO @table(ForeignKeyConstraintName, ForeignKeyConstraintTableSchema, ForeignKeyConstraintTableName, ForeignKeyConstraintColumnName)
SELECT 
   U.CONSTRAINT_NAME, 
   U.TABLE_SCHEMA, 
   U.TABLE_NAME, 
   U.COLUMN_NAME
FROM 
   INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
      INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
         ON U.CONSTRAINT_NAME = C.CONSTRAINT_NAME
WHERE
   C.CONSTRAINT_TYPE = 'FOREIGN KEY'

UPDATE @table SET
   T.PrimaryKeyConstraintName = R.UNIQUE_CONSTRAINT_NAME,
   T.UpdateRule = R.UPDATE_RULE,
   T.DeleteRule = R.DELETE_RULE
FROM 
   @table T
      INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS R
         ON T.ForeignKeyConstraintName = R.CONSTRAINT_NAME

UPDATE @table SET
   PrimaryKeyConstraintTableSchema  = TABLE_SCHEMA,
   PrimaryKeyConstraintTableName  = TABLE_NAME
FROM @table T
   INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
      ON T.PrimaryKeyConstraintName = C.CONSTRAINT_NAME

UPDATE @table SET
   PrimaryKeyConstraintColumnName = COLUMN_NAME
FROM @table T
   INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
      ON T.PrimaryKeyConstraintName = U.CONSTRAINT_NAME

--SELECT * FROM @table

SELECT '
BEGIN TRANSACTION
BEGIN TRY'

--DROP CONSTRAINT:
SELECT
   '
 ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + '] 
 DROP CONSTRAINT ' + ForeignKeyConstraintName + '
   '
FROM
   @table

SELECT '
END TRY

BEGIN CATCH
   ROLLBACK TRANSACTION
   RAISERROR(''Operation failed.'', 16, 1)
END CATCH

IF(@@TRANCOUNT != 0)
BEGIN
   COMMIT TRANSACTION
   RAISERROR(''Operation completed successfully.'', 10, 1)
END
'

--ADD CONSTRAINT:
SELECT '
BEGIN TRANSACTION
BEGIN TRY'

SELECT
   '
   ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + '] 
   ADD CONSTRAINT ' + ForeignKeyConstraintName + ' FOREIGN KEY(' + ForeignKeyConstraintColumnName + ') REFERENCES [' + PrimaryKeyConstraintTableSchema + '].[' + PrimaryKeyConstraintTableName + '](' + PrimaryKeyConstraintColumnName + ') ON UPDATE ' + UpdateRule + ' ON DELETE ' + DeleteRule + '
   '
FROM
   @table

SELECT '
END TRY

BEGIN CATCH
   ROLLBACK TRANSACTION
   RAISERROR(''Operation failed.'', 16, 1)
END CATCH

IF(@@TRANCOUNT != 0)
BEGIN
   COMMIT TRANSACTION
   RAISERROR(''Operation completed successfully.'', 10, 1)
END'

GO

10

WITH CHECK CHECK ほぼ間違いなく必要です!

この点は、いくつかの回答やコメントで提起されましたが、もう一度呼びかけることが重要だと思います。

次のコマンド(no WITH CHECK)を使用して制約を再度有効にすると、いくつかの重大な欠点が生じます。

ALTER TABLE MyTable CHECK CONSTRAINT MyConstraint;

チェック付き| チェックなし

テーブル内のデータが、新しく追加された、または再度有効にされたFOREIGN KEYまたはCHECK制約に対して検証されるかどうかを指定します。指定しない場合、WITH CHECKは新しい制約に対して想定され、WITH NOCHECKは再有効化された制約に対して想定されます。

既存のデータに対して新しいCHECKまたはFOREIGN KEY制約を検証しない場合は、WITH NOCHECKを使用します。まれな場合を除いて、これを行うことはお勧めしません。新しい制約は、その後のすべてのデータ更新で評価されます。制約が追加されたときにWITH NOCHECKによって抑制された制約違反があると、制約に準拠しないデータで行を更新すると、将来の更新が失敗する可能性があります。

クエリオプティマイザーは、WITH NOCHECKで定義された制約を考慮しません。このような制約は、ALTER TABLE table WITH CHECK CHECK CONSTRAINT ALLを使用して再度有効にするまで無視されます。

注: WITH NOCHECKは、制約を再度有効にするためのデフォルトです。なぜだろう...

  1. このコマンドの実行中にテーブル内の既存のデータは評価されません。正常に完了しても、テーブル内のデータが制約に従って有効であるとは限りません。
  2. 無効なレコードの次の更新中に、制約が評価されて失敗します。その結果、行われた実際の更新とは無関係のエラーが発生する可能性があります。
  3. データが有効であることを確認するために制約に依存するアプリケーションロジックは失敗する可能性があります。
  4. クエリオプティマイザーは、この方法で有効になっている制約を利用しません。

sys.foreign_keysシステムビューは、問題にいくつかの可視性を提供します。それはAN両方持っていることを注意is_disabledしてis_not_trusted列を。is_disabled将来のデータ操作操作が制約に対して検証されるかどうかを示します。is_not_trusted現在テーブルにあるすべてのデータが制約に対して検証されたかどうかを示します。

ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT MyConstraint;

あなたの制約は信頼されるべきですか?探し出す...

SELECT * FROM sys.foreign_keys WHERE is_not_trusted = 1;

9

最初の投稿:)

OPの場合、大量のデータの削除や大きな削除に関するトランザクションログバルーンの問題がない限り、kristofのソリューションが機能します。また、tlogストレージに余裕があっても、削除はtlogへの書き込みであるため、数億行のテーブルでは操作に非常に長い時間がかかる可能性があります。

一連のカーソルを使用して、巨大な本番データベースの1つの大規模なコピーを頻繁に切り捨てて再ロードします。このソリューションは、複数のスキーマ、複数の外部キー列を考慮して設計されており、SSISで使用するためにsprocを実行できます。

これには、DROP、CREATE、およびCHECK FKスクリプトを格納する3つのステージングテーブル(実際のテーブル)の作成、それらのスクリプトの作成とテーブルへの挿入、およびテーブルのループと実行が含まれます。添付のスクリプトは4つの部分で構成されています。1)3つのステージング(実際の)テーブルでのスクリプトの作成と保存、2)カーソルによるFKドロップスクリプトの実行、1)3)sp_MSforeachtableを使用してすべての3つのステージングテーブル以外のデータベース内のテーブルおよび4.)ETL SSISパッケージの最後にあるFKの作成とFKのチェックスクリプトの実行。

SSISのSQL実行タスクでスクリプト作成部分を実行します。2番目のSQL実行タスクで「ドロップFKスクリプトの実行」部分を実行します。トランケーションスクリプトを3番目のSQL実行タスクに配置し、CREATEとCHECKスクリプトを制御フローの最後の最後のSQL実行タスク(または必要に応じて2つ)にアタッチする前に、他に必要なETLプロセスを実行します。

sync_CreateFKから*を選択し、クエリウィンドウにコピーして貼り付け、一度に1つずつ実行し、データの問題を修正すると、外部キーの再適用が失敗したときに、実際のテーブルにスクリプトを保存することが非常に重要であることが証明されています。失敗した/まだ再適用に失敗しているものを見つけます。

スクリプトが失敗した場合は、再実行する前にすべての外部キー/チェックを再適用することを確認せずにスクリプトを再実行しないでください。そうしないと、ステージングテーブルが削除され、fkスクリプトの作成が失われてチェックされる可能性が高くなります。実行するスクリプトの作成前に再作成されます。

----------------------------------------------------------------------------
1)
/*
Author:         Denmach
DateCreated:    2014-04-23
Purpose:        Generates SQL statements to DROP, ADD, and CHECK existing constraints for a 
                database.  Stores scripts in tables on target database for execution.  Executes
                those stored scripts via independent cursors. 
DateModified:
ModifiedBy
Comments:       This will eliminate deletes and the T-log ballooning associated with it.
*/

DECLARE @schema_name SYSNAME; 
DECLARE @table_name SYSNAME; 
DECLARE @constraint_name SYSNAME; 
DECLARE @constraint_object_id INT; 
DECLARE @referenced_object_name SYSNAME; 
DECLARE @is_disabled BIT; 
DECLARE @is_not_for_replication BIT; 
DECLARE @is_not_trusted BIT; 
DECLARE @delete_referential_action TINYINT; 
DECLARE @update_referential_action TINYINT; 
DECLARE @tsql NVARCHAR(4000); 
DECLARE @tsql2 NVARCHAR(4000); 
DECLARE @fkCol SYSNAME; 
DECLARE @pkCol SYSNAME; 
DECLARE @col1 BIT; 
DECLARE @action CHAR(6);  
DECLARE @referenced_schema_name SYSNAME;



--------------------------------Generate scripts to drop all foreign keys in a database --------------------------------

IF OBJECT_ID('dbo.sync_dropFK') IS NOT NULL
DROP TABLE sync_dropFK

CREATE TABLE sync_dropFK
    (
    ID INT IDENTITY (1,1) NOT NULL
    , Script NVARCHAR(4000)
    )

DECLARE FKcursor CURSOR FOR

    SELECT 
        OBJECT_SCHEMA_NAME(parent_object_id)
        , OBJECT_NAME(parent_object_id)
        , name
    FROM 
        sys.foreign_keys WITH (NOLOCK)
    ORDER BY 
        1,2;

OPEN FKcursor;

FETCH NEXT FROM FKcursor INTO 
    @schema_name
    , @table_name
    , @constraint_name

WHILE @@FETCH_STATUS = 0

BEGIN
        SET @tsql = 'ALTER TABLE '
                + QUOTENAME(@schema_name) 
                + '.' 
                + QUOTENAME(@table_name)
                + ' DROP CONSTRAINT ' 
                + QUOTENAME(@constraint_name) 
                + ';';
    --PRINT @tsql;
    INSERT sync_dropFK  (
                        Script
                        )
                        VALUES (
                                @tsql
                                )   

    FETCH NEXT FROM FKcursor INTO 
    @schema_name
    , @table_name
    , @constraint_name
    ;

END;

CLOSE FKcursor;

DEALLOCATE FKcursor;


---------------Generate scripts to create all existing foreign keys in a database --------------------------------
----------------------------------------------------------------------------------------------------------
IF OBJECT_ID('dbo.sync_createFK') IS NOT NULL
DROP TABLE sync_createFK

CREATE TABLE sync_createFK
    (
    ID INT IDENTITY (1,1) NOT NULL
    , Script NVARCHAR(4000)
    )

IF OBJECT_ID('dbo.sync_createCHECK') IS NOT NULL
DROP TABLE sync_createCHECK

CREATE TABLE sync_createCHECK
    (
    ID INT IDENTITY (1,1) NOT NULL
    , Script NVARCHAR(4000)
    )   

DECLARE FKcursor CURSOR FOR

     SELECT 
        OBJECT_SCHEMA_NAME(parent_object_id)
        , OBJECT_NAME(parent_object_id)
        , name
        , OBJECT_NAME(referenced_object_id)
        , OBJECT_ID
        , is_disabled
        , is_not_for_replication
        , is_not_trusted
        , delete_referential_action
        , update_referential_action
        , OBJECT_SCHEMA_NAME(referenced_object_id)

    FROM 
        sys.foreign_keys WITH (NOLOCK)

    ORDER BY 
        1,2;

OPEN FKcursor;

FETCH NEXT FROM FKcursor INTO 
    @schema_name
    , @table_name
    , @constraint_name
    , @referenced_object_name
    , @constraint_object_id
    , @is_disabled
    , @is_not_for_replication
    , @is_not_trusted
    , @delete_referential_action
    , @update_referential_action
    , @referenced_schema_name;

WHILE @@FETCH_STATUS = 0

BEGIN

        BEGIN
            SET @tsql = 'ALTER TABLE '
                        + QUOTENAME(@schema_name) 
                        + '.' 
                        + QUOTENAME(@table_name)
                        +   CASE 
                                @is_not_trusted
                                WHEN 0 THEN ' WITH CHECK '
                                ELSE ' WITH NOCHECK '
                            END
                        + ' ADD CONSTRAINT ' 
                        + QUOTENAME(@constraint_name)
                        + ' FOREIGN KEY (';

        SET @tsql2 = '';

        DECLARE ColumnCursor CURSOR FOR 

            SELECT 
                COL_NAME(fk.parent_object_id
                , fkc.parent_column_id)
                , COL_NAME(fk.referenced_object_id
                , fkc.referenced_column_id)

            FROM 
                sys.foreign_keys fk WITH (NOLOCK)
                INNER JOIN sys.foreign_key_columns fkc WITH (NOLOCK) ON fk.[object_id] = fkc.constraint_object_id

            WHERE 
                fkc.constraint_object_id = @constraint_object_id

            ORDER BY 
                fkc.constraint_column_id;

        OPEN ColumnCursor;

        SET @col1 = 1;

        FETCH NEXT FROM ColumnCursor INTO @fkCol, @pkCol;

        WHILE @@FETCH_STATUS = 0

        BEGIN
            IF (@col1 = 1)
                SET @col1 = 0;
            ELSE
            BEGIN
                SET @tsql = @tsql + ',';
                SET @tsql2 = @tsql2 + ',';
            END;

            SET @tsql = @tsql + QUOTENAME(@fkCol);
            SET @tsql2 = @tsql2 + QUOTENAME(@pkCol);
            --PRINT '@tsql = ' + @tsql 
            --PRINT '@tsql2 = ' + @tsql2
            FETCH NEXT FROM ColumnCursor INTO @fkCol, @pkCol;
            --PRINT 'FK Column ' + @fkCol
            --PRINT 'PK Column ' + @pkCol 
        END;

        CLOSE ColumnCursor;
        DEALLOCATE ColumnCursor;

        SET @tsql = @tsql + ' ) REFERENCES ' 
                    + QUOTENAME(@referenced_schema_name) 
                    + '.' 
                    + QUOTENAME(@referenced_object_name)
                    + ' (' 
                    + @tsql2 + ')';

        SET @tsql = @tsql
                    + ' ON UPDATE ' 
                    + 
                        CASE @update_referential_action
                            WHEN 0 THEN 'NO ACTION '
                            WHEN 1 THEN 'CASCADE '
                            WHEN 2 THEN 'SET NULL '
                                ELSE 'SET DEFAULT '
                        END

                    + ' ON DELETE ' 
                    + 
                        CASE @delete_referential_action
                            WHEN 0 THEN 'NO ACTION '
                            WHEN 1 THEN 'CASCADE '
                            WHEN 2 THEN 'SET NULL '
                                ELSE 'SET DEFAULT '
                        END

                    + 
                    CASE @is_not_for_replication
                        WHEN 1 THEN ' NOT FOR REPLICATION '
                            ELSE ''
                    END
                    + ';';

        END;

    --  PRINT @tsql
        INSERT sync_createFK    
                        (
                        Script
                        )
                        VALUES (
                                @tsql
                                )

-------------------Generate CHECK CONSTRAINT scripts for a database ------------------------------
----------------------------------------------------------------------------------------------------------

        BEGIN

        SET @tsql = 'ALTER TABLE '
                    + QUOTENAME(@schema_name) 
                    + '.' 
                    + QUOTENAME(@table_name)
                    + 
                        CASE @is_disabled
                            WHEN 0 THEN ' CHECK '
                                ELSE ' NOCHECK '
                        END
                    + 'CONSTRAINT ' 
                    + QUOTENAME(@constraint_name)
                    + ';';
        --PRINT @tsql;
        INSERT sync_createCHECK 
                        (
                        Script
                        )
                        VALUES (
                                @tsql
                                )   
        END;

    FETCH NEXT FROM FKcursor INTO 
    @schema_name
    , @table_name
    , @constraint_name
    , @referenced_object_name
    , @constraint_object_id
    , @is_disabled
    , @is_not_for_replication
    , @is_not_trusted
    , @delete_referential_action
    , @update_referential_action
    , @referenced_schema_name;

END;

CLOSE FKcursor;

DEALLOCATE FKcursor;

--SELECT * FROM sync_DropFK
--SELECT * FROM sync_CreateFK
--SELECT * FROM sync_CreateCHECK
---------------------------------------------------------------------------
2.)
-----------------------------------------------------------------------------------------------------------------
----------------------------execute Drop FK Scripts --------------------------------------------------

DECLARE @scriptD NVARCHAR(4000)

DECLARE DropFKCursor CURSOR FOR
    SELECT Script 
    FROM sync_dropFK WITH (NOLOCK)

OPEN DropFKCursor

FETCH NEXT FROM DropFKCursor
INTO @scriptD

WHILE @@FETCH_STATUS = 0
BEGIN
--PRINT @scriptD
EXEC (@scriptD)
FETCH NEXT FROM DropFKCursor
INTO @scriptD
END
CLOSE DropFKCursor
DEALLOCATE DropFKCursor
--------------------------------------------------------------------------------
3.) 

------------------------------------------------------------------------------------------------------------------
----------------------------Truncate all tables in the database other than our staging tables --------------------
------------------------------------------------------------------------------------------------------------------


EXEC sp_MSforeachtable 'IF OBJECT_ID(''?'') NOT IN 
(
ISNULL(OBJECT_ID(''dbo.sync_createCHECK''),0),
ISNULL(OBJECT_ID(''dbo.sync_createFK''),0),
ISNULL(OBJECT_ID(''dbo.sync_dropFK''),0)
)
BEGIN TRY
 TRUNCATE TABLE ?
END TRY
BEGIN CATCH
 PRINT ''Truncation failed on''+ ? +''
END CATCH;' 
GO
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------
----------------------------execute Create FK Scripts and CHECK CONSTRAINT Scripts---------------
----------------------------tack me at the end of the ETL in a SQL task-------------------------
-------------------------------------------------------------------------------------------------
DECLARE @scriptC NVARCHAR(4000)

DECLARE CreateFKCursor CURSOR FOR
    SELECT Script 
    FROM sync_createFK WITH (NOLOCK)

OPEN CreateFKCursor

FETCH NEXT FROM CreateFKCursor
INTO @scriptC

WHILE @@FETCH_STATUS = 0
BEGIN
--PRINT @scriptC
EXEC (@scriptC)
FETCH NEXT FROM CreateFKCursor
INTO @scriptC
END
CLOSE CreateFKCursor
DEALLOCATE CreateFKCursor
-------------------------------------------------------------------------------------------------
DECLARE @scriptCh NVARCHAR(4000)

DECLARE CreateCHECKCursor CURSOR FOR
    SELECT Script 
    FROM sync_createCHECK WITH (NOLOCK)

OPEN CreateCHECKCursor

FETCH NEXT FROM CreateCHECKCursor
INTO @scriptCh

WHILE @@FETCH_STATUS = 0
BEGIN
--PRINT @scriptCh
EXEC (@scriptCh)
FETCH NEXT FROM CreateCHECKCursor
INTO @scriptCh
END
CLOSE CreateCHECKCursor
DEALLOCATE CreateCHECKCursor

7

制約を見つける

SELECT * 
FROM sys.foreign_keys
WHERE referenced_object_id = object_id('TABLE_NAME')

このSQLによって生成されたSQLを実行する

SELECT 
    'ALTER TABLE ' +  OBJECT_SCHEMA_NAME(parent_object_id) +
    '.[' + OBJECT_NAME(parent_object_id) + 
    '] DROP CONSTRAINT ' + name
FROM sys.foreign_keys
WHERE referenced_object_id = object_id('TABLE_NAME')

安全な方法。

注:制約を削除するためのソリューションが追加され、制約エラーなしでテーブルを削除または変更できるようになりました。


3

テーブルデザインを右クリックして[リレーションシップ]に移動し、左側のペインと右側のペインで外部キーを選択して、[外部キー制約を適用]を[はい](外部キー制約を有効にする)または[いいえ](に変更)に設定します。それを無効にします)。 ここに画像の説明を入力してください


3

「905」とマークされた回答は問題ないように見えますが、機能しません。

以下は私のために働いた。主キー、一意キー、デフォルトの制約は無効にできません。実際、 'sp_helpconstraint' 'がstatus_enabledに' n / a 'を示している場合- 有効/無効にできないことを意味します。

-無効にするスクリプトを生成するには

select 'ALTER TABLE ' + object_name(id) + ' NOCHECK CONSTRAINT [' + object_name(constid) + ']'
from sys.sysconstraints 
where status & 0x4813 = 0x813 order by object_name(id)

-有効にするスクリプトを生成するには

select 'ALTER TABLE ' + object_name(id) + ' CHECK CONSTRAINT [' + object_name(constid) + ']'
from sys.sysconstraints 
where status & 0x4813 = 0x813 order by object_name(id)

3

他の制約を一時的に無効にするのと同じ方法で、実際に外部キー制約を無効にできるはずです。

Alter table MyTable nocheck constraint FK_ForeignKeyConstraintName

制約名にリストされている最初のテーブルで制約を無効にしていることを確認してください。たとえば、外部キー制約がFK_LocationsEmployeesLocationIdEmployeeIdである場合、次のように使用します。

Alter table Locations nocheck constraint FK_LocationsEmployeesLocationIdEmployeeId

この制約に違反するとエラーが発生しますが、必ずしもそのテーブルが競合の原因であるとは限りません。


1

それらをすべてルール化する1つのスクリプト:これは、切り捨てコマンドと削除コマンドをsp_MSforeachtableと組み合わせて、制約の削除と再作成を回避できるようにする-切り捨てではなく削除する必要があるテーブルを指定するだけで、目的のために追加のスキーマフィルターを含めましたメジャー(2008r2でテスト済み)

declare @schema nvarchar(max) = 'and Schema_Id=Schema_id(''Value'')'
declare @deletiontables nvarchar(max) = '(''TableA'',''TableB'')'
declare @truncateclause nvarchar(max) = @schema + ' and o.Name not in ' +  + @deletiontables;
declare @deleteclause nvarchar(max) = @schema + ' and o.Name in ' + @deletiontables;        

exec sp_MSforeachtable 'alter table ? nocheck constraint all', @whereand=@schema
exec sp_MSforeachtable 'truncate table ?', @whereand=@truncateclause
exec sp_MSforeachtable 'delete from ?', @whereand=@deleteclause
exec sp_MSforeachtable 'alter table ? with check check constraint all', @whereand=@schema

1

テーブルの制約を一時的に無効にし、作業を行ってから、再構築できます。

ここにそれを行う簡単な方法があります...

すべての外部キーを無効にする主キーを含むすべてのインデックスを無効にしてから、主キーのみを再度有効にして、それらを操作できるようにします...

DECLARE @sql AS NVARCHAR(max)=''
select @sql = @sql +
    'ALTER INDEX ALL ON [' + t.[name] + '] DISABLE;'+CHAR(13)
from  
    sys.tables t
where type='u'

select @sql = @sql +
    'ALTER INDEX ' + i.[name] + ' ON [' + t.[name] + '] REBUILD;'+CHAR(13)
from  
    sys.key_constraints i
join
    sys.tables t on i.parent_object_id=t.object_id
where
    i.type='PK'


exec dbo.sp_executesql @sql;
go

[データの読み込みなど、何かを行う]

次に、インデックスを再度有効にして再構築します...

DECLARE @sql AS NVARCHAR(max)=''
select @sql = @sql +
    'ALTER INDEX ALL ON [' + t.[name] + '] REBUILD;'+CHAR(13)
from  
    sys.tables t
where type='u'

exec dbo.sp_executesql @sql;
go

これは有望に思えましたが、@sql常に切り捨てられます。:(
Will Strohl、

1

興味があれば、もっと便利なバージョンがあります。リンクがアクティブではなくなったWebサイトから、コードを少し持ち上げました。テーブルの配列をストアドプロシージャに含めることができるように変更し、すべてのステートメントを実行する前に、drop、truncate、addステートメントを入力します。これにより、どのテーブルを切り捨てる必要があるかを制御できます。

/****** Object:  UserDefinedTableType [util].[typ_objects_for_managing]    Script Date: 03/04/2016 16:42:55 ******/
CREATE TYPE [util].[typ_objects_for_managing] AS TABLE(
    [schema] [sysname] NOT NULL,
    [object] [sysname] NOT NULL
)
GO

create procedure [util].[truncate_table_with_constraints]
@objects_for_managing util.typ_objects_for_managing readonly

--@schema sysname
--,@table sysname

as 
--select
--    @table = 'TABLE',
--    @schema = 'SCHEMA'

declare @exec_table as table (ordinal int identity (1,1), statement nvarchar(4000), primary key (ordinal));

--print '/*Drop Foreign Key Statements for ['+@schema+'].['+@table+']*/'

insert into @exec_table (statement)
select
          'ALTER TABLE ['+SCHEMA_NAME(o.schema_id)+'].['+ o.name+'] DROP CONSTRAINT ['+fk.name+']'
from sys.foreign_keys fk
inner join sys.objects o
          on fk.parent_object_id = o.object_id
where 
exists ( 
select * from @objects_for_managing chk 
where 
chk.[schema] = SCHEMA_NAME(o.schema_id)  
and 
chk.[object] = o.name
) 
;
          --o.name = @table and
          --SCHEMA_NAME(o.schema_id)  = @schema

insert into @exec_table (statement) 
select
'TRUNCATE TABLE ' + src.[schema] + '.' + src.[object] 
from @objects_for_managing src
; 

--print '/*Create Foreign Key Statements for ['+@schema+'].['+@table+']*/'
insert into @exec_table (statement)
select 'ALTER TABLE ['+SCHEMA_NAME(o.schema_id)+'].['+o.name+'] ADD CONSTRAINT ['+fk.name+'] FOREIGN KEY (['+c.name+']) 
REFERENCES ['+SCHEMA_NAME(refob.schema_id)+'].['+refob.name+'](['+refcol.name+'])'
from sys.foreign_key_columns fkc
inner join sys.foreign_keys fk
          on fkc.constraint_object_id = fk.object_id
inner join sys.objects o
          on fk.parent_object_id = o.object_id
inner join sys.columns c
          on      fkc.parent_column_id = c.column_id and
                   o.object_id = c.object_id
inner join sys.objects refob
          on fkc.referenced_object_id = refob.object_id
inner join sys.columns refcol
          on fkc.referenced_column_id = refcol.column_id and
                   fkc.referenced_object_id = refcol.object_id
where 
exists ( 
select * from @objects_for_managing chk 
where 
chk.[schema] = SCHEMA_NAME(o.schema_id)  
and 
chk.[object] = o.name
) 
;

          --o.name = @table and
          --SCHEMA_NAME(o.schema_id)  = @schema



declare @looper int , @total_records int, @sql_exec nvarchar(4000)

select @looper = 1, @total_records = count(*) from @exec_table; 

while @looper <= @total_records 
begin

select @sql_exec = (select statement from @exec_table where ordinal =@looper)
exec sp_executesql @sql_exec 
print @sql_exec 
set @looper = @looper + 1
end

あなたの答えのデッドリンク。空白の記事を指します。
Neolisk

こんにちは、デッドリンクがあるかもしれませんが、コード全体がピースで指定されています。これの何が問題になっていますか?
ザックウィリス

間違いはありませんが、おそらく回答を編集してデッドリンクを削除する必要があります。
Neolisk
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.