Sql-Server

級聯主鍵更新到所有引用外鍵

  • December 5, 2014

是否可以通過在引用它的所有外鍵之間級聯更新來更新主鍵列值?

# 編輯 1: 當我執行 followinq 查詢時

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

,我看到 update_referential_action 設置為 0。因此更新我的主鍵列後不採取任何行動。如何更新外鍵以使其ON CASCADE UPDATE

# 編輯 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';

如果您已將外鍵約束定義為ON UPDATE CASCADE,則更改的主鍵值應向下級聯到具有該約束的所有外鍵。

如果您沒有ON UPDATE CASCADE約束,那麼您將需要創建腳本來完成更新。

編輯:由於您沒有ON UPDATE CASCADE約束,但是您想要進行設置,因此需要做一些工作。SQL Server 不支持將約束更改為新設置。

有必要遍歷每個對 PK 表有 FK 約束的表。對於每個帶有 FK 的表:

  1. ALTER TABLE 刪除現有的 FK 約束。
  2. 再次 ALTER TABLE 為有問題的 FK 創建 ON UPDATE CASCADE 約束。

這需要一些努力,但會導致為您的案例正確設置約束。

編輯 2:您需要的資訊在 sys.foreign_keys 中找到。您可以從該表中進行選擇以獲取所需的所有資訊。

約翰保羅庫克的文章可以在這裡找到:

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

此程式碼將刪除並在數據庫中創建所有 FK 約束。您應該能夠從中工作以僅在數據庫中進行所需的更改。

引用自:https://dba.stackexchange.com/questions/84434