Cascade pembaruan kunci utama untuk semua referensi kunci asing

11

Apakah mungkin untuk memperbarui nilai kolom kunci utama dengan mengalirkan pembaruan di antara semua kunci asing yang merujuknya?

# EDIT 1: Ketika saya menjalankan permintaan followinq

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

, Saya melihat bahwa update_referential_action diatur ke 0. Jadi TIDAK ADA TINDAKAN diambil setelah memperbarui kolom kunci utama saya. Bagaimana saya bisa memperbarui kunci asing untuk membuatnya PADA PEMBARUAN CASCADE ?

# EDIT 2:
Untuk membuat skrip pembuatan atau menjatuhkan semua kunci asing di skema Anda, jalankan skrip berikut (diambil dari sini )

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;  

Untuk menghasilkan skrip kunci asing DROP, ubah nilai @action agar sama dengan 'DROP' di klausa deklarasi:

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

Jawaban:

9

Jika Anda telah menetapkan batasan Kunci Asing, ON UPDATE CASCADEmaka nilai Kunci Utama yang diubah harus turun ke semua Kunci Asing dengan batasan itu.

Jika Anda tidak memiliki ON UPDATE CASCADEkendala, maka Anda perlu membuat skrip untuk menyelesaikan pembaruan.

EDIT: Karena Anda tidak memiliki ON UPDATE CASCADEkendala, tetapi Anda ingin mengaturnya, itu sedikit kerja. SQL Server tidak mendukung mengubah kendala ke pengaturan baru.

Penting untuk beralih melalui setiap tabel yang memiliki batasan FK ke tabel PK. Untuk setiap tabel dengan FK:

  1. ALTER TABLE untuk menjatuhkan batasan FK yang ada.
  2. ALTER TABLE lagi untuk membuat batasan ON UPDATE CASCADE untuk FK yang bersangkutan.

Ini membutuhkan sedikit usaha, tetapi akan menyebabkan kendala Anda diatur dengan benar untuk kasus Anda.

EDIT 2: Informasi yang Anda butuhkan terdapat di sys.foreign_keys. Anda dapat memilih dari tabel itu untuk mendapatkan semua informasi yang Anda butuhkan.

Pos dari John Paul Cook dapat ditemukan di sini:

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

Kode ini akan turun dan membuat SEMUA batasan FK dalam database. Anda harus dapat bekerja dari itu untuk membuat hanya perubahan yang Anda inginkan dalam database Anda.

RLF
sumber
lihat hasil edit saya untuk informasi lebih lanjut
mounaim
Apakah Anda tahu cara skrip semua kunci asing @RLF?
mounaim
@mounaim - Diperbarui dengan catatan tentang cara membuat skrip.
RLF
Saya sedang mengerjakan hal yang sama dan tautan yang sama melihat edit saya @RLF
mounaim
1
lebih baik untuk memasukkan blok kode di sini di DBA SE karena tautan ke situs web lain mungkin rusak nanti :)
mounaim
4

Kamu yakin bisa. ON UPDATE CASCADEadalah apa yang kamu cari.

Berikut ini cara kecil: http://sqlandme.com/2011/08/08/sql-server-how-to-cascade-updates-and-deletes-to-related-tables/

Pada dasarnya, ketika Anda memodifikasi PK, kaskade akan keluar dan memperbarui semua FK yang merujuknya. Ini dapat dilakukan dalam CREATEpernyataan Anda , sama seperti jika Anda melakukan aCASCADE DELETE

Mengawasi hal-hal ketika Anda melakukan ini karena, seperti yang saya mengerti, CASCADE benar-benar berjalan pada tingkat isolasi SERIALIZABLE(biasanya, SQL berjalan READ COMMITTEDsecara default) di belakang layar jadi perhatikan setiap masalah pemblokiran.

Info tambahan tentang tingkat isolasi dapat ditemukan dalam artikel ini: http://msdn.microsoft.com/en-us/library/ms173763.aspx

Kris Gruttemeyer
sumber
3

Tentukan semua kunci asing sebagai PEMBARUAN CASCADE

Jika Anda belum melakukan ini, maka Anda harus melakukannya

  1. Buat baris baru dengan kunci primer baru
  2. Perbarui semua tabel anak
  3. Hapus baris lama

.. dalam transaksi tentu saja dan mengawasi kendala lain yang bisa gagal

gbn
sumber
terima kasih @gbn. Apakah mungkin untuk memperbarui kunci asing saya atau saya hanya perlu menjatuhkannya dan membuatnya kembali dengan klausa UPDATE ON CASCADE?
mounaim
Jatuhkan dan
buat