使用具有相同源和目标表的SQL Server MERGE命令

mer*_*din 2 sql-server merge

我正在尝试使用MERGE命令插入或更新单个表,但是我总是得到"0行受影响".我的目标很简单:如果存在更新,否则插入.我究竟做错了什么?

注意:表的主键是组合键= [date] + sip + dip + port,其中date是datetime,所有其他字段都是int

merge iplog as t
using (SELECT * from iplog Where [date]='20120101' and sip=1 and dip=2 and port=80) as s
on t.[date]=s.[date] and t.sip=s.sip and t.dip=s.dip and t.port=s.port
when matched then
    update set t.size=t.size+s.size
when not matched then
    insert values ('20120101',1,2,80,1);
Run Code Online (Sandbox Code Playgroud)

Dam*_*ver 9

我想你想插入一个新的值,如果没有当前一个通过匹配date,sip,dipport,但你在想什么规模现在还不清楚UPDATE情况.我选了1:

create table iplog (
    [date] date not null,
    sip int not null,
    dip int not null,
    port int not null,
    size int not null
)
GO
merge iplog as t
using (SELECT '20120101' as [date] , 1 as sip , 2 as dip , 80 as port) as s
on t.[date]=s.[date] and t.sip=s.sip and t.dip=s.dip and t.port=s.port
when matched then
    update set t.size=t.size+1 --What should this be?
when not matched then
    insert values ('20120101',1,2,80,1);

select * from iplog
Run Code Online (Sandbox Code Playgroud)

您会注意到源根本不会引用目标表.


旁注 - 我建议避免使用SQL关键字,例如date列名.


huh*_*u78 6

我猜你的逻辑错了.

你的逻辑是:

if source is empty* then insert my row
Run Code Online (Sandbox Code Playgroud)

*来源是空的

SELECT '20120101' as [date] , 1 as sip , 2 as dip , 80 as port
Run Code Online (Sandbox Code Playgroud)

返回0行..

所以实际上你正在尝试将目标与空源合并.这是逻辑错误.

你应该写这样的东西

IF EXISTS(SELECT * from iplog Where [date]='20120101' and sip=1 and dip=2 and port=80)
BEGIN
 UPDATE
   iplog 
 SET 
   t.size=t.size+1
 WHERE
   [date]='20120101' and sip=1 and dip=2 and port=80
END
ELSE
BEGIN
  INSERT INTO iplog VALUES ('20120101',1,2,80,1)
END
Run Code Online (Sandbox Code Playgroud)

更新: 想象一下MERGE的工作原理:你有空源而不是空目标.

MERGE可以有两种WHEN NOT MATCHED条款

第一,

[ WHEN NOT MATCHED [ BY TARGET ] [ AND <clause_search_condition> ]
        THEN <merge_not_matched> ]
Run Code Online (Sandbox Code Playgroud)

这意味着对于源中没有成对的每一行,您可以执行INSERT到目标.所以,如果你有空源,就没有机会做任何事情INSERT.

<merge_not_matched>::=
{
    INSERT [ ( column_list ) ] 
        { VALUES ( values_list )
        | DEFAULT VALUES }
}
Run Code Online (Sandbox Code Playgroud)

第二,

[ WHEN NOT MATCHED BY SOURCE [ AND <clause_search_condition> ]
    THEN <merge_matched> ] [ ...n ]
Run Code Online (Sandbox Code Playgroud)

这意味着对于目标中没有成对的目标中的每一行,您可以在目标上执行UPDATE或DELETE.没有可能做INSERT.

<merge_matched>::=
    { UPDATE SET <set_clause> | DELETE }
Run Code Online (Sandbox Code Playgroud)

为了让MERGE你的工作,你不需要empy源.你的source是SELECTwith WHERE子句,所以它可能成为一个空源.因此,您应该使用某种编码逻辑将其设置为非空,使用一些临时表或表变量或棘手的JOIN或UNION ..但这样您的代码可能会变得不可读.MERGE在这种情况下更好地放弃想法并做经典条件UPDATEINSERT.