Published on

February 10, 2020

Manipulando Restrições de Chave Estrangeira no SQL Server

As chaves estrangeiras (FK) são um componente essencial para manter a integridade referencial dentro de um banco de dados. Elas garantem que os relacionamentos de dados sejam mantidos e evitam registros órfãos. No entanto, quando se trata de fazer alterações na estrutura das tabelas ou modificar temporariamente os dados que podem violar as restrições de chave estrangeira, as FKs podem se tornar um desafio. Neste artigo, exploraremos a melhor abordagem para manipular restrições de chave estrangeira no SQL Server.

Antes de mergulharmos na solução, vamos recapitular rapidamente a importância das chaves estrangeiras e como identificá-las em seu banco de dados. As chaves estrangeiras estabelecem relacionamentos entre tabelas, referenciando a chave primária de outra tabela. Elas ajudam a manter a integridade dos dados e a garantir a consistência dos dados.

Para identificar todas as chaves estrangeiras em um banco de dados, você pode usar o seguinte script:

SELECT
    OBJECT_NAME(fk.parent_object_id) AS [Nome da Tabela],
    COL_NAME(fkc.parent_object_id, fkc.parent_column_id) AS [Nome da Coluna],
    OBJECT_NAME(fk.referenced_object_id) AS [Tabela Referenciada],
    COL_NAME(fkc.referenced_object_id, fkc.referenced_column_id) AS [Coluna Referenciada]
FROM
    sys.foreign_keys AS fk
INNER JOIN
    sys.foreign_key_columns AS fkc ON fk.object_id = fkc.constraint_object_id
ORDER BY
    [Nome da Tabela], [Nome da Coluna];

Agora, vamos passar para a solução para manipular restrições de chave estrangeira. O script abaixo demonstra como habilitar, desabilitar, excluir e recriar FKs com base em uma tabela de chave primária:

SET NOCOUNT ON

DECLARE @operation VARCHAR(10)
DECLARE @tableName sysname
DECLARE @schemaName sysname

SET @operation = 'DROP' -- ENABLE, DISABLE, DROP
SET @tableName = 'SpecialOfferProduct'
SET @schemaName = 'Sales'

DECLARE @cmd NVARCHAR(1000)

-- Cursor e consulta para buscar informações de FK
DECLARE cursor_fkeys CURSOR FOR
    SELECT
        Fk.name,
        Fk.OBJECT_ID,
        Fk.is_disabled,
        Fk.is_not_for_replication,
        Fk.delete_referential_action,
        Fk.update_referential_action,
        OBJECT_NAME(Fk.parent_object_id) AS Fk_table_name,
        SCHEMA_NAME(Fk.schema_id) AS Fk_table_schema,
        TbR.name AS Pk_table_name,
        SCHEMA_NAME(TbR.schema_id) AS Pk_table_schema
    FROM
        sys.foreign_keys Fk
    LEFT OUTER JOIN
        sys.tables TbR ON TbR.OBJECT_ID = Fk.referenced_object_id
    WHERE
        TbR.name = @tableName
        AND SCHEMA_NAME(TbR.schema_id) = @schemaName

OPEN cursor_fkeys

FETCH NEXT FROM cursor_fkeys INTO @FK_NAME, @FK_OBJECTID,
    @FK_DISABLED,
    @FK_NOT_FOR_REPLICATION,
    @DELETE_RULE,
    @UPDATE_RULE,
    @FKTABLE_NAME,
    @FKTABLE_OWNER,
    @PKTABLE_NAME,
    @PKTABLE_OWNER

