それを参照するすべての外部キー間で更新をカスケードして主キー列の値を更新することは可能ですか?
#EDIT 1:followinq queryを実行すると
select * from sys.foreign_keys where referenced_object_id=OBJECT_ID('myTable')
、update_referential_actionが0に設定されていることがわかります。したがって、主キー列を更新した後は何も行われません。外部キーを更新してON CASCADE UPDATEにするにはどうすればよいですか?
#編集2:
スキーマ内のすべての外部キーの作成または削除をスクリプト化するには、次のスクリプトを実行します( here から取得)
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';
外部キー制約をON UPDATE CASCADE
として定義した場合、変更された主キー値は、その制約を持つすべての外部キーにカスケードダウンする必要があります。
ON UPDATE CASCADE
制約がない場合は、更新を完了するためのスクリプトを作成する必要があります。
編集:ON UPDATE CASCADE
制約はありませんが、それを設定したいので、これは少しの作業です。 SQL Serverは、制約を新しい設定に変更することをサポートしていません。
PKテーブルに対するFK制約を持つ各テーブルを反復処理する必要があります。 FKを含む各テーブルについて:
これには少し手間がかかりますが、ケースに応じて制約が適切に設定されます。
編集2:必要な情報はsys.foreign_keysにあります。そのテーブルから選択して、必要なすべての情報を取得できます。
ジョンポールクックの投稿はこちらです。
このコードは、データベース内のすべてのFK制約を削除して作成します。データベースから必要な変更のみを加えることができるはずです。
できます。 ON UPDATE CASCADE
はあなたが探しているものです。
ここに小さなハウツーがあります: http://sqlandme.com/2011/08/08/sql-server-how-to-cascade-updates-and-deletes-to-related-tables/
基本的に、PKを変更すると、カスケードが実行され、それを参照するすべてのFKが更新されます。これは、CASCADE DELETE
を実行する場合と同じように、CREATE
ステートメントで実行できます。
CASCADEは実際にはバックグラウンドで分離レベルSERIALIZABLE
(通常、SQLはデフォルトでREAD COMMITTED
で実行されます)で実行されるため、これを行うときは注意してください。ブロッキングの問題。
分離レベルに関する追加情報はこの記事にあります: http://msdn.Microsoft.com/en-us/library/ms173763.aspx
すべての外部キーをCASCADE UPDATEとして定義します
これを行っていない場合は、
..もちろんトランザクションで、失敗する可能性のある他の制約に注意する