Reputation: 543
I have a source table called STG
which needs to be "merged" with a target table called MAP
.
STG
ID1 HASH TIME
A 123 12:01AM
A 456 12:05AM
A 789 12:10AM
B 123 12:15AM
B 789 12:20AM
C 987 12:25AM
MAP
ID1 ID2 HASH TIME
A A 123 11:55PM
ID1
in MAP
can have the same column values as in STG
The value for ID2
is determined by the first time MAP
sees the ID1
and HASH
combination. For example, if row 4, B 123 12:15AM
, were to be inserted as a single row into MAP
it woudd look like B A 123 12:15AM
due to the fact that the HASH
value 123
was already in MAP
, so the existing value of A
ID2
is used.
Goal: "Merge" all the rows in STG
into MAP
with the appropriate ID2
value.
Cases:
ID1
Exists in MAP
, HASH
Exists in MAP
: UPDATE(MAP.TIME = STG.TIME)
ID1
DNE in MAP
, HASH
DNE in MAP
: INSERT(STG.ID1, STG.ID1, STG.HASH, STG.TIME)
ID1
Exists in MAP
, HASH
DNE in MAP
: INSERT(STG.ID1, MAP.ID2, STG.HASH, STG.TIME)
ID1
DNE in MAP
, HASH
Exists in MAP
: INSERT(STG.ID1, MAP.ID2, STG.HASH, STG.TIME)
The problem with tackling the problem in this manner is that some of the rows in STG
have dependencies on one another. For instance, I the SQL code to execute Case 2 is ran, the 5th row will be inserted as neither ID1
and HASH
exist in MAP
, but the 4th row has an association with MAP
via HASH
value 123
.
Cases 1 and 2, are straight forward and obvious. Solving for the Cases 3 and 4 while considering the dependencies has proved difficult.
How should Cases 3 and 4 be solved?
The (correct) end result should look like this...
MAP
ID1 ID2 HASH TIME
A A 123 12:01AM
A A 456 12:05AM
A A 789 12:10AM
B A 123 12:15AM
B A 789 12:20AM
C C 987 12:25AM
Upvotes: 0
Views: 358
Reputation: 13393
You can use this.
DECLARE @STG TABLE (ID1 VARCHAR(5), [HASH] INT, [TIME] TIME)
INSERT INTO @STG VALUES
('A',123,'12:01AM'),
('A',456,'12:05AM'),
('A',789,'12:10AM'),
('B',123,'12:15AM'),
('B',789,'12:20AM'),
('C',987,'12:25AM')
DECLARE @MAP TABLE (ID1 VARCHAR(5), ID2 VARCHAR(5), [HASH] INT, [TIME] TIME)
INSERT INTO @MAP
VALUES
('A','A',123,'11:55PM')
;MERGE @MAP AS tar
USING (
SELECT S.ID1, COALESCE(M.ID1, S.ID1) ID2 , S.HASH, S.TIME
FROM @STG S
LEFT JOIN @MAP M ON (S.HASH = M.HASH OR S.ID1 = M.ID1)
) AS src (ID1, ID2, [HASH], [TIME])
ON (tar.ID1 = src.ID1 AND tar.[HASH] = src.[HASH])
WHEN MATCHED THEN
UPDATE SET [TIME] = src.[TIME]
WHEN NOT MATCHED THEN
INSERT (ID1, ID2, [HASH], [TIME])
VALUES (src.ID1, src.ID2, src.[HASH], src.[TIME]) ;
Result:
ID1 ID2 HASH TIME
----- ----- ----------- ----------------
A A 123 00:01:00.0000000
A A 456 00:05:00.0000000
A A 789 00:10:00.0000000
B A 123 00:15:00.0000000
B B 789 00:20:00.0000000
C C 987 00:25:00.0000000
Upvotes: 1