Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Solutions for INSERT OR UPDATE on SQL Server

Assume a table structure of MyTable(KEY, datafield1, datafield2...).

Often I want to either update an existing record, or insert a new record if it doesn't exist.

Essentially:

IF (key exists)   run update command ELSE   run insert command 

What's the best performing way to write this?

like image 459
Chris Cudmore Avatar asked Sep 20 '08 15:09

Chris Cudmore


People also ask

Can we use insert or update in SQL?

INSERT OR UPDATE table query inserts or updates rows of data the come from the result set of a SELECT query. The columns in the result set must match the columns in the table. You can use INSERT OR UPDATE with a SELECT to populate a table with existing data extracted from other tables.

Which SQL How can you insert?

INSERT INTO Syntax It is possible to write the INSERT INTO statement in two ways: 1. Specify both the column names and the values to be inserted: INSERT INTO table_name (column1, column2, column3, ...)

Which options can be used with insert statement in SQL?

You can use the INSERT statement to insert data into a table, partition, or view in two ways: conventional INSERT and direct-path INSERT . When you issue a conventional INSERT statement, Oracle Database reuses free space in the table into which you are inserting and maintains referential integrity constraints.


2 Answers

don't forget about transactions. Performance is good, but simple (IF EXISTS..) approach is very dangerous.
When multiple threads will try to perform Insert-or-update you can easily get primary key violation.

Solutions provided by @Beau Crawford & @Esteban show general idea but error-prone.

To avoid deadlocks and PK violations you can use something like this:

begin tran if exists (select * from table with (updlock,serializable) where key = @key) begin    update table set ...    where key = @key end else begin    insert into table (key, ...)    values (@key, ...) end commit tran 

or

begin tran    update table with (serializable) set ...    where key = @key     if @@rowcount = 0    begin       insert into table (key, ...) values (@key,..)    end commit tran 
like image 110
aku Avatar answered Sep 19 '22 17:09

aku


See my detailed answer to a very similar previous question

@Beau Crawford's is a good way in SQL 2005 and below, though if you're granting rep it should go to the first guy to SO it. The only problem is that for inserts it's still two IO operations.

MS Sql2008 introduces merge from the SQL:2003 standard:

merge tablename with(HOLDLOCK) 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, ... ) 

Now it's really just one IO operation, but awful code :-(

like image 43
Keith Avatar answered Sep 18 '22 17:09

Keith