Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 在SQL Server中按公司生成唯一密钥_Sql Server - Fatal编程技术网

Sql server 在SQL Server中按公司生成唯一密钥

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 我需要一个函数,它将公司编号

我将职位存储在SQL Server 2012数据库中,每个职位由职位编号和公司编号定义

职位编号仅适用于每家公司

例如,我的数据库可以有以下内容

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