【发布时间】:2017-12-20 18:23:25
【问题描述】:
我有一个在 SQL Server 2008 上运行的程序。有一个创建新货件的功能。创建货件所需的最少数据是 idno、subno 和 class。主键是 idno + idsub。我创建了一个存储过程来创建一个新的货件,如下所示
ALTER Proc [dbo].[spDP_CreateNewShipment](@Class char(10),@idno int = 0, @idsub smallint = 1)
as
If @idno = 0
Begin
Select @idno = Max(idno)+1 From Shipment
End
Insert Into Shipment
(idno,idsub, class)
Values (@idno,@idsub,@class)
如果我将@idno 传递给0,它应该使用下一个可用的idno 创建一个货件。这很好用,只是有时两批新货物会得到相同的新 idno。似乎时间必须完全相同,以至于这几乎是不可能的,但它确实发生了。我能想到的唯一另一种可能性是插入可能会被缓冲并且可能不会立即发生。我对 SQL Server 设置知之甚少。有谁知道可能导致写入不会立即发生的设置?
【问题讨论】:
-
这是 identity 列的用途,您应该使用一个。正如您所观察到的,如果进程 1 在进程 2 读取 Max(idno) 但尚未插入之后读取 Max(idno),您将得到重复。
-
不要重新发明轮子。使用 IDENTITY 列。它将更简单、更快、更可靠、更容易维护、更难意外损坏等等……
-
@MatBailie Identity 不起作用,因为 idno 不是唯一的。主键是 idno + idsub。
-
如果您对您的结构进行更多解释,我可以保证 IDENTITY 列将起作用。您可能还需要一张表,但这本身就表明当前的设计存在缺陷(将尺寸和事实混为一谈就是一个可能的例子)。您完全尝试这样做确实是一种严重的代码气味。它应该被视为一个警告,您可能正在尝试解决另一个问题的症状,一个真正应该首先解决的问题。
-
你的意思是
12345,1和12345,2是同一批货,但是在一个流程中的位置不同?这应该意味着您有“真实的”shipment表,每批货物只有一行(idno作为标识列)。然后,shipment_sub表的状态会随时间发生变化。在您的情况下,您也许可以改用shipment_master和shipment。然后您的程序插入到shipment_master以获取新的idno? (如果您使用示例数据更新您的问题,那么我可以在答案中给出一个具体示例,考虑到对您现有系统的最小更改。)
标签: sql sql-server tsql