J'ai écrit un proc stocké qui fera une mise à jour si un enregistrement existe, sinon il fera une insertion. Cela ressemble à quelque chose comme ceci:
update myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
insert into myTable (Col1, Col2) values (@col1, @col2)
Ma logique derrière l'écriture de cette manière est que la mise à jour effectuera une sélection implicite en utilisant la clause where et si cela renvoie 0, l'insertion aura lieu.
L'alternative à faire de cette façon serait de faire une sélection, puis en fonction du nombre de lignes renvoyées, faire une mise à jour ou une insertion. Cela a été jugé inefficace car si vous devez faire une mise à jour, cela entraînera 2 sélections (le premier appel de sélection explicite et le second implicite dans le lieu de la mise à jour). Si le proc faisait un insert, il n'y aurait aucune différence d'efficacité.
Ma logique est-elle valable ici? Est-ce ainsi que vous combineriez une insertion et une mise à jour dans un processus stocké?
Veuillez lire l' article sur mon blog pour un bon modèle sûr que vous pouvez utiliser. Il y a beaucoup de considérations et la réponse acceptée à cette question est loin d'être sûre.
Pour une réponse rapide, essayez le modèle suivant. Cela fonctionnera bien sur SQL 2000 et au-dessus. SQL 2005 vous donne une gestion des erreurs qui ouvre d'autres options et SQL 2008 vous donne une commande MERGE.
la source
S'il doit être utilisé avec SQL Server 2000/2005, le code d'origine doit être inclus dans la transaction pour s'assurer que les données restent cohérentes dans le scénario simultané.
Cela entraînera des coûts de performance supplémentaires, mais garantira l'intégrité des données.
Ajouter, comme déjà suggéré, MERGE doit être utilisé le cas échéant.
la source
MERGE est d'ailleurs l'une des nouvelles fonctionnalités de SQL Server 2008.
la source
Vous devez non seulement l'exécuter en transaction, mais également un niveau d'isolation élevé. En fait, le niveau d'isolement par défaut est Read Commited et ce code doit être sérialisable.
Peut-être que l'ajout de la vérification et de la restauration des erreurs @@ pourrait être une bonne idée.
la source
Si vous n'effectuez pas de fusion dans SQL 2008, vous devez le changer en:
si @@ rowcount = 0 et @@ error = 0
sinon, si la mise à jour échoue pour une raison quelconque, elle essaiera et une insertion par la suite car le nombre de lignes sur une instruction ayant échoué est 0
la source
Grand fan de l'UPSERT, réduit vraiment le code à gérer. Voici une autre façon de le faire: l'un des paramètres d'entrée est ID, si l'ID est NULL ou 0, vous savez que c'est un INSERT, sinon c'est une mise à jour. Suppose que l'application sait s'il y a un ID, donc ne fonctionnera pas dans toutes les situations, mais coupera les exécutions de moitié si vous le faites.
la source
Message de Dima Malenko modifié:
Vous pouvez intercepter l'erreur et envoyer l'enregistrement vers une table d'insertion ayant échoué.
J'avais besoin de le faire parce que nous prenons toutes les données envoyées via WSDL et si possible les réparons en interne.
la source
Votre logique semble saine, mais vous voudrez peut-être envisager d'ajouter du code pour empêcher l'insertion si vous avez passé une clé primaire spécifique.
Sinon, si vous effectuez toujours une insertion si la mise à jour n'a affecté aucun enregistrement, que se passe-t-il lorsque quelqu'un supprime l'enregistrement avant l'exécution de "UPSERT"? Maintenant, l'enregistrement que vous essayez de mettre à jour n'existe pas, il va donc créer un enregistrement à la place. Ce n'est probablement pas le comportement que vous recherchiez.
la source