Cập nhật khóa chính Cascade cho tất cả các khóa ngoại tham chiếu


11

Có thể cập nhật giá trị cột khóa chính với xếp tầng cập nhật trong số tất cả các khóa ngoại tham chiếu đến nó không?

# EDIT 1: Khi tôi chạy truy vấn followinq

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

, Tôi thấy rằng update_Vferential_action được đặt thành 0. Do đó, KHÔNG CÓ HÀNH ĐỘNG nào được thực hiện sau khi cập nhật các cột khóa chính của tôi. Làm cách nào tôi có thể cập nhật các khóa ngoại để làm cho chúng TRÊN CẬP NHẬT CASCADE ?

# EDIT 2:
Để tạo ra kịch bản tạo hoặc loại bỏ tất cả các khóa ngoại trong lược đồ của bạn, hãy chạy đoạn mã sau (lấy từ đây )

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;  

Để tạo tập lệnh khóa ngoài DROP, hãy sửa đổi giá trị @action bằng 'DROP' trong mệnh đề khai báo:

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

Câu trả lời:


9

Nếu bạn đã xác định các ràng buộc Khóa ngoài ON UPDATE CASCADEthì giá trị Khóa chính đã được thay đổi sẽ xếp tầng xuống tất cả các Khóa ngoại với ràng buộc đó.

Nếu bạn không có ON UPDATE CASCADEràng buộc, thì bạn sẽ cần tạo tập lệnh để hoàn thành cập nhật.

EDIT: Vì bạn không có ON UPDATE CASCADEràng buộc, nhưng bạn muốn thiết lập nó, đó là một chút công việc. SQL Server không hỗ trợ thay đổi các ràng buộc thành một cài đặt mới.

Cần lặp lại qua từng bảng có ràng buộc FK với bảng PK. Đối với mỗi bảng có FK:

  1. ALTER TABLE để loại bỏ ràng buộc FK hiện có.
  2. ALTER TABLE một lần nữa để tạo ràng buộc ON CẬP NHẬT CASCADE cho FK đang đề cập.

Điều này cần một chút nỗ lực, nhưng sẽ dẫn đến ràng buộc của bạn được đặt đúng cho trường hợp của bạn.

EDIT 2: Thông tin mà bạn cần được tìm thấy trong sys.forign_keys. Bạn có thể chọn từ bảng đó để có được tất cả thông tin bạn cần.

Một bài đăng của John Paul Cook có thể được tìm thấy ở đây:

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

Mã này sẽ bỏ và tạo TẤT CẢ các ràng buộc FK trong cơ sở dữ liệu. Bạn sẽ có thể làm việc từ đó để chỉ thực hiện các thay đổi mà bạn muốn trong cơ sở dữ liệu của mình.


xem chỉnh sửa của tôi để biết thêm thông tin
mounaim

Bạn có biết cách tạo kịch bản cho tất cả các khóa ngoại @RLF không?
mounaim

@mounaim - Cập nhật với một lưu ý về việc tạo tập lệnh.
RLF

Tôi đang làm việc trên cùng một thứ và cùng một liên kết, xem bản chỉnh sửa của tôi @RLF
mounaim

1
tốt hơn là bao gồm các khối mã ở đây trên DBA SE vì các liên kết đến các trang web khác có thể bị
hỏng

4

Bạn chắc chắn có thể. ON UPDATE CASCADElà những gì bạn đang tìm kiếm.

Đây là một cách nhỏ: http://sqlandme.com/2011/08/08/sql-server-how-to-cascade-updates-and-deletes-to-related-tables/

Về cơ bản, khi bạn sửa đổi PK, tầng sẽ đi ra ngoài và cập nhật tất cả các FK tham chiếu đến nó. Điều này có thể được thực hiện trong CREATEtuyên bố của bạn , giống như khi bạn đang làm mộtCASCADE DELETE

Hãy theo dõi mọi thứ khi bạn làm điều này bởi vì, theo tôi hiểu, CASCADE thực sự chạy ở mức cô lập SERIALIZABLE(thông thường, SQL chạy READ COMMITTEDtheo mặc định) phía sau hậu trường để theo dõi mọi vấn đề chặn.

Thông tin bổ sung về các mức cô lập có thể được tìm thấy trong bài viết này: http://msdn.microsoft.com/en-us/l Library / ms173763.aspx


3

Xác định tất cả các khóa ngoại là CẬP NHẬT CASCADE

Nếu bạn chưa làm điều này, thì bạn sẽ phải

  1. Tạo một hàng mới với khóa chính mới
  2. Cập nhật tất cả các bảng con
  3. Xóa hàng cũ

.. trong một giao dịch tất nhiên và xem ra các ràng buộc khác có thể thất bại


cảm ơn @gbn. Có thể cập nhật khóa ngoại của tôi không hoặc tôi chỉ cần bỏ chúng và tạo lại chúng bằng mệnh đề ON CASCADE UPDATE?
mounaim

Thả và tái tạo ...
gbn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.