sql >> Databasteknik >  >> RDS >> Sqlserver

Inaktivera tillfälligt alla begränsningar för främmande nyckel

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


  1. Bevilja alla på ett specifikt schema i db till en grupproll i PostgreSQL

  2. Hämta datum/tid från en Unix-tidsstämpel i SQLite

  3. SQL GROUP BY CASE-sats med aggregatfunktion

  4. SQL Server Passthrough-fråga som grund för en DAO-postuppsättning i Access