Kaskaden-Primärschlüsselaktualisierung für alle referenzierenden Fremdschlüssel

11

Ist es möglich, einen Primärschlüsselspaltenwert zu aktualisieren, indem die Aktualisierung auf alle Fremdschlüssel kaskadiert wird, die darauf verweisen?

# EDIT 1: Wenn ich followinq query ausführe

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

Ich sehe, dass update_referential_action auf 0 gesetzt ist. Daher wird nach dem Aktualisieren meiner Primärschlüsselspalten KEINE AKTION ausgeführt. Wie kann ich die Fremdschlüssel aktualisieren, um sie auf CASCADE UPDATE zu setzen ?

# BEARBEITEN 2:
Um das Erstellen oder Löschen aller Fremdschlüssel in Ihrem Schema per Skript auszuführen, führen Sie das folgende Skript aus (von hier aus ).

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;  

Um das DROP-Fremdschlüssel-Skript zu generieren, ändern Sie den @ action-Wert so, dass er in der Deklarationsklausel gleich 'DROP' ist:

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

Antworten:

9

Wenn Sie die Fremdschlüsseleinschränkungen als definiert haben ON UPDATE CASCADE, sollte der geänderte Primärschlüsselwert auf alle Fremdschlüssel mit dieser Einschränkung herunterkaskadieren.

Wenn Sie nicht über die ON UPDATE CASCADEEinschränkung verfügen , müssen Sie Skripts erstellen, um die Aktualisierung abzuschließen.

BEARBEITEN: Da Sie die ON UPDATE CASCADEEinschränkung nicht haben , diese aber einrichten möchten, ist dies ein wenig Arbeit. SQL Server unterstützt das Ändern der Einschränkungen in eine neue Einstellung nicht.

Es ist erforderlich, jede Tabelle zu durchlaufen, für die eine FK-Einschränkung für die PK-Tabelle gilt. Für jeden Tisch mit dem FK:

  1. ALTER TABLE, um die vorhandene FK-Einschränkung zu löschen.
  2. ALTER TABLE erneut, um die ON UPDATE CASCADE-Einschränkung für den betreffenden FK zu erstellen.

Dies erfordert ein wenig Aufwand, würde jedoch dazu führen, dass Ihre Einschränkung für Ihren Fall richtig festgelegt wird.

BEARBEITEN 2: Die benötigten Informationen finden Sie in sys.foreign_keys. Sie können aus dieser Tabelle auswählen, um alle benötigten Informationen zu erhalten.

Ein Beitrag von John Paul Cook ist hier zu finden:

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

Dieser Code löscht und erstellt ALLE FK-Einschränkungen in einer Datenbank. Sie sollten in der Lage sein, daraus zu arbeiten, um nur die gewünschten Änderungen in Ihrer Datenbank vorzunehmen.

RLF
quelle
Weitere Informationen finden Sie in meiner Bearbeitung
Montag,
Wissen Sie, wie man alle Fremdschlüssel @RLF schreibt?
Montag,
@mounaim - Aktualisiert mit einem Hinweis zum Erstellen des Skripts.
RLF
Ich habe an der gleichen Sache und dem gleichen Link gearbeitet, siehe meine Bearbeitung @RLF
mounaim
1
Es ist besser, Codeblöcke hier in DBA SE aufzunehmen, da Links zu anderen Websites möglicherweise später
unterbrochen werden
4

Sie können sicher. ON UPDATE CASCADEist das, wonach Sie suchen.

Hier ist eine kleine Anleitung: http://sqlandme.com/2011/08/08/sql-server-how-to-cascade-updates-and-deletes-to-related-tables/

Wenn Sie die PK ändern, erlischt im Grunde genommen die Kaskade und aktualisiert alle FKs, die darauf verweisen. Dies kann in Ihrer CREATEErklärung genauso geschehen , als ob Sie eineCASCADE DELETE

Behalten Sie die Dinge im Auge, wenn Sie dies tun, da CASCADE meines Wissens tatsächlich auf der Isolationsstufe SERIALIZABLE(normalerweise wird SQL READ COMMITTEDstandardmäßig ausgeführt) hinter den Kulissen ausgeführt wird. Achten Sie daher auf Blockierungsprobleme.

Weitere Informationen zu Isolationsstufen finden Sie in diesem Artikel: http://msdn.microsoft.com/en-us/library/ms173763.aspx

Kris Gruttemeyer
quelle
3

Definieren Sie alle Fremdschlüssel als CASCADE UPDATE

Wenn Sie dies nicht getan haben, müssen Sie

  1. Erstellen Sie eine neue Zeile mit neuem Primärschlüssel
  2. Aktualisieren Sie alle untergeordneten Tabellen
  3. Alte Reihe entfernen

.. in einer Transaktion natürlich und achten Sie auf andere Einschränkungen, die fehlschlagen könnten

gbn
quelle
danke @gbn. Ist es möglich, meine Fremdschlüssel zu aktualisieren, oder muss ich sie einfach löschen und mit der ON CASCADE UPDATE-Klausel neu erstellen?
Montag,
Löschen