21

雅各布问了一个完美的问题:给我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

Marc 建议这someOtherTable是一个虚拟的占位符值 - 你没有那个表并不重要。

我试了一下,SQL Server确实抱怨

无效的对象名称“someOtherTable”。

这让我很难理解如果它不重要(除了实际上重要)USINGUSING foo什么。

当我使用 SQL Server 2008 MERGE 语法时USING使用foo时使用的是什么?


奖金问题

使用 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

不明确的

4

3 回答 3

17

合并具有表源和目标表。这引入了源表(不必是实际的物理表,只是一个结果集)。

您的问题中指出了语法。要从另一个表或视图合并,请使用

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); 
于 2012-06-26T21:35:56.183 回答
6

源表可以是任何东西,例如:

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);
于 2012-06-26T21:24:37.813 回答
3

继 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); 

在 SQL Server 2012 上对此进行了测试。(会将此添加为注释,但字符太多。)

我添加了一个 HOLDLOCK 已经看到,因为如果您使用 MERGE 进行 UPSERT 肯定是锁定,语法肯定不会更清晰。另请参阅 Marcel 对大型表的 ROWLOCK 的评论。

我发现另一篇帖子也比平均水平更清晰。

于 2014-10-16T09:12:53.460 回答