Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Deaktivieren Sie vorübergehend alle Fremdschlüsseleinschränkungen

So deaktivieren Sie Fremdschlüsselbeschränkungen:

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;

Zum erneuten Aktivieren:

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;

Sie können jedoch nicht abschneiden die Tabellen, müssen Sie sie in der richtigen Reihenfolge löschen. Wenn Sie abschneiden müssen Sie müssen die Einschränkungen vollständig aufheben und neu erstellen. Dies ist einfach, wenn Ihre Fremdschlüsseleinschränkungen alle einfache, einspaltige Einschränkungen sind, aber definitiv komplexer, wenn mehrere Spalten beteiligt sind.

Hier ist etwas, das Sie ausprobieren können. Um dies zu einem Teil Ihres SSIS-Pakets zu machen, benötigen Sie einen Ort, an dem Sie die FK-Definitionen speichern können, während das SSIS-Paket ausgeführt wird (Sie können dies nicht alles in einem Skript tun). Erstellen Sie also in einer Hilfsdatenbank eine Tabelle:

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

Dann können Sie in Ihrer Datenbank eine gespeicherte Prozedur haben, die dies tut:

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

Wenn Ihr SSIS-Paket nun fertig ist, sollte es eine andere gespeicherte Prozedur aufrufen, die Folgendes tut:

DECLARE @sql NVARCHAR(MAX);

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

EXEC sp_executesql @sql;

Wenn Sie all dies nur tun, um abschneiden zu können, anstatt zu löschen, schlage ich vor, einfach den Treffer zu nehmen und einen Löschvorgang auszuführen. Verwenden Sie möglicherweise ein massenprotokolliertes Wiederherstellungsmodell, um die Auswirkungen des Protokolls zu minimieren. Im Allgemeinen sehe ich nicht, wie diese Lösung viel schneller sein wird, als nur eine Löschung in der richtigen Reihenfolge zu verwenden.

2014 habe ich hier einen ausführlicheren Beitrag dazu veröffentlicht:

  • Alle Fremdschlüsseleinschränkungen in SQL Server löschen und neu erstellen