Sql server 在SQL Server中按公司生成唯一密钥
我将职位存储在SQL Server 2012数据库中,每个职位由职位编号和公司编号定义 职位编号仅适用于每家公司 例如,我的数据库可以有以下内容Sql server 在SQL Server中按公司生成唯一密钥,sql-server,Sql Server,我将职位存储在SQL Server 2012数据库中,每个职位由职位编号和公司编号定义 职位编号仅适用于每家公司 例如,我的数据库可以有以下内容 POSITION_NO COMPANY_NO 1 1 2 1 3 1 1 2 2 2 3 2 1 3 我需要一个函数,它将公司编号
POSITION_NO COMPANY_NO
1 1
2 1
3 1
1 2
2 2
3 2
1 3
我需要一个函数,它将公司编号作为参数,并返回下一个连续的职位编号,在上面的示例表中,对于公司编号=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)会有潜在的缺陷,但这是在防止数据库上的数据锁定的一次失败尝试中添加的。事实上,除了写得好的代码显然更可取之外,我问这个问题的主要原因是试图减少可能导致数据锁定的位置数量 有什么方法可以改进我的代码吗
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
请注意,只有在没有添加位置_NO+1的情况下,才会在第二条语句中插入此项。如果是,它将重试。创建一个包含序列的辅助表,每个公司一行(正如您已经做的那样): 为每个公司分配一个计数器(假设有两个公司,1和2): 然后,您只需要在一条语句中更新和选择新值,以避免竞争条件。这是如何做到的:
declare @next int;
declare @company int;
set @company = 2;
update seq
set @next = sequence = sequence + 1
where company = @company;
select @next
最好将其封装到标量函数中,但不幸的是,函数中不允许更新。但是您已经有了一个存储过程,所以只需修改其中的代码即可
请告诉我,使用的数据类型不是真正的浮动?为什么不使用ints?“但这是在阻止数据库上的数据锁定的一次失败尝试中添加的”好吧,死锁消失了,腐败也来了。僵局经常发生,因为否则会有腐败。谢谢你的建议!(浮动是Oracle自动转换的残余)如果@ROWCOUNT=0 begin insert到seq(company,sequence)值(@company,1)end,我没有设置计数器种子,并添加以下代码
是否有问题,可能没有,但您可能需要确保它是线程安全的。一个唯一的约束和一点错误处理就可以了。
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