I have a table test having columns id which primary key and auto incremented and name. I want to insert a new record if annd only if there are no records.For example
input is id=30122 and name =john
if there are records with id 30122 then I have update the name column to john,if there are no records then I have insert a new record.
I can do using 2 queries like
select * from test where id=30122
if it has some records then I can use update test set name='john' where id=3012
or if it does not have records then I can use
insert into test(name) values('john')
But I wanted to use single query?
Can somebody tell if its possible?
2 Answers 2
You can try this
IF EXISTS(select * from test where id=30122)
update test set name='john' where id=3012
ELSE
insert into test(name) values('john');
Other approach for better performance is
update test set name='john' where id=3012
IF @@ROWCOUNT=0
insert into test(name) values('john');
-
6The first example is wasteful and can often lead to deadlocks - I wouldn't suggest it at all.Aaron Bertrand– Aaron Bertrand2015年01月20日 14:48:03 +00:00Commented Jan 20, 2015 at 14:48
-
2@AaronBertrand care to elaborate? ThanksHexo– Hexo2017年08月21日 12:44:34 +00:00Commented Aug 21, 2017 at 12:44
-
11@SlapY Sure, in the first example, you are saying: "Hey, SQL Server, is there a row with this ID?" SQL Server goes off to find the row, perhaps using a scan, and then comes back with the answer. "Why, yes, user, I do have a row with that ID!" Then you say, "Okay, SQL Server, go find that row again, but this time, update it!" Do you see how performing the seek or scan twice is wasteful? Can you imagine what happens if another user asks SQL Server the same question about the existence of a row, before you've moved on to doing something about it?Aaron Bertrand– Aaron Bertrand2017年08月21日 13:25:44 +00:00Commented Aug 21, 2017 at 13:25
-
3Thanks, I just don't see why the first is threatend to deadlock while the second isnt? Both consist of multiple statements that can be intercepted if not run with full lock. Am I wrong?Hexo– Hexo2017年08月21日 13:30:24 +00:00Commented Aug 21, 2017 at 13:30
-
3@0x25b3 It isn't that one is threatened by deadlocks and the other isn't, it's that the first example is much more prone to them. You should be wrapping in a full and proper transaction in either case, but people don't, so...Aaron Bertrand– Aaron Bertrand2019年05月10日 18:55:05 +00:00Commented May 10, 2019 at 18:55
Assuming SQL Server 2008 or later, you could use MERGE
:
Table
CREATE TABLE dbo.Test
(
id integer NOT NULL,
name varchar(30) NULL,
CONSTRAINT PK_dbo_Test__id
PRIMARY KEY CLUSTERED (id)
);
Query
MERGE dbo.Test WITH (SERIALIZABLE) AS T
USING (VALUES (3012, 'john')) AS U (id, name)
ON U.id = T.id
WHEN MATCHED THEN
UPDATE SET T.name = U.name
WHEN NOT MATCHED THEN
INSERT (id, name)
VALUES (U.id, U.name);
The SERIALIZABLE
hint is required for correct operation under high concurrency.
You can find a comparisons of the common methods by Michael J. Swart here:
-
8Merge has some issues.vonPryz– vonPryz2015年01月20日 14:00:18 +00:00Commented Jan 20, 2015 at 14:00
-
the mythbusting link there is excellent. Nice one!JonnyRaa– JonnyRaa2019年11月20日 16:15:05 +00:00Commented Nov 20, 2019 at 16:15
But I wanted to use single query?
Why?MERGE
in any version, even SQL Server 2019. Some background on that here.ON DUPLICATE KEY UPDATE
.