From: Mark Fitzgerald on
I had this a while ago. The Merge runs as a single transaction so cannot be
split ie some rows complete successfully while others not. I have to add
further checking into the merge statement. Below is a sql script that
describes our requirement. Duplicate keys were not a problem as we wanted
to update on duplicate, the problem came due to a balance figure not being
allowed to be negative. This was implemented as a check constraint.

Fitz


create database MergeOutput;
go

use MergeOutput;
go

create table Original(id int primary key,name varchar(30),value money)
go

insert into Original values (1,'M',100)
insert into Original values (2,'N',100)
insert into Original values (3,'O',100)
go
---------Add a constraint that will cause a problem later
alter table Original
add constraint NoNegativevalues
check(value > 0)

go

select * from Original
go

create table UpdateValues(id int,name varchar(30),value money)
go

insert into UpdateValues values (3,'O',-200)
insert into UpdateValues values (4,'P',100)
insert into UpdateValues values (5,'Q',-100)
go

/*
Try 1 : As merge statement is a transaction will complete
as a whole or rollback entirely
*/
declare @SuccessfullyChanged table (id int)
merge into Original O
using (select ID,Name,sum(value) as UpdateTotal
from UpdateValues
group by ID,Name) as U
on O.ID = U.ID
when matched then update set value = value + U.UpdateTotal
when not matched then insert values (U.ID,U.Name,U.UpdateTotal)
output inserted.ID into @SuccessfullyChanged;

select * from @SuccessfullyChanged
select * from Original
select * from UpdateValues
go

/*
Try 2 : Test the matched with AND clause to check no problems. This would
need to be
repeated on the not matched if necessary
*/

-- Using OUTPUT and Pre-calculated totals (if required)
declare @SuccessfullyChanged table (ID int)
declare @ComputedValue table (ID int,Name varchar(30),UpdateTotal money)

insert into @ComputedValue
select ID,Name,sum(value)
from UpdateValues
group by ID,Name

merge into Original O
using (select * from @ComputedValue) as U
on O.ID = U.ID
when matched and O.Value + U.UpdateTotal > 0 then update set value = value +
U.UpdateTotal
when not matched and U.UpdateTotal > 0 then insert values
(U.ID,U.Name,U.UpdateTotal)
output inserted.ID into @SuccessfullyChanged;

-- Result : successfully inserted or updated rows
select * from @SuccessfullyChanged

-- Result : unsuccessfully updated rows due to conflict
select ID from UpdateValues
EXCEPT
select ID from @SuccessfullyChanged

-- Result : Updated tables
select * from Original
select * from UpdateValues
go



"Andy B." <a_borka(a)sbcglobal.net> wrote in message
news:eESymVBzKHA.264(a)TK2MSFTNGP05.phx.gbl...
> What I mean is that if rows 1,3 and 5 failed to insert because of a unique
> key violation (or some other reason), I need to be able to identify those
> rows so they can be written to a log somewhere.
> "Uri Dimant" <urid(a)iscar.co.il> wrote in message
> news:uarf50AzKHA.1064(a)TK2MSFTNGP04.phx.gbl...
>> Andy
>> What do you by as what ones failed to insert.??? Will it generate an
>> error and terminate the whole batch?
>> See the below example from Adam Machanic to use a table variavle along
>> with output clause
>>
>> DECLARE @ChangedOrderDetail SalesOrderDetail_Type
>> DECLARE @SalesOrderID int
>>
>>
>> DECLARE @t TABLE (Changed int, ID int)
>>
>>
>>
>> INSERT INTO @t
>> SELECT Changed, SalesOrderDetailID
>> FROM (MERGE Sales.SalesOrderDetail OrderDetail
>> USING @ChangedOrderDetail Chng ON
>> Chng.[SalesOrderDetailID] = OrderDetail.[SalesOrderDetailID]
>>
>> AND Chng.[SalesOrderID] =
>> OrderDetail.[SalesOrderID]
>>
>>
>> WHEN MATCHED THEN
>> UPDATE SET [SalesOrderID] = CASE WHEN Chng.Rowversion =
>> OrderDetail.Rowversion
>> THEN Chng.SalesOrderID
>>
>> ELSE
>> OrderDetail.SalesOrderID
>>
>> END
>>
>> ,[CarrierTrackingNumber] = CASE WHEN Chng.Rowversion =
>> OrderDetail.Rowversion
>>
>> THEN
>> Chng.CarrierTrackingNumber
>>
>> ELSE
>> OrderDetail.CarrierTrackingNumber
>>
>> END
>>
>> OUTPUT CASE WHEN Chng.Rowversion = deleted.Rowversion THEN 1 ELSE 0
>> END Changed
>>
>> , Chng.SalesOrderDetailID) da
>>
>> WHERE CHanged = 0
>>
>>
>>
>> SELECT *
>>
>> FROM @t
>>
>>
>>
>>
>>
>> "Andy B." <a_borka(a)sbcglobal.net> wrote in message
>> news:uc3$vFAzKHA.1236(a)TK2MSFTNGP06.phx.gbl...
>>>I have to write code that needs to log down what rows were inserted as
>>>well as what ones failed to insert. I use a merge statement to
>>>insert/update/delete multiple rows at a time. How would I figure this
>>>out?
>>>
>>
>>
>
>