【问题标题】: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 在哪里:

未定义

【问题讨论】:

标签: sql-server merge sql-server-2008-r2 upsert


【解决方案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 只是一个虚拟的占位符。
    猜你喜欢
    • 1970-01-01
    • 2011-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-17
    • 1970-01-01
    • 2011-01-29
    相关资源
    最近更新 更多