ジェイコブは完璧な質問をしました: MERGE
構文 を教えてください。
そこにあるすべての答えは、彼らが考えることができる最も複雑なケースにすぐにジャンプします。余分な混乱で構文を曖昧にします。
マークは 答え を与えました:
MERGE
member_topic AS target
USING
someOtherTable AS source
ON
target.mt_member = source.mt_member
AND source.mt_member = 0
AND source.mt_topic = 110
WHEN MATCHED THEN
UPDATE SET mt_notes = 'test'
WHEN NOT MATCHED THEN
INSERT (mt_member, mt_topic, mt_notes) VALUES (0, 110, 'test')
;
この答えを見て、私はジェイコブがそうであったのと同じくらい混乱しています:
SomeOtherTableがありません
マークは、someOtherTable
はダミーのプレースホルダー値であると提案しました。そのテーブルがなくてもかまいません。
試してみると、SQL Serverは文句を言います
無効なオブジェクト名 'someOtherTable'。
そのため、USING foo
のUSING
が重要でない場合(実際に重要な場合を除く)、forを理解するのに苦労します。
SQL Server 2008 MERGE構文を使用するときにfooを使用する場合、USING
は何を使用しますか?
MERGEを使用したUPSERT構文とは何ですか。
IF (rowExists)
UPDATE Users SET Firstname='Ian', LastName='Boyd' WHERE Username='iboyd'
ELSE
INSERT INTO Users (UserGUID, Username, FirstName, LastName, AuthenticationMethod)
VALUES ('{77410DC5-7A3E-4F1A-82C6-8EFB3068DE66}', 'iboyd', 'Ian', 'Boyd', 'Windows')
になる(私が試した正確なコード):
begin transaction
MERGE
Users
USING
foo
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 ('{77410DC5-7A3E-4F1A-82C6-8EFB3068DE66}', 'iboyd', 'Ian', 'Boyd', 'Windows')
; --A MERGE statement must be terminated by a semi-colon (;).
rollback
Msg 208, Level 16, State 1, Line 3
Invalid object name 'foo'.
?
列を含む
Users
テーブルの場合:UserGUID uniqueidentifier Username varchar(50) FirstName varchar(50) LastName varchar(50) AuthenticationMethod varchar(50)
更新:
USING <table_source>
table_source
は次のとおりです。
table_or_view_name [ [ AS ] table_alias ] [ <tablesample_clause> ]
[ WITH ( table_hint [ [ , ]...n ] ) ]
| rowset_function [ [ AS ] table_alias ]
[ ( bulk_column_alias [ ,...n ] ) ]
| user_defined_function [ [ AS ] table_alias ]
| OPENXML <openxml_clause>
| derived_table [ AS ] table_alias [ ( column_alias [ ,...n ] ) ]
| <joined_table>
| <pivoted_table>
| <unpivoted_table>
joined_table
は次のとおりです。
未定義
pivoted_table
は次のとおりです。
未定義
unpivoted_table
は次のとおりです。
未定義
マージには、テーブルソーステーブルとターゲットテーブルがあります。これにより、ソーステーブル(実際の物理テーブルである必要はなく、結果セットのみ)が導入されます。
文法はあなたの質問に示されています。別のテーブルまたはビューからマージするには、
MERGE
Users
USING SomeOtherTableName AS foo /*Alias is optional*/
ON /* ... */
または、たとえば <unpivoted_table>
を使用できます
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);
ボーナスの質問については、ここでVALUES
句をderived_table
オプションの一部として使用できます。
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);
ソーステーブルは、次のようなものにすることができます。
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');
明らかに、ネストされたソース選択では、さらに多くのことができます。ビュー、関数、テーブル変数、CTEからも選択します。
ボーナス質問については、あなた自身の質問に答えました。
場合によっては、非常に大きなテーブルの場合、ターゲットテーブルでROWLOCK
ヒントを使用して、少なくとも更新の場合にテーブル全体をロックしないようにします。
MERGE
member_topic WITH (ROWLOCK) AS target
ボーナスの質問が機能しないことに関連して、これが機能するサンプルです。もちろん、いくつかのオブジェクトの名前を変更しました。
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);
Martin Smithの回答に続いて、角かっこを繰り返し、コンマで区切るだけで、複数の明示的な値の行を一度にアップサートできます。
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);
これをSQLServer 2012でテストしました(コメントとして追加しましたが、文字数が多すぎます)。
this を見たHOLDLOCKを追加しました。これは、UPSERTにMERGEを使用している場合、ポイントが確実にロックされているため、構文が明確ではないためです。大きなテーブルについては、ROWLOCKに関するMarcelのコメントも参照してください。
別の投稿 私も平均よりもはっきりしていることがわかりました。