it-swarm.com.de

Deaktivieren Sie vorübergehend alle Fremdschlüsseleinschränkungen

Ich verwende ein SSIS-Paket, das Daten für einige Tabellen von FlatFiles in vorhandene Tabellen in einer Datenbank ersetzt.

Mein Paket schneidet die Tabellen ab und fügt die neuen Daten ein. Wenn ich mein SSIS-Paket ausführte, erhalte ich eine Ausnahme wegen der Fremdschlüssel.

Kann ich die Einschränkungen deaktivieren, den Import ausführen und sie dann wieder aktivieren?

41
HaBo

So deaktivieren Sie Fremdschlüsseleinschränkungen:

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;

So aktivieren Sie es erneut:

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;

Sie können die Tabellen jedoch nicht kürzen , sondern müssen sie in der richtigen Reihenfolge löschen. Wenn Sie sie kürzen müssen , müssen Sie die Einschränkungen vollständig löschen und neu erstellen. Dies ist einfach durchzuführen, wenn Ihre Fremdschlüsseleinschränkungen aus einfachen einspaltigen Einschränkungen bestehen, aber auf jeden Fall komplexer, wenn mehrere Spalten beteiligt sind.

Hier ist etwas, was Sie ausprobieren können. Um dies zu einem Teil Ihres SSIS-Pakets zu machen, benötigen Sie einen Speicherort für die FK-Definitionen, während das SSIS-Paket ausgeführt wird (dies kann nicht alles in einem Skript erfolgen). Erstellen Sie daher in einer Dienstprogrammdatenbank eine Tabelle:

CREATE TABLE dbo.PostCommand(cmd NVARCHAR(MAX));

Dann können Sie in Ihrer Datenbank eine gespeicherte Prozedur haben, die dies tut:

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

Wenn Ihr SSIS-Paket nun fertig ist, sollte es eine andere gespeicherte Prozedur aufrufen.

DECLARE @sql NVARCHAR(MAX);

SELECT @sql = cmd FROM other_database.dbo.PostCommand;

EXEC sp_executesql @sql;

Wenn Sie dies alles nur tun, um in der Lage zu sein, abzuschneiden, anstatt zu löschen, empfehle ich, nur den Treffer zu nehmen und einen Löschvorgang auszuführen. Verwenden Sie möglicherweise ein massenprotokolliertes Wiederherstellungsmodell, um die Auswirkungen des Protokolls zu minimieren. Im Allgemeinen sehe ich nicht, wie diese Lösung viel schneller sein wird, als nur ein Löschen in der richtigen Reihenfolge zu verwenden.

2014 habe ich hier einen ausführlicheren Beitrag dazu veröffentlicht:

79
Aaron Bertrand

Verwenden Sie die integrierte gespeicherte Prozedur sp_msforeachtable.

So deaktivieren Sie alle Einschränkungen:

EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT ALL";

So aktivieren Sie alle Einschränkungen:

EXEC sp_msforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL";

Alle Tabellen löschen:

EXEC sp_msforeachtable "DROP TABLE ?";
29
Ed Randall

Eine gute Referenz finden Sie unter: http://msdn.Microsoft.com/de-de/magazine/cc163442.aspx Unter dem Abschnitt "Deaktivieren aller Fremdschlüssel".

Inspiriert davon kann ein Ansatz erstellt werden, indem eine temporäre Tabelle erstellt und die Einschränkungen in diese Tabelle eingefügt wird. Anschließend werden die Einschränkungen gelöscht und anschließend aus der temporären Tabelle übernommen. Genug gesagt, hier rede ich

 SET NOCOUNT ON

    DECLARE @temptable TABLE(
       Id INT PRIMARY KEY IDENTITY(1, 1),
       FKConstraintName VARCHAR(255),
       FKConstraintTableSchema VARCHAR(255),
       FKConstraintTableName VARCHAR(255),
       FKConstraintColumnName VARCHAR(255),
       PKConstraintName VARCHAR(255),
       PKConstraintTableSchema VARCHAR(255),
       PKConstraintTableName VARCHAR(255),
       PKConstraintColumnName VARCHAR(255)    
    )

    INSERT INTO @temptable(FKConstraintName, FKConstraintTableSchema, FKConstraintTableName, FKConstraintColumnName)
    SELECT 
       KeyColumnUsage.CONSTRAINT_NAME, 
       KeyColumnUsage.TABLE_SCHEMA, 
       KeyColumnUsage.TABLE_NAME, 
       KeyColumnUsage.COLUMN_NAME 
    FROM 
       INFORMATION_SCHEMA.KEY_COLUMN_USAGE KeyColumnUsage
          INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TableConstraints
             ON KeyColumnUsage.CONSTRAINT_NAME = TableConstraints.CONSTRAINT_NAME
    WHERE
       TableConstraints.CONSTRAINT_TYPE = 'FOREIGN KEY'

    UPDATE @temptable SET
       PKConstraintName = UNIQUE_CONSTRAINT_NAME
    FROM 
       @temptable tt
          INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS ReferentialConstraint
             ON tt.FKConstraintName = ReferentialConstraint.CONSTRAINT_NAME

    UPDATE @temptable SET
       PKConstraintTableSchema  = TABLE_SCHEMA,
       PKConstraintTableName  = TABLE_NAME
    FROM @temptable tt
       INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TableConstraints
          ON tt.PKConstraintName = TableConstraints.CONSTRAINT_NAME

    UPDATE @temptable SET
       PKConstraintColumnName = COLUMN_NAME
    FROM @temptable tt
       INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KeyColumnUsage
          ON tt.PKConstraintName = KeyColumnUsage.CONSTRAINT_NAME


    --Now to drop constraint:
    SELECT
       '
       ALTER TABLE [' + FKConstraintTableSchema + '].[' + FKConstraintTableName + '] 
       DROP CONSTRAINT ' + FKConstraintName + '

       GO'
    FROM
       @temptable

    --Finally to add constraint:
    SELECT
       '
       ALTER TABLE [' + FKConstraintTableSchema + '].[' + FKConstraintTableName + '] 
       ADD CONSTRAINT ' + FKConstraintName + ' FOREIGN KEY(' + FKConstraintColumnName + ') REFERENCES [' + PKConstraintTableSchema + '].[' + PKConstraintTableName + '](' + PKConstraintColumnName + ')

       GO'
    FROM
       @temptable

    GO
