Aby wyłączyć ograniczenia klucza obcego:
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;
Aby ponownie włączyć:
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;
Nie będziesz jednak w stanie skrócić tabele, będziesz musiał usunąć z nich w odpowiedniej kolejności. Jeśli musisz skrócić je, musisz całkowicie usunąć ograniczenia i ponownie je utworzyć. Jest to proste, jeśli wszystkie ograniczenia klucza obcego są proste, jednokolumnowe, ale zdecydowanie bardziej złożone, jeśli zaangażowanych jest wiele kolumn.
Oto coś, czego możesz spróbować. Aby uczynić to częścią pakietu SSIS, potrzebujesz miejsca do przechowywania definicji FK podczas działania pakietu SSIS (nie będziesz w stanie zrobić tego wszystkiego w jednym skrypcie). Więc w jakiejś bazie danych narzędzi utwórz tabelę:
CREATE TABLE dbo.PostCommand(cmd NVARCHAR(MAX));
Następnie w swojej bazie danych możesz mieć procedurę składowaną, która to robi:
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
Teraz, gdy Twój pakiet SSIS jest gotowy, powinien wywołać inną procedurę składowaną, która:
DECLARE @sql NVARCHAR(MAX);
SELECT @sql = cmd FROM other_database.dbo.PostCommand;
EXEC sp_executesql @sql;
Jeśli robisz to wszystko tylko po to, aby móc obcinać zamiast usuwać, sugeruję po prostu wziąć trafienie i uruchomić usuwanie. Być może użyj modelu odzyskiwania z logowaniem zbiorczym, aby zminimalizować wpływ dziennika. Ogólnie nie widzę, jak to rozwiązanie będzie o wiele szybsze niż samo użycie usuwania we właściwej kolejności.
W 2014 opublikowałem bardziej rozbudowany post na ten temat tutaj:
- Upuść i ponownie utwórz wszystkie ograniczenia klucza obcego w SQL Server