Chcete-li zakázat omezení cizího klíče:
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;
Opětovná aktivace:
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;
Nebudete však moci zkrátit tabulky, budete z nich muset mazat ve správném pořadí. Pokud potřebujete zkrátit musíte omezení úplně zrušit a znovu je vytvořit. To je jednoduché, pokud jsou vaše omezení cizího klíče jednoduchá, omezení s jedním sloupcem, ale rozhodně složitější, pokud se jedná o více sloupců.
Zde je něco, co můžete vyzkoušet. Aby se to stalo součástí vašeho balíčku SSIS, budete potřebovat místo pro uložení definic FK, zatímco balíček SSIS běží (nebudete to moci udělat vše v jednom skriptu). Takže v nějaké databázi nástrojů vytvořte tabulku:
CREATE TABLE dbo.PostCommand(cmd NVARCHAR(MAX));
V databázi pak můžete mít uloženou proceduru, která dělá toto:
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
Nyní, když je váš balíček SSIS hotový, měl by volat jinou uloženou proceduru, což dělá:
DECLARE @sql NVARCHAR(MAX);
SELECT @sql = cmd FROM other_database.dbo.PostCommand;
EXEC sp_executesql @sql;
Pokud to všechno děláte jen proto, abyste mohli místo mazání zkrátit, doporučuji prostě vzít zásah a spustit mazání. Možná použijte hromadně protokolovaný model obnovy, abyste minimalizovali dopad protokolu. Obecně nechápu, jak bude toto řešení o tolik rychlejší než pouhé použití mazání ve správném pořadí.
V roce 2014 jsem o tom zveřejnil podrobnější příspěvek zde:
- Zrušte a znovu vytvořte všechna omezení cizích klíčů v SQL Server