3

我正在尝试使用 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);
4

2 回答 2

18

date如果当前没有匹配的,和,我认为您想要插入一个新值sip,但目前尚不清楚您想要的条件大小。我选了1:dipportUPDATE

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

您会注意到源现在根本没有引用目标表。


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

于 2012-05-29T07:48:49.373 回答
7

我猜你的逻辑是错误的。

你的逻辑是:

if source is empty* then insert my row

*源为空时

SELECT '20120101' as [date] , 1 as sip , 2 as dip , 80 as port

返回 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

更新: 想象一下 MERGE 是如何工作的:你有空源而不是空目标。

MERGE可以有两种WHEN NOT MATCHED从句

第一的,

[ WHEN NOT MATCHED [ BY TARGET ] [ AND <clause_search_condition> ]
        THEN <merge_not_matched> ]

这意味着对于源中没有一对目标的每一行,您都可以插入目标。因此,如果您有空源,则没有机会做任何INSERT.

<merge_not_matched>::=
{
    INSERT [ ( column_list ) ] 
        { VALUES ( values_list )
        | DEFAULT VALUES }
}

第二,

[ WHEN NOT MATCHED BY SOURCE [ AND <clause_search_condition> ]
    THEN <merge_matched> ] [ ...n ]

这意味着对于目标中没有一对源的每一行,您可以在目标上执行 UPDATE 或 DELETE。不可能进行 INSERT。

<merge_matched>::=
    { UPDATE SET <set_clause> | DELETE }

要为您制作MERGE作品,您无需使用源代码。您的来源是SELECTwithWHERE子句,因此它可能成为一个空来源。因此,您应该使用某种代码逻辑使其非空,使用一些临时表或表变量或棘手的 JOIN 或 UNION .. 但这样您的代码可能对您来说变得不可读。最好在那种情况下完全放弃想法MERGE并做经典的条件UPDATEor INSERT

于 2012-05-29T08:23:04.130 回答