4

I'm trying to insert or update a single table using the MERGE command however I always get a "0 rows affected". My goal is simple: if exists update, otherwise insert. What am I doing wrong?

Note: the table's primary key is a combo key = [date]+sip+dip+port where date is datetime and all other fields are 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);
1
  • 4
    How can the target table be the source when you're aiming for a "when not matched"? What would that even mean? Commented May 29, 2012 at 7:45

2 Answers 2

20

I think you're wanting to insert a new value if there isn't currently one matching by date, sip, dip and port, but it's unclear what size you want in the UPDATE condition. I've picked 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

You'll note that the source doesn't reference the target table at all now.


Side note - I'd recommend avoiding SQL keywords such as date as column names.

Sign up to request clarification or add additional context in comments.

1 Comment

I'm planning to use this in a procedure like: InsertOrUpdate(DateTime.Date, sourceIP, DestIP, Port, PacketSize). So, if the respetive record exists it will increment the packet size, otherwise insert a new record with the values.
6

I guess you logic is wrong.

Your logic is:

if source is empty* then insert my row

*Source is empty when

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

returns 0 rows..

So in fact you're trying to merge target with empty source. It's logic error.

You should rather write something like this

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

UPDATE: Imagine how MERGE works: You have empty source and not empty target.

MERGE can have two sorts of WHEN NOT MATCHED clauses

First,

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

That means for every row in source without a pair at target you can do INSERT into target. So if you have empty source there is no occasion to do any INSERT.

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

Second,

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

That means for every row in target without a pair at source you can do UPDATE or DELETE on target. No possibility to do INSERT.

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

To make MERGE works for you, you need not empy source. Your source is SELECT with WHERE clause, so it may become an empty source. So you should make it non empty with some sort of coditional logic, use some temporary table or table varialble or tricky JOIN or UNION.. But in that way your code may become unreadable for you. Better drop idea of MERGE in that case at all and do classic conditional UPDATE or INSERT.

3 Comments

This is what I want to do but with MERGE command. Is this possible?
Of course you can do it with MERGE but at first you need not empty source like tabular variable, temporary table, common table expression - but still to fill your source table you need some sort of conditional logic. MERGE is very useful but it does not fit everywhere.
SELECT '20120101' as [date] , 1 as sip , 2 as dip , 80 as port will return one row..

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.