To jest coś, co mnie denerwuje w MSSQL ( rant na moim blogu ). Chciałbym, żeby obsługiwany był MSSQL upsert
.
Kod @ Dillie-O jest dobry w starszych wersjach SQL (+1 głos), ale nadal jest to w zasadzie dwie operacje IO ( exists
a następnie update
or insert
)
W tym poście jest nieco lepszy sposób :
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', ... )
Zmniejsza to do jednej operacji we / wy, jeśli jest to aktualizacja, lub dwóch, jeśli jest wstawiana.
MS Sql2008 wprowadza merge
ze standardu 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, ... )
Teraz to tylko jedna operacja IO, ale okropny kod :-(
MERGE
nie obsługujeWHERE
klauzuli, musisz to przepisać, używającUSING
iON
. Ponadto, jeśli nie dodaszWITH (HOLDLOCK)
, jest wyścig iINSERT
mogą się zdarzyć równoczesne s, a jeden z nich zawiedzie z powodu zderzenia kluczy.Funkcjonalność, której szukasz, jest tradycyjnie nazywana UPSERT. Przynajmniej wiedza o tym, jak to się nazywa, może pomóc Ci znaleźć to, czego szukasz.
Nie sądzę, aby SQL Server 2005 miał na to świetne sposoby. 2008 wprowadza oświadczenie MERGE, które można wykorzystać do osiągnięcia tego celu, jak pokazano na: http://www.databasejournal.com/features/mssql/article.php/3739131 lub http://blogs.conchango.com/davidportas/archive/ 2007/11/14 / SQL-Server-2008-MERGE.aspx
Merge było dostępne w wersji beta 2005, ale usunęli je w ostatecznej wersji.
źródło
To, co robi upsert / merge, ma wpływ na ...
IF EXISTS (SELECT * FROM [Table] WHERE Id = X) UPDATE [Table] SET... ELSE INSERT INTO [Table]
Miejmy nadzieję, że połączenie tych artykułów i tego pseudo kodu może ożywić sprawę.
źródło
Napisałem wpis na blogu dotyczący tego problemu.
Najważniejsze jest to, że jeśli chcesz tanie aktualizacje i chcesz być bezpieczny przy jednoczesnym użyciu, spróbuj:
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
W ten sposób masz 1 operację aktualizacji i maksymalnie 3 operacje wstawiania. Tak więc, jeśli generalnie aktualizujesz, jest to bezpieczna i tania opcja.
Byłbym również bardzo ostrożny, aby nie używać niczego, co jest niebezpieczne przy jednoczesnym użyciu. Uzyskanie naruszeń klucza podstawowego lub zduplikowanych wierszy w środowisku produkcyjnym jest naprawdę łatwe.
źródło