WHILE @@FETCH_STATUS = 0
BEGIN
    -- Criar comando para habilitar FK
    IF @operation = 'ENABLE'
    BEGIN
        SET @cmd = 'ALTER TABLE [' + @FKTABLE_OWNER + '].[' + @FKTABLE_NAME
            + '] CHECK CONSTRAINT [' + @FK_NAME + ']'

        PRINT @cmd
    END

    -- Criar comando para desabilitar FK
    IF @operation = 'DISABLE'
    BEGIN
        SET @cmd = 'ALTER TABLE [' + @FKTABLE_OWNER + '].[' + @FKTABLE_NAME
            + '] NOCHECK CONSTRAINT [' + @FK_NAME + ']'

        PRINT @cmd
    END

    -- Criar comando para excluir e recriar FK
    IF @operation = 'DROP'
    BEGIN
        -- Comando de exclusão
        SET @cmd = 'ALTER TABLE [' + @FKTABLE_OWNER + '].[' + @FKTABLE_NAME
            + '] DROP CONSTRAINT [' + @FK_NAME + ']'

        PRINT @cmd

        -- Processo de recriação
        DECLARE @FKCOLUMNS VARCHAR(1000), @PKCOLUMNS VARCHAR(1000), @COUNTER INT

        -- Cursor para obter colunas FK
        DECLARE cursor_fkeyCols CURSOR FOR
            SELECT
                COL_NAME(Fk.parent_object_id, Fk_Cl.parent_column_id) AS Fk_col_name,
                COL_NAME(Fk.referenced_object_id, Fk_Cl.referenced_column_id) AS Pk_col_name
            FROM
                sys.foreign_keys Fk
            LEFT OUTER JOIN
                sys.tables TbR ON TbR.OBJECT_ID = Fk.referenced_object_id
            INNER JOIN
                sys.foreign_key_columns Fk_Cl ON Fk_Cl.constraint_object_id = Fk.OBJECT_ID
            WHERE
                TbR.name = @tableName
                AND SCHEMA_NAME(TbR.schema_id) = @schemaName
                AND Fk_Cl.constraint_object_id = @FK_OBJECTID
            ORDER BY
                Fk_Cl.constraint_column_id

        OPEN cursor_fkeyCols

        FETCH NEXT FROM cursor_fkeyCols INTO @FKCOLUMN_NAME, @PKCOLUMN_NAME

        SET @COUNTER = 1
        SET @FKCOLUMNS = ''
        SET @PKCOLUMNS = ''

        WHILE @@FETCH_STATUS = 0
        BEGIN
            IF @COUNTER > 1
            BEGIN
                SET @FKCOLUMNS = @FKCOLUMNS + ','
                SET @PKCOLUMNS = @PKCOLUMNS + ','
            END

            SET @FKCOLUMNS = @FKCOLUMNS + '[' + @FKCOLUMN_NAME + ']'
            SET @PKCOLUMNS = @PKCOLUMNS + '[' + @PKCOLUMN_NAME + ']'

            SET @COUNTER = @COUNTER + 1

            FETCH NEXT FROM cursor_fkeyCols INTO @FKCOLUMN_NAME, @PKCOLUMN_NAME
        END

        CLOSE cursor_fkeyCols
        DEALLOCATE cursor_fkeyCols

        -- Gerar comando de criação de FK
        SET @cmd = 'ALTER TABLE [' + @FKTABLE_OWNER + '].[' + @FKTABLE_NAME + '] WITH ' +
            CASE @FK_DISABLED
                WHEN 0 THEN 'CHECK'
                WHEN 1 THEN 'NOCHECK'
            END + ' ADD CONSTRAINT [' + @FK_NAME
            + '] FOREIGN KEY (' + @FKCOLUMNS
            + ') REFERENCES [' + @PKTABLE_OWNER + '].[' + @PKTABLE_NAME + '] ('
            + @PKCOLUMNS + ') ON UPDATE ' +
            CASE @UPDATE_RULE
                WHEN 0 THEN 'NO ACTION'
                WHEN 1 THEN 'CASCADE'
                WHEN 2 THEN 'SET_NULL'
            END + ' ON DELETE ' +
            CASE @DELETE_RULE
                WHEN 0 THEN 'NO ACTION'
                WHEN 1 THEN 'CASCADE'
                WHEN 2 THEN 'SET_NULL'
            END + '' +
            CASE @FK_NOT_FOR_REPLICATION
                WHEN 0 THEN ''
                WHEN 1 THEN ' NOT FOR REPLICATION'
            END

        PRINT @cmd
    END

    FETCH NEXT FROM cursor_fkeys INTO @FK_NAME, @FK_OBJECTID,
        @FK_DISABLED,
        @FK_NOT_FOR_REPLICATION,
        @DELETE_RULE,
        @UPDATE_RULE,
        @FKTABLE_NAME,
        @FKTABLE_OWNER,
        @PKTABLE_NAME,
        @PKTABLE_OWNER
END

CLOSE cursor_fkeys
DEALLOCATE cursor_fkeys

Ao modificar os valores das variáveis @operation, @tableName e @schemaName, você pode habilitar, desabilitar, excluir ou recriar restrições de chave estrangeira para uma tabela específica em um esquema específico.

Lembre-se de ter cuidado ao manipular restrições de chave estrangeira, pois quaisquer alterações podem afetar a integridade dos dados. Sempre teste seus scripts em um ambiente controlado antes de aplicá-los a um banco de dados de produção.

Isso é tudo! Agora você tem uma melhor compreensão de como manipular restrições de chave estrangeira no SQL Server. Usando o script fornecido, você pode facilmente habilitar, desabilitar, excluir ou recriar restrições de chave estrangeira com base em seus requisitos específicos.

Click to rate this post!
[Total: 0 Average: 0]

Let's work together

Send us a message or book free introductory meeting with us using button below.