Sql server SQL Server中自动生成的重复编号
温柔点,我是SQL新手。我有一个名为autonumber\u settings的表,如下所示:Sql server SQL Server中自动生成的重复编号,sql-server,duplicates,Sql Server,Duplicates,温柔点,我是SQL新手。我有一个名为autonumber\u settings的表,如下所示: Prefix | AutoNumber SO | 112320 CA | 3542 A每当创建新的销售行时,都会调用一个存储过程,该存储过程从“SO”行读取当前自动编号值,然后递增编号,更新该行,然后从存储过程返回编号。存储过程如下所示: ALTER PROCEDURE [dbo].[GetAutoNumber] ( @type nvarchar(50) , @out
Prefix | AutoNumber
SO | 112320
CA | 3542
A每当创建新的销售行时,都会调用一个存储过程,该存储过程从“SO”行读取当前自动编号值,然后递增编号,更新该行,然后从存储过程返回编号。存储过程如下所示:
ALTER PROCEDURE [dbo].[GetAutoNumber]
(
@type nvarchar(50) ,
@out nvarchar(50) = '' OUTPUT
)
as
set nocount on
declare @currentvalue nvarchar(50)
declare @prefix nvarchar(10)
if exists (select * from autonumber_settings where lower(autonumber_type) = lower(@type))
begin
select @prefix = isnull(autonumber_prefix,''),@currentvalue=autonumber_currentvalue
from autonumber_settings
where lower(autonumber_type) = lower(@type)
set @currentvalue = @currentvalue + 1
update dbo.autonumber_settings set autonumber_currentvalue = @currentvalue where lower(autonumber_type) = lower(@type)
set @out = cast(@prefix as nvarchar(10)) + cast(@currentvalue as nvarchar(50))
select @out as value
end
else
select '' as value
现在,有另一个过程访问复制订单的同一个表,复制标题和行。有时,重复会导致重复的行号。以下是该程序的一部分:
BEGIN TRAN
IF exists
(
SELECT *
FROM autonumber_settings
WHERE autonumber_type = 'SalesOrderDetail'
)
BEGIN
SELECT
@prefix = ISNULL(autonumber_prefix,'')
,@current_value=CAST (autonumber_currentvalue AS INTEGER)
FROM autonumber_settings
WHERE autonumber_type = 'SalesOrderDetail'
SET @new_auto_number = @current_value + @number_of_lines
UPDATE dbo.autonumber_settings
SET autonumber_currentvalue = @new_auto_number
WHERE autonumber_type = 'SalesOrderDetail'
END
COMMIT TRAN
关于为什么这两个过程不能很好地结合在一起,偶尔会给出与通过复制创建的行相同的从零开始创建的行号的任何想法。这是一个竞赛条件或您的自动编号分配。在将新的执行写回数据库之前,两次执行可能会读取相同的值 解决此问题的最佳方法是使用标识列并让SQL server处理自动编号分配
除非您可以使用它来序列化对自动编号设置的访问。您可以在选择上使用可重复读取。这将锁定行并阻止另一个过程的select,直到更新值并提交为止
在每个select的from子句后插入WITH(REPEATABLEREAD,ROWLOCK)。我强烈建议使用标识列,这正是它们设计用来避免的。整个
select…/增加一个/UPDATE
周期不是并发安全的-多个进程可以获取相同的起始值,增加一个,然后写回新值。您需要(a)改用INT-IDENTITY
(保证并发安全),(b)等待SQL Server 2012获取SEQUENCE
对象,或(c)更改为单个UPDATE
语句,该语句不能由多个调用方多次执行。还有:为什么要将@currentvalue
定义为nvarchar(50)
变量??这不是一个数值吗??如果它是一个数字-声明它是一个数字!考虑到“自动编号”列中的数字始终是数字,我是否可以用该列作为标识重新生成表,并使用当前值进行种子设定?换句话说,存储过程中的代码是否必须更改?一个表上不能有多个标识列。由于程序的介绍,我认为这对你不起作用。您必须查看正在使用自动编号的表,看看它们是否具有标识列。