我有一个名为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
答案 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。