我将职位存储在SQL Server 2012数据库中,其中每个职位由职位编号和公司编号定义。
位置编号仅适用于每家公司。
例如,我的数据库可能有以下内容
POSITION_NO COMPANY_NO
1 1
2 1
3 1
1 2
2 2
3 2
1 3
我需要一个以公司编号作为参数的函数,并返回下一个连续的位置编号,在上面的示例表中,对于COMPANY_NO = 3,该编号为2
我目前使用的是:
CREATE PROCEDURE [DB].[GenerateKey]
@p_company_no float(53),
@return_value_argument float(53) OUTPUT
AS
BEGIN
DECLARE
@v_position_no numeric(5, 0)
SELECT @v_position_no = max(POSITION_NO) + 1
FROM DB.POSITION_TABLE with (nolock)
WHERE COMPANY_NO = @p_company_no
SET @return_value_argument = @v_position_no
RETURN
END
我知道使用with(nolock)可能存在的缺陷,但这是为了防止数据库数据锁定失败而添加的。事实上,除了编写良好的代码显然更可取之外,我提出这个问题的主要原因是试图减少可能导致数据锁定的位置数量。
我的代码有什么方法可以改进吗?
答案 0 :(得分:2)
创建一个包含序列的辅助表,每个公司都有一行(正如您已经做过的那样):
create table seq (company int, sequence int);
go
种子柜台,每个公司一个(比如有两家公司,1和2):
insert seq values
(1, 1), (2, 1);
go
然后,您只需要在单个语句中更新和选择新值,以避免竞争条件。这是怎么做的:
declare @next int;
declare @company int;
set @company = 2;
update seq
set @next = sequence = sequence + 1
where company = @company;
select @next
将它封装到标量函数中会很好,但不幸的是,不允许更新函数。但是您已经有了存储过程,所以只需修改其中的代码即可。
请告诉我使用的数据类型不是真正的浮点数吗?为什么不注明?
答案 1 :(得分:0)
WHILE(1=1)
BEGIN
SELECT @v_position_no = max(POSITION_NO)
FROM DB.POSITION_TABLE with (nolock)
WHERE COMPANY_NO = @p_company_no
INSERT INTO DB.POSITION_TABLE
(COMPANY_NO, POSITION_NO)
SELECT TOP 1 @p_company_no, @v_position_no + 1
FROM DB.POSITION_TABLE with (nolock)
WHERE NOT EXISTS (SELECT 1
FROM DB.POSITION_TABLE with (nolock)
WHERE COMPANY_NO = @p_company_no
AND POSITION_NO = @v_position_no + 1)
IF(@@ROWCOUNT > 0)
BREAK;
END
SET @return_value_argument = @v_position_no + 1
请注意,如果自添加后POSITION_NO + 1不存在,则只会在第二个语句中插入。如果是那么它会再试一次。