Comment supprimer toutes les contraintes de toutes les tables?

30

Je souhaite supprimer toutes les contraintes par défaut, vérifier les contraintes, les contraintes uniques, les clés primaires et les clés étrangères de toutes les tables d'une base de données SQL Server. Je sais comment obtenir tous les noms de contraintes sys.objects, mais comment remplir la ALTER TABLEpièce?

Aaron Bertrand
la source
Par curiosité, quel est le contexte d'une telle demande? Je me demande comment les dépendances fonctionnelles sont traitées (c'est-à-dire les vues indexées, les événements en cascade sur les FK et les UQ qui avaient IGNORE_DUP_KEY = ON).
Solomon Rutzky
3
@srutzky On l'a demandé sur Stack Overflow mais j'ai décidé de créer une version canonique plus propre ici. Quoi qu'il en soit, il s'agit d'une demande courante, qui fait souvent partie d'une tâche plus vaste de nettoyage d'une base de données (redémarrage, nettoyage d'objets qui ont été placés par erreur dans le maître, etc.). Je ne pense pas que ces dépendances fonctionnelles soient affectées par la suppression des contraintes - en fait, je soupçonne que dans la plupart des cas, l'image plus large tronque ou supprime également les tables. Supprimer les contraintes permet d'abord cela.
Aaron Bertrand

Réponses:

36

Vous pouvez facilement dériver ces informations en vous joignant sys.tables.object_id = sys.objects.parent_object_idà ces types d'objets.

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 juste là pour le globe oculaire - si vous avez beaucoup de contraintes, il peut ne pas afficher l'intégralité du script car il est limité à 8K. Dans ces cas, consultez cette astuce pour d'autres façons de valider le script avant de l'exécuter.

Une fois que vous êtes satisfait du résultat, décommentez le EXEC.

Aaron Bertrand
la source
3
Vous pouvez également vous assurer de supprimer les contraintes de clé étrangère avant les clés primaires; ORDER BY (CASE WHEN c.[type] IN ('PK', 'UQ') THEN 1 ELSE 0 END)
Daniel Hutmacher
1
@Daniel bon point, le type ORDER BY est probablement suffisant jusqu'à ce que SQL Server introduise de nouveaux types de contraintes.
Aaron Bertrand
6

J'ai commencé avec la réponse acceptée et modifié la structure pour utiliser une boucle while plutôt que pour construire l'instruction sql complète dans sql dynamique. J'aime mieux cela pour plusieurs raisons.

La requête n'est pas stockée dans la grande variable @sql. Cette implémentation permet une impression pour chaque contrainte supprimée à des fins de journalisation dans la sortie. L'exécution a semblé un peu plus rapide dans mes tests unitaires.

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
la source