Ini adalah sesuatu yang mengganggu saya tentang MSSQL ( kata-kata kasar di blog saya ). Saya berharap MSSQL didukung upsert
.
Kode @ Dillie-O adalah cara yang baik dalam versi SQL yang lebih lama (+1 suara), tetapi pada dasarnya masih dua operasi IO ( exists
dan kemudian update
atau insert
)
Ada cara yang sedikit lebih baik di posting ini , pada dasarnya:
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', ... )
Ini menguranginya menjadi satu operasi IO jika itu pembaruan, atau dua jika disisipkan.
MS Sql2008 memperkenalkan merge
dari standar 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, ... )
Sekarang ini benar-benar hanya satu operasi IO, tetapi kode yang mengerikan :-(
MERGE
tidak mendukungWHERE
klausa tersebut, Anda harus menulis ulang dengan menggunakanUSING
danON
. Selain itu, kecuali Anda menambahkanWITH (HOLDLOCK)
, ada balapan danINSERT
mungkin terjadi bersamaan , dengan salah satu dari mereka gagal karena benturan kunci.Fungsionalitas yang Anda cari biasanya disebut UPSERT. Setidaknya mengetahui apa namanya dapat membantu Anda menemukan apa yang Anda cari.
Saya tidak berpikir SQL Server 2005 memiliki cara yang bagus untuk melakukan ini. 2008 memperkenalkan pernyataan MERGE yang dapat digunakan untuk melakukannya seperti yang ditunjukkan di: http://www.databasejournal.com/features/mssql/article.php/3739131 atau http://blogs.conchango.com/davidportas/archive/ 2007/11/14 / SQL-Server-2008-MERGE.aspx
Merge tersedia dalam versi beta tahun 2005, tetapi mereka menghapusnya di rilis final.
sumber
Apa yang dilakukan upsert / merge adalah sesuatu yang mempengaruhi ...
IF EXISTS (SELECT * FROM [Table] WHERE Id = X) UPDATE [Table] SET... ELSE INSERT INTO [Table]
Jadi semoga kombinasi artikel-artikel itu dan pseudo code ini bisa menggerakkan semuanya.
sumber
Saya menulis posting blog tentang masalah ini.
Intinya adalah jika Anda menginginkan pembaruan murah dan ingin aman untuk penggunaan bersamaan, coba:
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
Dengan cara ini Anda memiliki 1 operasi untuk pembaruan dan maksimal 3 operasi untuk penyisipan. Jadi, jika Anda biasanya memperbarui, ini adalah opsi murah yang aman.
Saya juga akan sangat berhati-hati untuk tidak menggunakan apa pun yang tidak aman untuk penggunaan bersamaan. Sangat mudah untuk mendapatkan pelanggaran kunci primer atau baris duplikat dalam produksi.
sumber