SQL SERVER 2014
I need to update two columns in TargetTable with values from SourceTable
SourceTbl
PersonNr | Block | BlockReason |
---------|----------|---------------|
000001 | 1 | abuse |
000001 | 1 | age |
000001 | 0 | memo |
000002 | 1 | age |
000002 | 0 | |
000003 | 0 | |
000003 | 0 | |
000004 | 1 | behaviour |
000005 | 0 | |
TargetTable
PersonNr | Block | BlockReason |
---------|----------|---------------|
000001 | 0 | |
000001 | 0 | |
000002 | 0 | |
000002 | 0 | |
000004 | 1 | |
000005 | 0 | |
Result needed:
PersonNr | Block | BlockReason |
---------|----------|---------------|
000001 | 1 | abuse |
000001 | 1 | abuse |
000002 | 1 | age |
000002 | 1 | age |
000004 | 1 | behaviour |
000005 | 0 | |
It is not relevant which BlockReason
Person 1 gets, as far as it's one from a row where Block
= '1'.
I've tried this pretty straight-forward update :
UPDATE
src
SET
src.Block = '1',
src.BlockReason = targ.BlockReason
FROM
SourceTbl src
INNER JOIN
TargetTable targ
ON
src.PersonNr= targ.PersonNr
WHERE src.Block = '1'
But ended up with faulty result-rows where Block and Reason are updated separately :
PersonNr | Block | BlockReason |
---------|----------|---------------|
000001 | 1 | memo |
Next I've tried :
MERGE INTO TargetTable AS TGT
USING
(
SELECT Block, BlockReason, PersonNr
FROM SourceTbl
GROUP BY Block, BlockReason, PersonNr
) AS SRC
ON
SRC.PersonNr= TGT.PersonNr AND
SRC.Block= '1'
WHEN MATCHED THEN
UPDATE SET TGT.Block= SRC.Block, TGT.BlockReason= SRC.BlockReason;
Got the error
The MERGE statement attempted to UPDATE or DELETE the same row more than once. This happens when a target row matches more than one source row. A MERGE statement cannot UPDATE/DELETE the same row of the target table multiple times. Refine the ON clause to ensure a target row matches at most one source row, or use the GROUP BY clause to group the source rows.
Any help? Hugely appreciated! Truly. Totally.
The problem with your query is that it gives duplicate values and it's trying to update the same record more than once.And the GROUP BY
in the subquery doesn't make any sense since you are not using any aggregate function.
Let's take an id(say 1) and check what's going wrong with your query.
src.PersonNr | src.Block | src.BlockReason | tgt.PersonNr | tgt.Block | tgt.BlockReason |
-------------|--------------|-------------------|--------------
000001 | 1 | abuse | 000001 | 0 | |
000001 | 1 | age | 000001 | 0 | |
000001 | 1 | abuse | 000001 | 0 | |
000001 | 1 | age | 000001 | 0 | |
Your query will give you the above result and try to update targettable 2 times for each record once with abuse and next with age.
You can try the below query:
MERGE INTO TargetTable AS TGT
USING
(
SELECT Block, BlockReason, PersonNr
FROM(
SELECT Block, BlockReason, PersonNr,ROW_NUMBER() OVER (PARTITION BY PersonNr ORDER BY [YourPrimaryKey]) RN
FROM SourceTbl ) X
WHERE X.RN=1
) AS SRC
ON
SRC.PersonNr= TGT.PersonNr AND
SRC.Block= '1'
WHEN MATCHED THEN
UPDATE SET TGT.Block= SRC.Block, TGT.BlockReason= SRC.BlockReason;
You have duplicates in your data. Add another (or more than one) column to the ON
clause of the MERGE
that will help identify exactly one record or find a way to remove duplicates before merging.
The UPDATE
should be something like this:
UPDATE
targ
SET
Block = '1',
BlockReason = src.BlockReason
FROM
SourceTbl src
INNER JOIN
TargetTable targ
ON
src.PersonNr= targ.PersonNr
WHERE src.Block = '1'
Since we're only using rows from SourceTbl
where Block
is 1
, it should not be possible for a row affected by this update to end up with a reason which had a Block
of 0
.
There is still the general issue that this is non-deterministic in cases where multiple rows from SourceTbl
are joined to one row in TargetTbl
, but since you've indicated that determinism isn't required here, it shouldn't result in a problem.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.