考虑下表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
这是一个具有三个运行的DB_Fiddle。
编辑:我已经更改了上面,以假定AttrName而不是nvarchar的varchar类型。小提琴有混合物。确保您输入正确无误(尤其是食物,因为它可能具有特殊字符),这将是很好的。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句