SQL Server 2008 MERGE 语法中的 USING 是啥?

Posted

技术标签:

【中文标题】SQL Server 2008 MERGE 语法中的 USING 是啥?【英文标题】:What is USING in SQL Server 2008 MERGE syntax?SQL Server 2008 MERGE 语法中的 USING 是什么? 【发布时间】:2012-06-28 06:52:30 【问题描述】:

Jacob 提出了完美的问题:give me the MERGE syntax

那里的每个答案都会立即跳到他们能想到的最复杂的情​​况;用无关的混淆来掩盖语法。

马克给了an answer:

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”。

这让我很难理解USING foo 中的USING 是什么用于,如果它不重要(除了实际上很重要)。

当我使用 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 在哪里:

未定义

【问题讨论】:

你看语法了吗? USING &lt;table_source&gt; @MartinSmith 确实我做到了。在 14 年 [[交易] ::= 我从来没有 |曾经|能|到 [, ] 阅读 他们的文档 The various undefined parts of the grammar are here BTW 【参考方案1】:

按照 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 上对此进行了测试。(会将此作为注释添加,但字符太多。)

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

我也发现another post 比一般人更清晰。

【讨论】:

【参考方案2】:

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

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

MERGE 
   Users
USING SomeOtherTableName AS foo /*Alias is optional*/
ON /* ... */

或者您可以使用&lt;unpivoted_table&gt; 为例

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

【讨论】:

这就是为什么 using 子句不重要的原因 - 它不是不重要的。它至关重要。这解释了我对其他答案的困惑。【参考方案3】:

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

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

【讨论】:

也可以写成USING (VALUES (@Variable1, @Variable2, @Variable3)) AS source(Col1, Col2, Col3) 我的奖金问题不起作用; SQL Server 给出错误:Msg 208, Level 16, State 1, Line 3 Invalid object name 'foo'. @MartinSmith:不确定,但我会在第一次尝试。 @IanBoyd:你是如何使用它的?你能用完整的查询更新你的问题吗?还是一样? 用实际查询更新了问题。 SQL Server 是正确的:我有 no 对象,名为 foo。但是 foo 只是一个虚拟的占位符。

以上是关于SQL Server 2008 MERGE 语法中的 USING 是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Sql Server 2008 MERGE - 获取计数的最佳方式

在 SQL Server 2008 R2 的 MERGE 语句中更新插入的记录

SQL Server 2008 中的 MERGE 语句

SQL Server2008中的MERGE SQL语句中的MERGE的全称是什麼?代表什麼意思? 有没有

sql server 2008 merge matched判定条件

SQL Server 中单行 MERGE / upsert 的语法