参照するすべての外部キーへの主キー更新のカスケード


11

それを参照するすべての外部キー間で更新をカスケードして主キー列の値を更新することは可能ですか?

#編集1: followinqクエリを実行すると

select * from sys.foreign_keys where referenced_object_id=OBJECT_ID('myTable') 

、update_referential_actionが0に設定されていることがわかります。したがって、主キー列を更新した後は何も行われません。外部キーを更新してCASCADE UPDATEでそれらを作成するにはどうすればよいですか?

#EDIT 2:
スキーマ内のすべての外部キーの作成または削除をスクリプト化するには、次のスクリプトを実行します(ここから取得)

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;



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

    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



      IF @action <> 'CREATE'

        SET @tsql = 'ALTER TABLE '

                  + QUOTENAME(@schema_name) + '.' + QUOTENAME(@table_name)

                  + ' DROP CONSTRAINT ' + QUOTENAME(@constraint_name) + ';';

    ELSE

        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

            inner join sys.foreign_key_columns fkc

            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);

            FETCH NEXT FROM ColumnCursor INTO @fkCol, @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;

    IF @action = 'CREATE'

        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;

        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;  

DROP外部キースクリプトを生成するには、@ actionの値を、宣言句の 'DROP'と等しくなるように変更します。

DECLARE @action char(6) = 'DROP';

回答:


9

外部キー制約をON UPDATE CASCADE次のように定義した場合、変更された主キー値は、その制約を持つすべての外部キーにカスケードする必要があります。

ON UPDATE CASCADE制約がない場合は、更新を完了するためのスクリプトを作成する必要があります。

編集:ON UPDATE CASCADE制約はありませんが、それを設定したいので、それは少しの作業です。SQL Serverでは、制約を新しい設定に変更することはサポートされていません。

PKテーブルに対するFK制約を持つ各テーブルを反復処理する必要があります。FKを含む各テーブルについて:

  1. 既存のFK制約を削除するALTER TABLE。
  2. 問題のFKに対してON UPDATE CASCADE制約を作成するために、ALTER TABLEを再度実行します。

これには少し手間がかかりますが、ケースに応じて制約が適切に設定されます。

編集2:必要な情報はsys.foreign_keysにあります。そのテーブルから選択して、必要なすべての情報を取得できます。

ジョン・ポール・クックの投稿はここにあります:

http://social.technet.microsoft.com/wiki/contents/articles/2958.script-to-create-all-foreign-keys.aspx

このコードは、データベース内のすべてのFK制約を削除して作成します。データベースから必要な変更のみを加えることができるようにする必要があります。


詳細については、編集を参照してください
mounaim '12

すべての外部キー@RLFをスクリプト化する方法を知っていますか?
mounaim 14

@mounaim-スクリプトの作成に関するメモで更新。
RLF 2014

私は同じことと同じリンクに取り組んでいた私の編集@RLFを参照してください
mounaim '12

1
他のWebサイトへのリンクが後で壊れる可能性があるため、ここでDBA SEにコードブロックを含めることをお
勧めします

4

確かにできます。ON UPDATE CASCADEあなたが探しているものです。

ここに小さなハウツーがあります:http : //sqlandme.com/2011/08/08/sql-server-how-to-cascade-updates-and-deletes-to-related-tables/

基本的に、PKを変更すると、カスケードが実行され、それを参照するすべてのFKが更新されます。これは、CREATEステートメントで行うことができます。CASCADE DELETE

CASCADEは実際にはバックグラウンドSERIALIZABLEで分離レベル(通常、SQLはREAD COMMITTEDデフォルトで実行されます)で実行されるので、ブロッキングの問題に注意してください。

分離レベルの詳細については、次の記事を参照してください。http//msdn.microsoft.com/en-us/library/ms173763.aspx


3

すべての外部キーをCASCADE UPDATEとして定義します

これを行っていない場合は、

  1. 新しい主キーで新しい行を作成する
  2. すべての子テーブルを更新する
  3. 古い行を削除

..もちろんトランザクションで、失敗する可能性のある他の制約に注意する


@gbnに感謝します。私の外部キーを更新することは可能ですか、それともそれらを削除してON CASCADE UPDATE句で再作成する必要がありますか?
mounaim 2014

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