级联主键更新所有引用外键

mou*_*aim 13 sql-server-2008 foreign-key sql-server referential-integrity update

是否可以通过在引用它的所有外键之间级联更新来更新主键列值?

# EDIT 1: 当我运行 followinq 查询

select * from sys.foreign_keys where referenced_object_id=OBJECT_ID('myTable') 
Run Code Online (Sandbox Code Playgroud)

,我看到 update_referential_action 设置为 0。因此更新我的主键列后没有采取任何操作。如何更新外键以使其ON 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;  
Run Code Online (Sandbox Code Playgroud)

要生成 DROP 外键脚本,请在声明子句中将 @action 值修改为等于 'DROP' :

DECLARE @action char(6) = 'DROP';
Run Code Online (Sandbox Code Playgroud)

RLF*_*RLF 10

如果您已将外键约束定义为,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 中找到。您可以从该表中进行选择以获取所需的所有信息。

可以在此处找到约翰·保罗·库克 (John Paul Cook) 的帖子:

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

此代码将删除并在数据库中创建所有 FK 约束。您应该能够从中工作,仅对数据库进行所需的更改。


Kri*_*yer 5

你当然可以。ON UPDATE CASCADE就是您正在寻找的。

这是一个小操作方法: http://sqlandme.com/2011/08/08/sql-server-how-to-cascade-updates-and-deletes-to-lated-tables/

基本上,当您修改 PK 时,级联将退出并更新引用它的所有 FK。这可以在你的声明中完成CREATE,就像你在做一个CASCADE DELETE

执行此操作时请密切注意,因为据我了解,CASCADE 实际上在幕后以隔离级别运行SERIALIZABLE(通常,SQL 默认运行),因此请注意任何阻塞问题。READ COMMITTED

有关隔离级别的其他信息可以在本文中找到:http://msdn.microsoft.com/en-us/library/ms173763.aspx