Jacob asked the perfect question: give me the MERGE syntax.
Every answer out there immediately jumps to the most complicated case they can think of; obscuring the sy
Source table can be anything, such as:
MERGE
member_topic AS target
USING
(SELECT @Variable1, @Variable2, @Variable3) AS source(Col1, Col2, Col3)
ON
target.mt_member = source.Col1
AND source.Col1 = 0
AND source.Col2 = 110
WHEN MATCHED THEN
UPDATE SET mt_notes = 'test'
WHEN NOT MATCHED THEN
INSERT (mt_member, mt_topic, mt_notes) VALUES (0, 110, 'test');
Obviously, in the nested source select you can do many more things. Select from a view, a function, a table variable, a CTE even.
As for the bonus question, you answered your own question.
Sometimes,for very large tables, I also use the ROWLOCK
hint on the target table, to at least try not to lock the entire table in case of updates:
MERGE
member_topic WITH (ROWLOCK) AS target
Related to the bonus question not working, here's a working sample. I renamed some of the objects, of course.
DECLARE @Variable1 AS INT;
SET @Variable1 = 1234;
MERGE dbo.Table1 WITH(ROWLOCK) target
USING(SELECT @Variable1) source(Key)
ON target.[Key] = source.[Key]
WHEN MATCHED THEN
UPDATE SET
Col1 = @SomeVar1,
Col2 = @SomeVar2
WHEN NOT MATCHED THEN
INSERT
([Key]
,[Col1]
,[Col2])
VALUES
(@Variable1
,@SomeVar1
,@SomeVar2);
A merge has a table source and a target table. This introduces the source table (which need not be an actual physical table, just a result set).
The grammar is indicated in your question. To merge from another table or view use
MERGE
Users
USING SomeOtherTableName AS foo /*Alias is optional*/
ON /* ... */
Or you can use <unpivoted_table> for example
MERGE
Users
USING master..spt_values
UNPIVOT (X FOR Y IN ([high],[low])) AS foo
ON
Users.Username = foo.Y
WHEN MATCHED THEN
UPDATE SET FirstName = foo.Y
WHEN NOT MATCHED THEN
INSERT (UserGUID, Username, FirstName, LastName, AuthenticationMethod)
VALUES (foo.Y, foo.Y, foo.Y, foo.Y, foo.Y);
For your bonus question you can use the VALUES
clause here as part of the derived_table
option.
MERGE Users
USING (VALUES ('{77410DC5-7A3E-4F1A-82C6-8EFB3068DE66}',
'iboyd',
'Ian',
'Boyd',
'Windows')) AS foo(UserGUID, Username, FirstName, LastName, AuthenticationMethod)
ON Users.UserName = foo.UserName
WHEN MATCHED THEN
UPDATE SET Firstname = foo.FirstName,
Lastname = foo.LastName
WHEN NOT MATCHED THEN
INSERT (UserGUID,
Username,
FirstName,
LastName,
AuthenticationMethod)
VALUES (UserGUID,
Username,
FirstName,
LastName,
AuthenticationMethod);
Following on from Martin Smith's answer, you can upsert several explicit value rows at once simply by repeating the brackets, separating with a comma, eg,
MERGE Users WITH (HOLDLOCK)
USING (VALUES ('{77410DC5-7A3E-4F1A-82C6-8EFB3068DE66}',
'iboyd',
'Ian',
'Boyd',
'Windows'),
('{00000DC5-7A3E-4F1A-82C6-8EF452D2DE66}',
'jsmith',
'John',
'Smith',
'ActiveDirectory')) AS foo(UserGUID, Username, FirstName, LastName, AuthenticationMethod)
ON Users.UserName = foo.UserName
WHEN MATCHED THEN
UPDATE SET Firstname = foo.FirstName,
Lastname = foo.LastName
WHEN NOT MATCHED THEN
INSERT (UserGUID,
Username,
FirstName,
LastName,
AuthenticationMethod)
VALUES (UserGUID,
Username,
FirstName,
LastName,
AuthenticationMethod);
Tested this on SQL Server 2012. (Would have added this as a comment but too many characters.)
I added a HOLDLOCK having seen this, because if you're using MERGE for UPSERT surely the point is locking, the syntax is certainly no clearer. See also Marcel's comment on ROWLOCK for large tables.
There was another post I found clearer than average, too.