sql >> Base de Datos >  >> RDS >> Sqlserver

Deshabilitar temporalmente todas las restricciones de clave externa

Para deshabilitar las restricciones de clave externa:

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

;WITH x AS 
(
  SELECT DISTINCT obj = 
      QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.' 
    + QUOTENAME(OBJECT_NAME(parent_object_id)) 
  FROM sys.foreign_keys
)
SELECT @sql += N'ALTER TABLE ' + obj + ' NOCHECK CONSTRAINT ALL;
' FROM x;

EXEC sp_executesql @sql;

Para volver a habilitar:

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

;WITH x AS 
(
  SELECT DISTINCT obj = 
      QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.' 
    + QUOTENAME(OBJECT_NAME(parent_object_id)) 
  FROM sys.foreign_keys
)
SELECT @sql += N'ALTER TABLE ' + obj + ' WITH CHECK CHECK CONSTRAINT ALL;
' FROM x;

EXEC sp_executesql @sql;

Sin embargo, no podrá truncar las tablas, tendrá que eliminarlas en el orden correcto. Si necesita truncar ellos, debe eliminar las restricciones por completo y volver a crearlas. Esto es simple de hacer si sus restricciones de clave externa son todas simples, de una sola columna, pero definitivamente más complejas si hay varias columnas involucradas.

Aquí hay algo que puedes probar. Para que esto forme parte de su paquete SSIS, necesitará un lugar para almacenar las definiciones de FK mientras se ejecuta el paquete SSIS (no podrá hacer todo esto en un solo script). Entonces, en alguna base de datos de utilidad, cree una tabla:

CREATE TABLE dbo.PostCommand(cmd NVARCHAR(MAX));

Luego, en su base de datos, puede tener un procedimiento almacenado que haga esto:

DELETE other_database.dbo.PostCommand;

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

SELECT @sql += N'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id))
   + '.' + QUOTENAME(OBJECT_NAME(fk.parent_object_id)) 
   + ' ADD CONSTRAINT ' + fk.name + ' FOREIGN KEY (' 
   + STUFF((SELECT ',' + c.name
    FROM sys.columns AS c 
        INNER JOIN sys.foreign_key_columns AS fkc 
        ON fkc.parent_column_id = c.column_id
        AND fkc.parent_object_id = c.[object_id]
    WHERE fkc.constraint_object_id = fk.[object_id]
    ORDER BY fkc.constraint_column_id 
    FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '')
+ ') REFERENCES ' + 
QUOTENAME(OBJECT_SCHEMA_NAME(fk.referenced_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(fk.referenced_object_id))
+ '(' + 
STUFF((SELECT ',' + c.name
    FROM sys.columns AS c 
        INNER JOIN sys.foreign_key_columns AS fkc 
        ON fkc.referenced_column_id = c.column_id
        AND fkc.referenced_object_id = c.[object_id]
    WHERE fkc.constraint_object_id = fk.[object_id]
    ORDER BY fkc.constraint_column_id 
    FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '') + ');
' FROM sys.foreign_keys AS fk
WHERE OBJECTPROPERTY(parent_object_id, 'IsMsShipped') = 0;

INSERT other_database.dbo.PostCommand(cmd) SELECT @sql;

IF @@ROWCOUNT = 1
BEGIN
  SET @sql = N'';

  SELECT @sql += N'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id))
    + '.' + QUOTENAME(OBJECT_NAME(fk.parent_object_id)) 
    + ' DROP CONSTRAINT ' + fk.name + ';
  ' FROM sys.foreign_keys AS fk;

  EXEC sp_executesql @sql;
END

Ahora, cuando su paquete SSIS haya terminado, debería llamar a un procedimiento almacenado diferente, que hace lo siguiente:

DECLARE @sql NVARCHAR(MAX);

SELECT @sql = cmd FROM other_database.dbo.PostCommand;

EXEC sp_executesql @sql;

Si está haciendo todo esto solo por poder truncar en lugar de eliminar, le sugiero que simplemente tome el golpe y ejecute una eliminación. Tal vez use un modelo de recuperación de registro masivo para minimizar el impacto del registro. En general, no veo cómo esta solución será mucho más rápida que simplemente usar una eliminación en el orden correcto.

En 2014 publiqué un post más elaborado sobre esto aquí:

  • Eliminar y volver a crear todas las restricciones de clave externa en SQL Server