我们经常会遇到“如果不存在,则插入”的情况。Dan Guzman 的博客对如何使此进程线程安全进行了出色的调查。
我有一个基本表,它只是将字符串从SEQUENCE
. 在存储过程中,我需要获取该值的整数键(如果它存在),或者INSERT
它然后获取结果值。该dbo.NameLookup.ItemName
列有一个唯一性约束,因此数据完整性没有风险,但我不想遇到异常。
这不是一个IDENTITY
所以我无法获得,SCOPE_IDENTITY
并且NULL
在某些情况下价值可能是。
在我的情况下,我只需要处理INSERT
桌面上的安全问题,所以我试图决定是否使用MERGE
这样的方法更好:
SET NOCOUNT, XACT_ABORT ON;
DECLARE @vValueId INT
DECLARE @inserted AS TABLE (Id INT NOT NULL)
MERGE
dbo.NameLookup WITH (HOLDLOCK) AS f
USING
(SELECT @vName AS val WHERE @vName IS NOT NULL AND LEN(@vName) > 0) AS new_item
ON f.ItemName= new_item.val
WHEN MATCHED THEN
UPDATE SET @vValueId = f.Id
WHEN NOT MATCHED BY TARGET THEN
INSERT …
Run Code Online (Sandbox Code Playgroud) 在表中Orders
,我存储了我们从所有商店收到的订单。由于一个订单可以有多个行,列中有OrderID
和OrderLineID
在那里OrderID
可以复制,但OrderLineID
必须是一个顺序中是唯一的。
由于订单可以修改,存储过程首先检查收到的订单OrderLineID
是否已经存在于表中,然后决定插入还是更新。为此,我们:
然后是主表:
IF NOT EXISTS (Select 1 from Orders where OrderLineID=@OrderLineID ......)
INSERT INTO Orders () VALUES ()
ELSE UPDATE Orders SET ... WHERE OrderLineID=@OrderLineID
Run Code Online (Sandbox Code Playgroud)
或者该MERGE
功能是否提供更好的性能/控制?
但问题如下:
由于线路问题/服务器繁忙等,Order
消息(或修改)可能会被多次发送,我们不知道按哪个顺序发送。因此,为了避免Order
修改后到达,从而覆盖修改,我们添加了一个时间列:
IF NOT EXISTS (Select 1 from Orders where OrderLineID=@OrderLineID)
INSERT INTO Orders () VALUES ()
ELSE UPDATE Orders SET ... WHERE OrderLineID=@OrderLineID AND LastModified<@CreatedTime
Run Code Online (Sandbox Code Playgroud)
这样,如果后一条消息比前一条消息旧,则对表没有影响。
但是,消息及其修改可能会在很短的时间内发送两次(或更多),以至于后一条消息在保存前一条消息之前到达。因此,对于存储过程的两次执行,它 …