当Id为非自动编号时生成下一个ID

时间:2013-06-30 14:37:17

标签: sql sql-server

我有一个名为Employee的表。 EmpId列用作主键。在我的场景中,我无法使其成为自动编号。

为我要在表中插入的新行生成下一个EmpId的最佳方法是什么?

我正在使用SQL Server 2008和C#。

这是我目前获得的代码,但是在键值对表或链接表中输入Id(m * n关系)

Create PROCEDURE [dbo].[mSP_GetNEXTID]
@NEXTID int out,
@TABLENAME varchar(100),
@UPDATE CHAR(1) = NULL

AS
BEGIN
    DECLARE @QUERY VARCHAR(500)

        BEGIN
        IF EXISTS (SELECT LASTID FROM LASTIDS WHERE TABLENAME = @TABLENAME and    active=1)
        BEGIN

            SELECT @NEXTID = LASTID  FROM LASTIDS WHERE TABLENAME = @TABLENAME and active=1

            IF(@UPDATE IS NULL OR @UPDATE = '')
            BEGIN
                UPDATE LASTIDS
                SET LASTID = LASTID + 1 
                WHERE TABLENAME = @TABLENAME
                and active=1
            END

        END
        ELSE
        BEGIN
            SET @NEXTID = 1

            INSERT INTO LASTIDS(LASTID,TABLENAME, ACTIVE)
            VALUES(@NEXTID+1,@TABLENAME, 1)
        END
    END

END

4 个答案:

答案 0 :(得分:5)

使用MAX(id) + 1对性能和并发性都是一个坏主意。

相反,你应该求助sequences专门针对这类问题而设计。

CREATE SEQUENCE EmpIdSeq AS bigint
  START WITH 1
  INCREMENT BY 1;

要生成下一个id,请使用:

SELECT NEXT VALUE FOR EmpIdSeq;

您可以在insert语句中使用生成的值:

INSERT Emp (EmpId, X, Y)
VALUES (NEXT VALUE FOR EmpIdSeq, 'x', 'y');

甚至将其用作列的默认值:

CREATE TABLE Emp 
(
 EmpId bigint PRIMARY KEY CLUSTERED 
    DEFAULT (NEXT VALUE FOR EmpIdSeq),
 X nvarchar(255) NULL,
 Y nvarchar(255) NULL
);

更新:上述解决方案仅适用于SQL Server 2012+。对于旧版本,您可以使用带有标识字段的虚拟表来模拟序列行为:

CREATE TABLE EmpIdSeq (
 SeqID bigint IDENTITY PRIMARY KEY CLUSTERED
);

模仿NEXT VALUE的程序:

CREATE PROCEDURE GetNewSeqVal_Emp
  @NewSeqVal bigint OUTPUT
AS
BEGIN
  SET NOCOUNT ON
  INSERT EmpIdSeq DEFAULT VALUES

  SET @NewSeqVal = scope_identity()

  DELETE FROM EmpIdSeq WITH (READPAST)
END;

用法例子:

DECLARE @NewSeqVal bigint
EXEC GetNewSeqVal_Emp @NewSeqVal OUTPUT

删除最后插入的元素的性能开销将是最小的;仍然,正如原作者所指出的那样,您可以选择删除删除语句并安排维护作业,以便在非工作时间(交易空间)中删除表内容。

改编自SQL Server Customer Advisory Team Blog


<强> Working SQL Fiddle

答案 1 :(得分:2)

以上

select max(empid) + 1 from employee

是获取下一个数字的方法,但是如果有多个用户插入数据库,那么上下文切换可能会导致两个用户为empid获取相同的值,然后为每个添加1,然后以重复ID结束。如果您有多个用户,则可能必须在插入时锁定表。这不是最佳实践,这就是数据库表存在自动增量的原因。

答案 2 :(得分:0)

我希望这适合你。考虑到您的ID字段是整数

INSERT INTO Table WITH (TABLOCK)
(SELECT CASE WHEN MAX(ID) IS NULL 
  THEN 1 ELSE MAX(ID)+1 END FROM Table), VALUE_1, VALUE_2....

答案 3 :(得分:-1)

尝试以下查询

INSERT INTO Table VALUES 
((SELECT isnull(MAX(ID),0)+1 FROM Table), VALUE_1, VALUE_2....)

你必须在最大值上检查isnull,否则当表中不包含行时,它将在最终结果中返回null。