C'est quelque chose qui me dérange à propos de MSSQL ( diatribe sur mon blog ). Je souhaite que MSSQL soit pris en charge upsert
.
Le code de @ Dillie-O est un bon moyen dans les anciennes versions de SQL (+1 vote), mais il s'agit toujours essentiellement de deux opérations d'E / S (le exists
puis le update
ou insert
)
Il existe un moyen légèrement meilleur sur ce post , en gros:
update tablename
set field1 = 'new value',
field2 = 'different value',
...
where idfield = 7
if @@rowcount = 0 and @@error = 0
insert into tablename
( idfield, field1, field2, ... )
values ( 7, 'value one', 'another value', ... )
Cela le réduit à une opération d'E / S s'il s'agit d'une mise à jour, ou à deux s'il s'agit d'une insertion.
MS Sql2008 introduit à merge
partir de la norme SQL: 2003:
merge tablename as target
using (values ('new value', 'different value'))
as source (field1, field2)
on target.idfield = 7
when matched then
update
set field1 = source.field1,
field2 = source.field2,
...
when not matched then
insert ( idfield, field1, field2, ... )
values ( 7, source.field1, source.field2, ... )
Maintenant, c'est vraiment juste une opération d'E / S, mais un code horrible :-(
MERGE
ne prend pas en charge laWHERE
clause, vous devez réécrire cela en utilisantUSING
etON
. De plus, sauf si vous ajoutezWITH (HOLDLOCK)
, il y a une course et desINSERT
s simultanés peuvent se produire, l'un d'entre eux échouant en raison du conflit de clé.La fonctionnalité que vous recherchez est traditionnellement appelée UPSERT. Au moins savoir comment cela s'appelle peut vous aider à trouver ce que vous recherchez.
Je ne pense pas que SQL Server 2005 ait d'excellents moyens de faire cela. 2008 introduit l'instruction MERGE qui peut être utilisée pour accomplir cela comme indiqué dans: http://www.databasejournal.com/features/mssql/article.php/3739131 ou http://blogs.conchango.com/davidportas/archive/ 2007/11/14 / SQL-Server-2008-MERGE.aspx
Merge était disponible dans la version bêta de 2005, mais ils l'ont supprimé dans la version finale.
la source
Ce que fait l'upsert / fusion est quelque chose à l'effet de ...
IF EXISTS (SELECT * FROM [Table] WHERE Id = X) UPDATE [Table] SET... ELSE INSERT INTO [Table]
J'espère donc que la combinaison de ces articles et de ce pseudo code pourra faire bouger les choses.
la source
J'ai écrit un article de blog sur ce problème.
L'essentiel est que si vous voulez des mises à jour bon marché et que vous voulez être sûr pour une utilisation simultanée, essayez:
update t set hitCount = hitCount + 1 where pk = @id if @@rowcount < 1 begin begin tran update t with (serializable) set hitCount = hitCount + 1 where pk = @id if @@rowcount = 0 begin insert t (pk, hitCount) values (@id,1) end commit tran end
De cette façon, vous avez 1 opération pour les mises à jour et un maximum de 3 opérations pour les insertions. Donc, si vous mettez généralement à jour, c'est une option sûre et bon marché.
Je ferais également très attention de ne pas utiliser quoi que ce soit qui n'est pas sûr pour une utilisation simultanée. Il est très facile d'obtenir des violations de clé primaire ou de dupliquer des lignes en production.
la source