Så här inaktiverar du begränsningar för främmande nyckel:
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;
För att återaktivera:
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;
Du kommer dock inte att kunna trunkera tabellerna måste du ta bort från dem i rätt ordning. Om du behöver trunkera dem måste du släppa begränsningarna helt och återskapa dem. Detta är enkelt att göra om dina främmande nyckelbegränsningar alla är enkla begränsningar med en kolumn, men definitivt mer komplex om det finns flera kolumner inblandade.
Här är något du kan prova. För att göra detta till en del av ditt SSIS-paket behöver du en plats för att lagra FK-definitionerna medan SSIS-paketet körs (du kommer inte att kunna göra allt detta i ett skript). Så i någon verktygsdatabas, skapa en tabell:
CREATE TABLE dbo.PostCommand(cmd NVARCHAR(MAX));
Sedan i din databas kan du ha en lagrad procedur som gör detta:
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
Nu när ditt SSIS-paket är klart bör det anropa en annan lagrad procedur, vilket gör:
DECLARE @sql NVARCHAR(MAX);
SELECT @sql = cmd FROM other_database.dbo.PostCommand;
EXEC sp_executesql @sql;
Om du gör allt detta bara för att kunna trunkera istället för att ta bort, föreslår jag att du bara tar träffen och kör en borttagning. Kanske använd bulkloggad återställningsmodell för att minimera effekten av loggen. Generellt sett ser jag inte hur den här lösningen ska gå så mycket snabbare än att bara använda en radering i rätt ordning.
2014 publicerade jag ett mer genomarbetat inlägg om detta här:
- Släpp och återskapa alla främmande nyckelbegränsningar i SQL Server