Reputation: 9610
I have the following table that links users with skills:
DECLARE @tbl_UsersSkills TABLE (
userId int NOT NULL,
skillId int NOT NULL,
UNIQUE NONCLUSTERED (userId, skillId)
);
INSERT INTO @tbl_UsersSkills
(userId, skillID)
VALUES
(100, 1),(100,2),(100,3),(100,4),(200,1),(200,3),(200,4);
This provides the following result set when selecting all rows:
userId skillId
----------- -----------
100 1
100 2
100 3
100 4
200 1
200 3
200 4
It has been decided that skill 1 is actually the same as skill 2, so we need to combine 1 & 2 together, leaving only 2.
I figured I could grab the skill 1 users, then delete them and re-insert them, but it seems like a fudge, and will increase the identity value (on the real table), and thought MERGE
was a more glamorous option.
I need to get to this result set:
userId skillId
----------- -----------
100 1 <-- removed because (100,2) exists already
100 2
100 3
100 4
200 1 <-- updated to be (200, 2)
200 3
200 4
Here's my attempt, but I get an error that the MERGE statement is modifying the same row multiple times.
Msg 8672, Level 16, State 1, Line 11 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.
Can anyone perfect it?
WITH cte AS (SELECT userId, skillId FROM @tbl_UsersSkills WHERE (skillId IN (@s1, @s2)))
MERGE
@tbl_UsersSkills tgt
USING
cte src
ON
(tgt.skillId = src.skillId)
WHEN NOT MATCHED BY TARGET THEN
INSERT (skillId) VALUES (@s2)
WHEN MATCHED THEN UPDATE SET
tgt.skillId = @s2;
Upvotes: 2
Views: 789
Reputation: 6018
My guess is this is probably not a common occurence. So if it works, it works. I think instead of using MERGE, you can just update the UserId's with only skill 1(not skill 2) to skill 2. Then delete any rows with skill 1.
DECLARE @tbl_UsersSkills TABLE (
userId int NOT NULL,
skillId int NOT NULL,
UNIQUE NONCLUSTERED (userId, skillId)
);
INSERT INTO @tbl_UsersSkills
(userId, skillID)
VALUES
(100, 1),(100,2),(100,3),(100,4),(200,1),(200,3),(200,4);
UPDATE @tbl_UsersSkills
SET skillID = 2
WHERE skillID = 1
AND userId NOT IN (SELECT DISTINCT userID FROM @tbl_UsersSkills WHERE skillId = 2)
DELETE
FROM @tbl_UsersSkills
WHERE skillId = 1
SELECT *
FROM @tbl_UsersSkills
Results:
userId skillId
----------- -----------
100 2
100 3
100 4
200 2
200 3
200 4
Upvotes: 1
Reputation: 7763
Try this two statement approach:
DELETE @tbl_UsersSkills
FROM @tbl_UsersSkills u1
WHERE u1.skillId = 1 and EXISTS
(SELECT * FROM @tbl_UsersSkills u2 WHERE u2.userId = u1.userId AND u2.skillId = 2)
UPDATE @tbl_UsersSkills
SET skillId = 2
WHERE skillId = 1
Upvotes: 1