3
NG.

Deaktivieren Sie alle Tabelleneinschränkungen

ALTER TABLE TableName NOCHECK CONSTRAINT ConstraintName

- Aktivieren Sie alle Tabelleneinschränkungen

ALTER TABLE TableName CHECK CONSTRAINT ConstraintName
2
Alam Usmani

Das Abschneiden der Tabelle ist nicht möglich, auch wenn Sie die Fremdschlüssel deaktivieren. Sie können mit dem Befehl Delete alle Datensätze aus der Tabelle entfernen. Beachten Sie jedoch, wenn Sie den Befehl delete Für eine Tabelle verwenden, die aus. Besteht Millionen von Datensätzen, dann wird Ihr Paket langsam Ihre Transaktionsprotokollgröße nimmt zu und es kann Ihren wertvollen Speicherplatz belegen.

Wenn Sie die Einschränkungen aufheben, kann es vorkommen, dass Sie Ihre Tabelle mit unreinen Daten füllen. Wenn Sie versuchen, die Einschränkungen neu zu erstellen, können Sie dies möglicherweise nicht zulassen, da dies zu Fehlern führt Wenn Sie die Einschränkungen löschen, laden Sie Daten, die korrekt miteinander in Beziehung stehen, und erfüllen die Abhängigkeitsbeziehungen, die Sie neu erstellen möchten.

Überlegen Sie sich also genau die Vor- und Nachteile jeder Methode und verwenden Sie sie entsprechend Ihren Anforderungen

1
vimal vasudevan

es müssen keine Abfragen für seitliche FKs auf SQL ausgeführt werden. Wenn Sie eine FK von Tabelle A bis B haben, sollten Sie:

  • daten aus Tabelle A löschen 
  • daten aus Tabelle B löschen
  • daten in B einfügen
  • daten in A einfügen

Sie können das Ziel auch anweisen, Einschränkungen nicht zu überprüfen

enter image description here

1
Diego

Falls Sie ein anderes Datenbankschema als ".dbo" verwenden oder Ihre Datenbank Pk´s enthält, die aus mehreren Feldern bestehen, verwenden Sie bitte nicht die Lösung von Carter Medlin, ansonsten beschädigen Sie Ihre Datenbank !!!

Wenn Sie mit verschiedenen Schemas arbeiten, versuchen Sie Folgendes (vergessen Sie nicht, vorher ein Backup Ihrer Datenbank zu erstellen!):

DECLARE @sql AS NVARCHAR(max)=''
select @sql = @sql +
    'ALTER INDEX ALL ON ' + SCHEMA_NAME( t.schema_id) +'.'+ '['+ t.[name] + '] DISABLE;'+CHAR(13)
from  
    sys.tables t
where type='u'

select @sql = @sql +
    'ALTER INDEX ' + i.[name] + ' ON ' + SCHEMA_NAME( t.schema_id) +'.'+'[' + t.[name] + '] REBUILD;'+CHAR(13)
from  
    sys.key_constraints i
join
    sys.tables t on i.parent_object_id=t.object_id
where     i.type='PK'

exec dbo.sp_executesql @sql;
go

Nach einigen Fk-freien Aktionen können Sie mit zurückschalten

DECLARE @sql AS NVARCHAR(max)=''
select @sql = @sql +
    'ALTER INDEX ALL ON ' + SCHEMA_NAME( t.schema_id) +'.'+'[' +  t.[name] + '] REBUILD;'+CHAR(13)
from  
    sys.tables t
where type='u'
print @sql

exec dbo.sp_executesql @sql;
exec sp_msforeachtable "ALTER TABLE ? WITH NOCHECK CHECK CONSTRAINT ALL";
0
olaf870