【发布时间】:2018-07-17 11:32:03
【问题描述】:
我使用存储过程来管理仓库。 PDA 扫描仪扫描添加的库存并将其批量(插入后)发送到 SQL 数据库 (SQL Server 2016)。
SQL 数据库相当偏远(其他国家/地区),因此某些查询有时会出现延迟,但这个特定的查询是有问题的:即使 stock 表没问题,我在 更新仓库地点。 PDA 将每个点中添加的项目作为 SMALLINT 进行跟踪,然后将此值发送回下面的存储过程。
PDA“send_spots”查询:
SELECT spot, added_items FROM spots WHERE change=1
存储过程:
CREATE PROCEDURE [dbo].[update_spots]
@spot VARCHAR(10),
@added_items SMALLINT
AS
BEGIN
BEGIN TRAN
UPDATE storage_spots
SET remaining_capacity = remaining_capacity - @added_items
WHERE storage_spot=@spot
IF @@ROWCOUNT <> 1
BEGIN
ROLLBACK TRAN
RETURN - 1
END
ELSE
BEGIN
COMMIT TRAN
RETURN 0
END
END
GO
如果remaining_capacity 的值为0,则PDA 无法在下一轮向其添加更多项目。但是在这个过程中,我得到了负值,因为据称查询运行了两次(因此减去了两次 @added_items)。
有没有办法做到这一点?我该如何解决?据我了解,如果受影响的行是!= 1,则事务应该被取消(回滚),但也许那是别的东西。
编辑:在@Zero 的帮助下的当前解决方案:
CREATE PROCEDURE [dbo].[update_spots]
@spot VARCHAR(10),
@added_racks SMALLINT
AS
BEGIN
-- Recover current capacity of the spot
DECLARE @orig_capacity SMALLINT
SELECT TOP 1
@orig_capacity = remaining_capacity
FROM storage_spots
WHERE storage_spot=@spot
-- Test if double is present in logs by comparing dates (last 10 seconds)
DECLARE @is_double BIT = 0
SELECT @is_double = CASE WHEN EXISTS(SELECT *
FROM spot_logs
WHERE log_timestamp >= dateadd(second, -10, getdate()) AND storage_spot=@spot AND delta=@added_racks)
THEN 1 ELSE 0 END
BEGIN
BEGIN TRAN
UPDATE storage_spots
SET remaining_capacity= @orig_capacity - @added_racks
WHERE storage_spot=@spot
IF @@ROWCOUNT <> 1 OR @is_double <> 0
-- If double, rollback UPDATE
ROLLBACK TRAN
ELSE
-- If no double, commit UPDATE
COMMIT TRAN
-- write log
INSERT INTO spot_logs
(storage_spot, former_capacity, new_capacity, delta, log_timestamp, double_detected)
VALUES
(@spot, @orig_capacity, @orig_capacity-@added_racks, @added_racks, getdate(), @is_double)
END
END
GO
【问题讨论】:
-
你应该检查调用这个过程的任何代码,因为这个过程看起来很好。要对其进行测试,请尝试直接运行此过程并查看它是否执行了两次(它应该只执行一次)。
-
您采取了哪些措施来确保传入的 added_items 不大于数据库中的剩余空间。 Remaining_space = 5,added_items 传入 = 10,这会将剩余空间更新为 -5,而 proc 不会运行两次。
-
如果您要实施审计表 - 即记录每个 UPDATE 的详细信息(值、日期时间、用户等),这将更容易诊断,因为它可能是如何使用系统的(并发更改例如)而不是数据库逻辑本身的问题。
-
Remaining_space = 5, added_items pass in = 10, remaining_space to -5 这种情况是不可能的,因为 PDA 应用程序确保您不能扫描超过剩余空间.有一种情况,两个(或多个)PDA 可以各自添加项目以溢出 remaining_space 值,但之前物理空间会被填满。
-
不能解决您当前的问题(您有两个单独的过程来读取和更新数据,并且没有事务来确保一致性),但我通常会将此建模为插槽具有固定的 容量,然后根据项目记录它们占用的插槽及其容量/容量使用情况。
remaining_capacity是从这两者中派生的数据。存储派生数据只是提供了不一致的机会(与其他数据、与现实等)
标签: sql-server stored-procedures