¿Cómo elimino todas las restricciones de todas las tablas?

30

Quiero eliminar todas las restricciones predeterminadas, verificar restricciones, restricciones únicas, claves principales y claves externas de todas las tablas en una base de datos de SQL Server. Sé cómo obtener todos los nombres de restricciones sys.objects, pero ¿cómo puedo completar la ALTER TABLEparte?

Aaron Bertrand
fuente
Solo por curiosidad, ¿cuál es el contexto de tal solicitud? Me pregunto cómo se abordan las dependencias funcionales (es decir, vistas indexadas, eventos en cascada en FK y UQ que tenían IGNORE_DUP_KEY = ON).
Solomon Rutzky
3
@srutzky Se solicitó en Stack Overflow, pero decidí crear una versión canónica más limpia aquí. De todos modos, es una solicitud común, a menudo parte de una tarea más grande de limpiar una base de datos (comenzar de nuevo, limpiar objetos que se colocaron por error en el maestro, etc.). No veo que estas dependencias funcionales se vean afectadas al eliminar las restricciones; de hecho, sospecho que en la mayoría de los casos, la imagen más grande también está truncando o eliminando las tablas. Dejar caer las restricciones primero lo permite.
Aaron Bertrand

Respuestas:

36

Puede derivar esta información fácilmente uniéndose sys.tables.object_id = sys.objects.parent_object_ida esos tipos de objeto.

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;

PRINTsolo está ahí para observar: si tiene muchas restricciones, es posible que no muestre todo el script porque está limitado a 8K. En esos casos, consulte este consejo para conocer otras formas de validar el script antes de ejecutarlo.

Una vez que esté satisfecho con la salida, descomente el EXEC.

Aaron Bertrand
fuente
3
También es posible que desee asegurarse de eliminar las restricciones de clave externa antes que las claves principales; ORDER BY (CASE WHEN c.[type] IN ('PK', 'UQ') THEN 1 ELSE 0 END)
Daniel Hutmacher
1
Buen punto de Daniel, el tipo ORDER BY probablemente sea suficiente hasta que SQL Server introduzca nuevos tipos de restricciones.
Aaron Bertrand
6

Comencé con la respuesta aceptada y modifiqué la estructura para usar un ciclo while en lugar de construir la declaración sql completa en sql dinámico. Esto me gusta más por varias razones.

La consulta no se almacena en la gran variable @sql. Esta implementación permite una impresión para cada restricción que se descarta para fines de registro en la salida. La ejecución pareció un poco más rápida en las pruebas de mi unidad.

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
fuente