모든 참조 외래 키에 대한 캐스케이드 기본 키 업데이트


11

참조하는 모든 외래 키 사이에서 업데이트를 연계하여 기본 키 열 값을 업데이트 할 수 있습니까?

# 편집 1 : followinq 쿼리를 실행할 때

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

, update_referential_action이 0으로 설정되어 있음을 알 수 있습니다. 따라서 기본 키 열을 업데이트 한 후 NO ACTION이 수행되지 않습니다. 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';

답변:


9

외래 키 제약 조건을 정의한 경우 ON UPDATE CASCADE변경된 기본 키 값은 해당 제약 조건이있는 모든 외래 키로 캐스케이드되어야합니다.

ON UPDATE CASCADE제한 조건 이없는 경우 업데이트를 완료하려면 스크립트를 작성해야합니다.

편집 : ON UPDATE CASCADE제약 조건은 없지만 설정을 원하기 때문에 약간의 작업이 필요합니다. SQL Server는 제약 조건을 새 설정으로 변경할 수 없습니다.

PK 테이블에 대한 FK 제한 조건이있는 각 테이블을 반복해야합니다. FK가있는 각 테이블의 경우 :

  1. 기존 FK 제약 조건을 삭제하려면 ALTER TABLE.
  2. 해당 FK에 대한 ON UPDATE CASCADE 제한 조건을 작성하려면 ALTER TABLE을 다시 수행하십시오.

이 작업에는 약간의 노력이 필요하지만 상황에 맞게 제약 조건이 올바르게 설정됩니다.

편집 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를 수정하면 캐스케이드가 나가고 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.