sql >> Databáze >  >> RDS >> Sqlserver

Dočasně deaktivujte všechna omezení cizího klíče

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


  1. Použijte SCOPE_IDENTITY() k vrácení naposledy vložené hodnoty identity ve stejném oboru (SQL Server)

  2. Jak mohu vypsat všechny cizí klíče odkazující na danou tabulku na serveru SQL?

  3. Zařízení Django selhalo a uvádí DatabaseError:hodnota je příliš dlouhá pro typový znak se liší (50)

  4. Automatické nebo pravidelné zálohování dat mysql