web-dev-qa-db-ja.com

SQL Server 2008 MERGE構文でのUSINGとは何ですか?

ジェイコブは完璧な質問をしました: 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 fooUSINGが重要でない場合(実際に重要な場合を除く)、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は次のとおりです。

未定義

21
Ian Boyd

マージには、テーブルソーステーブルとターゲットテーブルがあります。これにより、ソーステーブル(実際の物理テーブルである必要はなく、結果セットのみ)が導入されます。

文法はあなたの質問に示されています。別のテーブルまたはビューからマージするには、

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); 
17
Martin Smith

ソーステーブルは、次のようなものにすることができます。

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);
6
Marcel N.

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のコメントも参照してください。

別の投稿 私も平均よりもはっきりしていることがわかりました。

3
Chris