I am trying to consolidate data in one table and merge it into another.
The data in the source destination table is as follows :
name |dob |city |occupation
-----------------------------------------------------------------------------------
galileo-galilei |1900-01-01 00:00:00.000 |rome |polymath
issac-newton |1900-01-01 00:00:00.000 |london |mathematician-scientist
leonardo-da-cinci |1900-01-03 00:00:00.000 |rome |polymath
The data in the destination source table is :
sl_no |name |dob |city |occupation
-----------------------------------------------------------------------------
1 |galileo-galilei |1900-01-01 00:00:00.000 | |
2 |galileo-galilei |1900-01-02 00:00:00.000 |venice |
3 |galileo-galilei |1900-01-05 00:00:00.000 | |astronomer
The expected result in the destination table is :
name |dob |city |occupation
-----------------------------------------------------------------------------------
galileo-galilei |1900-01-05 00:00:00.000 |venice |astronomer
issac-newton |1900-01-01 00:00:00.000 |london |mathematician-scientist
leonardo-da-cinci |1900-01-03 00:00:00.000 |rome |polymath
My attempts using update-with-join
and merge
have not been successful.
Update-With-Join :
-- updates data from the first match only
update p
set p.city = s.city,
p.occupation = s.occupation
from person_update_with_join_test_primary p, person_update_with_join_test_secondary s
where p.name = s.name ;
Merge :
-- https://technet.microsoft.com/en-us/library/bb522522(v=sql.105).aspx
/*
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.
*/
begin
merge person_update_with_join_test_primary as p
using person_update_with_join_test_secondary as s
on (p.name = s.name)
when not matched by target
then insert (name, dob, city, occupation)
values (s.name, s.dob, s.city, s.occupation)
when matched
then update set p.dob = s.dob
, p.city=(case when (len(s.city)>0) then s.city else p.city end)
, p.occupation=(case when (len(s.occupation)>0) then s.occupation else p.occupation end)
output $action, inserted.*, deleted.*;
end
I believe what I am looking for is similar to what has been posted here and here. However its not quite what I am looking for.
Are there any other ways to accomplish this other than using a cursor and an upsert (assuming that works)?
Update #1 :
Basically as long as the values in the source are not empty the most recent values (having highest id value) in the source are expected to be merged into the destination.
Eg : For #3 row in the source
, the city
column would not be considered to be merged into destination. Similarly for #2 , the occupation
column would not be considered for being merged into destination.
The the column name
is a primary-key in the destination
table.
I am trying to achieve the same state in the destination
table as would have been expected if I were to iterate over the source
data and update only the non-empty values in the destination
- by using a query instead of doing it through application.
dob
values, in 2 tables, for galilleo. 2 differentcity
values (rome, venice), 2 different occupations (polymath, astronomer. How the specific ones are be chosen?