Como removo todas as restrições de todas as tabelas?

30

Desejo eliminar todas as restrições padrão, verificar restrições, restrições exclusivas, chaves primárias e chaves estrangeiras de todas as tabelas em um banco de dados do SQL Server. Sei como obter todos os nomes de restrições sys.objects, mas como preencho a ALTER TABLEpeça?

Aaron Bertrand
fonte
Por curiosidade, qual é o contexto de tal solicitação? Estou imaginando como as dependências funcionais são tratadas (ou seja, visualizações indexadas, eventos em cascata nos FKs e UQs que tiveram IGNORE_DUP_KEY = ON).
Solomon Rutzky
3
@srutzky Foi perguntado no Stack Overflow, mas eu decidi criar uma versão mais limpa e canônica aqui. De qualquer forma, é uma solicitação comum, geralmente parte de uma tarefa maior de limpar um banco de dados (reiniciar, limpar objetos que foram erroneamente colocados no mestre, etc.). Não vejo essas dependências funcionais sendo afetadas pela eliminação das restrições - na verdade, suspeito que, na maioria dos casos, a imagem maior esteja truncando ou descartando as tabelas também. A eliminação das restrições primeiro permite isso.
Aaron Bertrand

Respostas:

36

Você pode derivar essas informações facilmente ingressando sys.tables.object_id = sys.objects.parent_object_idnesses tipos de objetos.

DECLARE @sql NVARCHAR(MAX);
SET @sql = N'';

SELECT @sql = @sql + N'
  ALTER TABLE ' + QUOTENAME(s.name) + N'.'
  + QUOTENAME(t.name) + N' DROP CONSTRAINT '
  + QUOTENAME(c.name) + ';'
FROM sys.objects AS c
INNER JOIN sys.tables AS t
ON c.parent_object_id = t.[object_id]
INNER JOIN sys.schemas AS s 
ON t.[schema_id] = s.[schema_id]
WHERE c.[type] IN ('D','C','F','PK','UQ')
ORDER BY c.[type];

PRINT @sql;
--EXEC sys.sp_executesql @sql;

PRINTestá disponível apenas para observação - se você tiver muitas restrições, ele pode não mostrar o script inteiro porque está limitado a 8K. Nesses casos, consulte esta dica para outras maneiras de validar o script antes de executar.

Quando estiver satisfeito com a saída, remova o comentário do EXEC.

Aaron Bertrand
fonte
3
Você também pode querer eliminar restrições de chave estrangeira antes das chaves primárias; ORDER BY (CASE WHEN c.[type] IN ('PK', 'UQ') THEN 1 ELSE 0 END)
Daniel Hutmacher
11
@Daniel: bom ponto, o tipo ORDER BY provavelmente é suficiente até o SQL Server introduzir novos tipos de restrição.
Aaron Bertrand
6

Comecei com a resposta aceita e modifiquei a estrutura para usar um loop while, em vez de criar a instrução sql completa no sql dinâmico. Eu gosto mais disso por várias razões.

A consulta não é armazenada na variável @sql grande. Essa implementação permite uma impressão para cada restrição descartada para fins de registro na saída. A execução parecia um pouco mais rápida no meu teste de unidade.

Set NoCount ON

Declare @schemaName varchar(200)
set @schemaName=''
Declare @constraintName varchar(200)
set @constraintName=''
Declare @tableName varchar(200)
set @tableName=''

While exists
(   
    SELECT c.name
    FROM sys.objects AS c
    INNER JOIN sys.tables AS t
    ON c.parent_object_id = t.[object_id]
    INNER JOIN sys.schemas AS s 
    ON t.[schema_id] = s.[schema_id]
    WHERE c.[type] IN ('D','C','F','PK','UQ')
    and t.[name] NOT IN ('__RefactorLog', 'sysdiagrams')
    and c.name > @constraintName
)

Begin   
    -- First get the Constraint
    SELECT 
        @constraintName=min(c.name)
    FROM sys.objects AS c
    INNER JOIN sys.tables AS t
    ON c.parent_object_id = t.[object_id]
    INNER JOIN sys.schemas AS s 
    ON t.[schema_id] = s.[schema_id]
    WHERE c.[type] IN ('D','C','F','PK','UQ')
    and t.[name] NOT IN ('__RefactorLog', 'sysdiagrams')
    and c.name > @constraintName

    -- Then select the Table and Schema associated to the current constraint
    SELECT 
        @tableName = t.name,
        @schemaName = s.name
    FROM sys.objects AS c
    INNER JOIN sys.tables AS t
    ON c.parent_object_id = t.[object_id]
    INNER JOIN sys.schemas AS s 
    ON t.[schema_id] = s.[schema_id]
    WHERE c.name = @constraintName

    -- Then Print to the output and drop the constraint
    Print 'Dropping constraint ' + @constraintName + '...'
    Exec('ALTER TABLE [' + @schemaName + N'].[' + @tableName + N'] DROP CONSTRAINT [' + @constraintName + ']')
End

Set NoCount OFF
yourbuddypal
fonte