合并Upsert而不违反唯一约束

时间:2015-04-30 15:16:14

标签: sql-server tsql sql-server-2012

我有下表将用户与技能联系起来:

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);

在选择所有行时,它提供以下结果集:

userId      skillId
----------- -----------
100         1
100         2
100         3
100         4
200         1
200         3
200         4

已经确定技能1实际上与技能2相同,因此我们需要将1和1组合在一起。 2在一起,只留下2个。

我想我可以抓住1个用户的技能,然后删除它们并重新插入它们,但它似乎是一个软糖,并会增加身份值(在真实的桌子上),并认为MERGE是一个更迷人的选择。

我需要进入这个结果集:

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

这是我的尝试,但是我收到一条错误,即MERGE语句多次修改同一行。

  

Msg 8672,Level 16,State 1,Line 11 MERGE声明试图   多次更新或删除同一行。这发生在a   目标行匹配多个源行。 MERGE声明不能   多次更新/删除目标表的同一行。提炼   ON子句,以确保目标行最多匹配一个源行,   或使用GROUP BY子句对源行进行分组。

任何人都可以完善它吗?

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;

2 个答案:

答案 0 :(得分:1)

我猜这可能不是常见的事情。所以如果它有效,它就有效。我认为不是使用MERGE,而是只使用技能1(非技能2)将技能2更新为UserId,然后删除任何技能为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

结果:

userId      skillId
----------- -----------
100         2
100         3
100         4
200         2
200         3
200         4

答案 1 :(得分:1)

尝试这两种陈述方法:

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