【问题标题】:Using SQL Server MERGE command with same source & target table使用具有相同源表和目标表的 SQL Server MERGE 命令
【发布时间】:2012-06-03 10:10:45
【问题描述】:

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

注意:表的主键是一个组合键 = [日期]+sip+dip+port 其中日期是日期时间,所有其他字段都是 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);

【问题讨论】:

  • 当您的目标是“不匹配时”时,目标表如何成为源?这甚至意味着什么?

标签: sql-server merge


【解决方案1】:

如果datesipdipport 目前没有匹配的值,我认为您想要插入一个新值,但目前尚不清楚您想要在 @987654325 中的大小@ 健康)状况。我选择了 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

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


附注 - 我建议避免使用 SQL 关键字(例如 date)作为列名。

【讨论】:

  • 我打算在如下程序中使用它:InsertOrUpdate(DateTime.Date, sourceIP, DestIP, Port, PacketSize)。因此,如果存在相应记录,它将增加数据包大小,否则插入带有值的新记录。
【解决方案2】:

我猜你的逻辑是错误的。

你的逻辑是:

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 为您工作,您无需清空源代码。您的来源是带有WHERE 子句的SELECT,因此它可能成为一个空来源。因此,您应该使用某种代码逻辑使其非空,使用一些临时表或表变量或棘手的 JOIN 或 UNION .. 但这样您的代码可能对您来说变得不可读。在这种情况下,最好放弃MERGE 的想法,并使用经典的条件UPDATEINSERT

【讨论】:

  • 这就是我想要做的,但使用 MERGE 命令。这可能吗?
  • 当然你可以用 MERGE 来做,但首先你不需要像表格变量、临时表、公共表表达式那样清空源——但仍然要填充你的源表,你需要某种条件逻辑。 MERGE 非常有用,但并不适用于任何地方。
猜你喜欢
  • 1970-01-01
  • 2014-11-14
  • 2017-03-21
  • 2014-08-09
  • 2011-04-04
  • 2011-08-25
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
相关资源
最近更新 更多