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 <table_source>
@MartinSmith 确实我做到了。在 14 年 [[交易] 按照 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 /* ... */
或者您可以使用<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);
【讨论】:
这就是为什么 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 Server2008中的MERGE SQL语句中的MERGE的全称是什麼?代表什麼意思? 有没有