เรียงซ้อนการอัปเดตคีย์หลักเป็นคีย์ต่างประเทศที่อ้างอิงทั้งหมด


11

เป็นไปได้หรือไม่ที่จะอัพเดตค่าคอลัมน์คีย์หลักที่มีการเรียงซ้อนการอัพเดตระหว่างคีย์ต่างประเทศทั้งหมดที่อ้างถึง?

# แก้ไข 1: เมื่อฉันเรียกใช้แบบสอบถาม followinq

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

ฉันเห็นว่า update_referential_action ตั้งเป็น 0 ดังนั้นจะไม่มีการดำเนินการใด ๆ หลังจากอัปเดตคอลัมน์คีย์หลักของฉัน ฉันจะอัปเดตคีย์ต่างประเทศเพื่อใช้เป็น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;  

หากต้องการสร้างสคริปต์ foreign key ของ DROP ให้แก้ไขค่า @action ให้เท่ากับ 'DROP' ในส่วนการประกาศ:

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

คำตอบ:


9

หากคุณได้กำหนดข้อ จำกัด ของคีย์ต่างประเทศON UPDATE CASCADEแล้วค่าคีย์หลักที่มีการเปลี่ยนแปลงควรเรียงซ้อนกับคีย์ต่างประเทศทั้งหมดที่มีข้อ จำกัด นั้น

หากคุณไม่มีON UPDATE CASCADEข้อ จำกัด คุณจะต้องสร้างสคริปต์เพื่อให้การอัปเดตเสร็จสมบูรณ์

แก้ไข: เนื่องจากคุณไม่มีON UPDATE CASCADEข้อ จำกัด แต่คุณต้องการมีการตั้งค่าดังกล่าวจึงเป็นงานเล็กน้อย SQL Server ไม่สนับสนุนการเปลี่ยนแปลงข้อ จำกัด เป็นการตั้งค่าใหม่

จำเป็นต้องทำซ้ำในแต่ละตารางที่มีข้อ จำกัด FK กับตาราง PK สำหรับแต่ละตารางด้วย FK:

  1. ALTER TABLE เพื่อวางข้อ จำกัด FK ที่มีอยู่
  2. เปลี่ยนตารางอีกครั้งเพื่อสร้างข้อ จำกัด แบบเรียงซ้อน UPDATE สำหรับ FK ที่เป็นปัญหา

สิ่งนี้ใช้ความพยายามเล็กน้อย แต่จะส่งผลให้ข้อ จำกัด ของคุณถูกตั้งค่าอย่างเหมาะสมสำหรับกรณีของคุณ

แก้ไข 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

คุณรู้วิธีการสคริปต์ต่างประเทศทั้งหมด @RLF หรือไม่?
mounaim

@mounaim - อัปเดตพร้อมหมายเหตุในการสร้างสคริปต์
RLF

ฉันทำงานในสิ่งเดียวกันและลิงก์เดียวกันดูการแก้ไข @RLF ของฉัน
mounaim

1
มันจะดีกว่าที่จะรวมถึงบล็อกรหัสที่นี่ใน DBA SE เพราะเชื่อมโยงไปยังเว็บไซต์อื่น ๆ ที่อาจทำลายภายหลัง :)
mounaim

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(ปกติแล้ว SQL จะทำงานREAD COMMITTEDโดยปริยาย) ที่อยู่ด้านหลังฉากเพื่อดูปัญหาการบล็อก

ข้อมูลเพิ่มเติมเกี่ยวกับระดับการแยกสามารถดูได้ในบทความนี้: http://msdn.microsoft.com/en-us/library/ms173763.aspx


3

กำหนดคีย์ต่างประเทศทั้งหมดเป็น CASCADE UPDATE

หากคุณยังไม่ได้ทำสิ่งนี้คุณจะต้องทำ

  1. สร้างแถวใหม่ด้วยคีย์หลักใหม่
  2. อัปเดตตารางลูกทั้งหมด
  3. ลบแถวเก่า

.. ในการทำธุรกรรมและระวังข้อ จำกัด อื่น ๆ ที่อาจล้มเหลว


ขอบคุณ @gbn เป็นไปได้หรือไม่ที่จะอัปเดตคีย์ต่างประเทศของฉันหรือฉันเพียงแค่วางและสร้างมันใหม่ด้วยคำสั่ง ON CASCADE UPDATE?
mounaim

ลบและสร้าง ...
GBN
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.