SQL Server: comment ignorer l'intégrité référentielle jusqu'à COMMIT?

J'ai un process pour déplacer des lignes d'une database à l'autre. En raison de certaines strings de reference de foreign keys circulaires, je ne peux pas supprimer les lignes de l'ancienne database, ni les insert dans la nouvelle database.

Puisque toute l'opération se passe dans une transaction 1 , je veux que SQL Server ignore les échecs d'intégrité référentielle jusqu'à ce que j'appelle COMMIT TRANSACTION .

Par exemple 2 :

  Table: Turboencabulators Table: Marselvanes ========================= ======================= PK TurboencabulatorID int /-> PK MarselvaneID int ^ MarselvanesID int --/ HasGrammeter bit | PantamesortingcFan varchar(50) +------------------------------- TurboencabulatorID int 

Si j'essaye d'insert le turboencabulator dans la nouvelle table, il échouera sans que le marselvane soit déjà là. Inverser la command a le même problème.

Lorsque je tente de supprimer les anciennes lignes, je ne peux pas en supprimer une jusqu'à ce que l'autre soit supprimée.

J'ai essayé de faire un système n- phase, où toutes les lignes sont insérées avec toutes les colonnes qui sont sous la contrainte de key étrangère définie sur null . Ensuite, je mets à jour toutes les lignes insérées, en plaçant les bonnes valeurs manquantes. Ensuite, afin de supprimer les lignes source, j'annule toutes les colonnes affectées par un FK , puis supprime les lignes réelles. 3

Ce que je préfèrerais vraiment, c'est de faire mes opérations T-SQL, et SQL Server ne me le dira pas jusqu'à ce que j'essaie d'appeler commit.

Remarques

1 dissortingbué
2 inventé hypothétique
3 que je ne fais plus

vous pouvez utiliser …

 ALTER TABLE whatever_table NOCHECK CONSTRAINT ALL 

pour supprimer la vérification des contraintes avant de commencer

et une fois terminé, rallumez-le avec …

 ALTER TABLE whatever_table CHECK CONSTRAINT ALL 

c'est ce que je ferais de toute façon.

-Don

Imaginez comment vous implémenteriez cela.

Si la résolution de key étrangère est différée jusqu'à la validation de la transaction, la validation doit effectuer toutes les opérations de search / vérification / cascade qui n'ont pas eu lieu au moment de l'insertion / suppression / mise à jour. Pensez à ce qu'une contrainte FK signifie réellement: votre plan d'exécution d'insertion est annoté avec une opération supplémentaire pour valider et appliquer la contrainte FK. Si vous reportez la contrainte, la logique supplémentaire dans le plan de requête devrait être détachée du moment d'exécution et poussée dans un context de transaction afin qu'elle soit exécutée au moment de la validation. Tout le brusque changement se transforme de la transaction de 'marque courte commited in log' en une opération qui fait tout ce qui a été ignoré pendant la transaction réelle. Le pire, c'est que la contrainte peut échouer, et penser comment une application pourrait gérer l'échec ? Avec une contrainte imposée au moment où l'insertion est exécutée, l'application peut intercepter l'erreur et prendre des mesures correctives: elle sait exactement ce qui a échoué. Mais si vous remettez cela à plus tard, vous essayez de vous engager et d'attraper une exception, maintenant vous devez d'une manière ou d'une autre, d'une manière ou d'une autre, comprendre ce qui a échoué. Pensez à quel point la vie des développeurs d'applications serait compliquée dans ce cas.

Une deuxième raison pour laquelle cela ne fonctionnerait pas est que vous n'avez toujours pas résolu le problème. Vous avez la table A avec la contrainte FK dans B. Vous commencez la transaction, insérez dans B, puis insérez dans A, puis supprimez de A, puis supprimez de B, puis validez. Toutes les opérations satisfaisaient le FK au moment où elles se sont produites, la database satisfait le FK au moment de la validation. Pourtant, si vous différez les vérifications de contraintes, elles échoueront au moment de la validation !!

Donc je dirais que l'intégrité référentielle fonctionne bien telle qu'elle est, mais elle est conçue pour une hiérarchie cascadine sans cycles. Autant de data structures CS et d'algorithms, il casse lorsque des cycles sont instruits. La meilleure solution serait d'parsingr le schéma et de voir si les cycles sont vraiment inévitables. Bref, insert NULL et mettre à jour post insert est la meilleure solution.

Malheureusement, la désactivation de la contrainte et l'activation de return sont un grand non-non: la réactivation devrait vérifier chaque ligne de la table pour vérifier la contrainte, et durera pour toujours. Dans le cas contraire, la contrainte est marquée comme «non approuvée» dans les métadonnées de la database et l'optimiseur l'ignorera (elle sera toujours appliquée, mais vous ne bénéficierez pas d'optimization du plan).