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


11

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

#编辑1: 当我运行followinq查询

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

,我看到update_referential_action设置为0。因此,在更新主键列之后不执行任何操作。如何更新外键以使其成为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';

Answers:


9

如果您已将外键约束定义为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约束。您应该能够以此为基础,仅对数据库进行所需的更改。


请参阅我的编辑以获取更多信息
mounaim 2014年

您知道如何编写所有外键@RLF的脚本吗?
mounaim 2014年

@mounaim-更新了有关创建脚本的注释。
RLF 2014年

我在做同样的事情,并且在相同的链接上查看我的编辑@RLF
mounaim 2014年

1
最好在DBA SE上包含代码块,因为指向其他网站的链接可能以后会断开:)
mounaim 2014年

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运行(通常READ COMMITTED默认情况下,SQL在默认情况下运行),因此请注意是否存在阻塞问题。

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


3

将所有外键定义为CASCADE UPDATE

如果您尚未执行此操作,则必须

  1. 用新的主键创建一个新行
  2. 更新所有子表
  3. 删除旧行

..在交易过程中,当心其他可能失败的约束


谢谢@gbn。是否可以更新我的外键,或者我只需要删除它们并使用ON CASCADE UPDATE子句重新创建它们?
mounaim 2014年

拖放并重新创建...
gbn 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.