[英]Is there a way to insert a record in SQL server if it does not match the latest version of the record based on three of the columns?
考虑以下名为UserAttributes
表:
+----+--------+----------+-----------+
| Id | UserId | AttrName | AttrValue |
+----+--------+----------+-----------+
| 4 | 1 | FavFood | Apples |
| 3 | 2 | FavFood | Burgers |
| 2 | 1 | FavShape | Circle |
| 1 | 1 | FavFood | Chicken |
+----+--------+----------+-----------+
如果用户的特定属性的最新版本具有与最新版本不匹配的值,我想在此表中插入一条新记录。
我的意思是,例如,如果我要这样做: SELECT TOP(1) * FROM [UserAttributes] WHERE [UserId] = 1 AND [AttrName] = 'FavFood' ORDER BY [Id] DESC
我将能够看到用户 ID 1 当前最喜欢的食物是“苹果”。
是否有一个安全的并发查询,如果它与该用户当前最喜欢的食物不匹配,它只会插入一个新的最喜欢的食物?
我尝试将MERGE
查询与HOLDLOCK
一起使用,但问题是WHEN MATCHED
/ WHEN NOT MATCHED
,如果我不想在用户之前将他们最喜欢的食物(在本例中)设置为新值。 然而,它没有考虑到用户可能会切换到新的最喜欢的食物,然后又改回他们以前最喜欢的食物。 我想保留所有更改作为历史记录。
在上面的数据集中,如果用户 ID 1 的新喜欢的食物是“汉堡”,我想插入一条新记录,但如果他们新喜欢的食物是“苹果”,我不想插入记录(因为那是他们的目前最喜欢的食物)。 我还想让这个操作对于并发是安全的。
感谢您的帮助!
编辑:我可能还应该提到,当我将此操作拆分为两个查询时(即:首先选择他们当前最喜欢的食物,然后仅在检测到新食物时才执行插入查询)它在正常条件下工作。 但是,我们正在观察竞争条件(因此会出现重复),因为(您可能已经猜到)上面的数据集只是一个示例,并且有许多线程同时在该表上运行。
有点难看,但要在一个命令中完成,您可以插入用户(新的)最喜欢的食物,但使用他们当前值的EXCEPT进行过滤。
例如,(假设用户的新数据在@UserID、@FavFood
; WITH LatestFavFood AS
(SELECT TOP(1) UserID, AttrName, AttrValue
FROM [UserAttributes]
WHERE [UserId] = @UserID AND [AttrName] = 'FavFood'
ORDER BY [Id] DESC
)
INSERT INTO UserAttributes (UserID, AttrName, AttrValue)
SELECT @UserID, 'FavFood', @FavFood
EXCEPT
SELECT UserID, AttrName, AttrValue
FROM LatestFavFood
编辑:我已将上述更改为假设 AttrName 而不是 nvarchar 的 varchar 类型。 小提琴有混合物。 确保您正确理解它们会很好(尤其是食物,因为它可能具有特殊字符)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.