2

我有一张名为 Employee 的表。EmpId 列用作主键。在我的场景中,我不能让它自动编号。

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

我正在使用带有 C# 的 SQL Server 2008。

这是我目前得到的代码,但是要在键值对表或链接表中输入 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

4 回答 4

5

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

相反,您应该求助于专门为此类问题设计的序列。

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

并生成下一个 id 使用:

SELECT NEXT VALUE FOR EmpIdSeq;

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

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 客户咨询团队博客


工作 SQL 小提琴

于 2013-06-30T14:54:25.777 回答
2

以上

select max(empid) + 1 from employee

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

于 2013-06-30T14:49:09.213 回答
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....
于 2013-06-30T14:39:23.240 回答
-1

尝试以下查询

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

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

于 2013-06-30T14:50:53.700 回答