如何在SQL Server表中插入自动增量键
我想将行插入到具有唯一、非自动递增主键的表中 是否有一个本机SQL函数来计算最后一个键并将其递增,还是必须分两步执行:如何在SQL Server表中插入自动增量键,sql,sql-server,Sql,Sql Server,我想将行插入到具有唯一、非自动递增主键的表中 是否有一个本机SQL函数来计算最后一个键并将其递增,还是必须分两步执行: key = select max(primary.key) + 1 INSERT INTO dbo.TABLE (primary.key, field1, fiels2) VALUES (KEY, value1, value2) 因为它是自动生成的,所以不要提供: INSERT INTO bo.TABLE (field1, fiels2) VALUES (value1, v
key = select max(primary.key) + 1
INSERT INTO dbo.TABLE (primary.key, field1, fiels2) VALUES (KEY, value1, value2)
因为它是自动生成的,所以不要提供:
INSERT INTO bo.TABLE (field1, fiels2) VALUES (value1, value2)
更新:如果您的列是一个标识
列,则该操作将有效
要为标识列提供显式值,必须执行以下操作:
set identity_insert bo.TABLE on
INSERT INTO bo.TABLE (primary_key, field1, fiels2) VALUES ((SELECT ISNULL(MAX(id) + 1, 0) FROM bo.Table), value1, value2)
set identity_insert bo.TABLE off
但是没有令人信服的理由这样做。从您的注释判断,表中有一个主键不是标识列 如果您的SQL Server版本是SQL 2012,则应查看序列: 在其他版本中,您需要使用IDENTITY属性重新创建表(http://msdn.microsoft.com/en-us/library/aa933196(v=sql.80).aspx)或使用两步方法 如果采用两步方法,则需要确保并发运行的insert不会使用相同的新值。最简单的方法是将select和insert组合成一个值,并使用serializable表提示:
CREATE TABLE dbo.Tbl1(id INT PRIMARY KEY, val1 INT, val2 INT)
INSERT INTO dbo.Tbl1(id, val1, val2)
VALUES((SELECT ISNULL(MAX(id)+1,0) FROM dbo.Tbl1 WITH(SERIALIZABLE, UPDLOCK)), 42, 47);
SELECT * FROM dbo.Tbl1;
在我看来,最好的答案是修复表,使PK列成为标识列。(请参阅我对塞巴斯蒂安·梅因(Sebastian Meine)的答案的评论,关于为什么您当前选择的答案不是最佳答案。)使现有PK成为标识列的唯一方法是将表调出。大致:
BEGIN TRAN;
-- Rename all constraints in original table
EXEC sp_rename 'dbo.YourOriginalTable.PK_ConstraintName', 'PKConstraint_Backup';
EXEC sp_rename 'dbo.YourOriginalTable.OtherConstraintName', 'OtherConstraintName_Backup';
CREATE TABLE dbo.WorkTable (
YourPKColumn int identity(1, 1) NOT NULL -- your PK converted to identity
CONSTRAINT PK_YourOriginalTableConstraintName PRIMARY KEY CLUSTERED,
AllOtherColumns -- all your other columns exactly as in the original table
);
SET IDENTITY_INSERT dbo.WorkTable ON;
INSERT dbo.WorkTable (YourPKColumn, AllOtherColumns)
SELECT YourPKColumn, AllOtherColumns
FROM dbo.YourOriginalTable WITH (TABLOCKX, HOLDLOCK);
SET IDENTITY_INSERT dbo.WorkTable OFF;
-- Drop all FK constraints from other tables pointing to your table
ALTER TABLE dbo.TableWithFK_1
DROP CONSTRAINT FK_TableWithFK_1_YourOriginalTableSomethingID;
-- Swap out the tables
EXEC sp_rename 'dbo.YourOriginalTable', 'YourOriginalTableBackup';
EXEC sp_rename 'dbo.WorkTable', 'YourOriginalTable';
-- If you didn't add them in the WorkTable creation,
-- add all other removed or needed constraints creation
ALTER TABLE dbo.YourOriginalTable
ADD CONSTRAINT OriginalConstraint (OriginalConstraintColumns);
-- Add back FK constraints from other tables to this one.
COMMIT TRAN;
您现在有了一个表,该表有一个标识列,上面有一个聚集的PK。你可以插入它没有问题。不再存在并发问题,如果不存在Emp,请创建表 ( eid int(10)非空主键自动递增, 名称varchar(45)不为空, 年龄整数(5)默认值为20, 薪金(5) ) 插入emp值(102,'Ranjan',21450000) 然后尝试下面的sql查询。它将自动将eid增加到下一个数字 插入emp(姓名、薪水)值('Lisma',118500)
从emp中选择* 我已经尝试过了,抛出了一个约束错误,我必须提供值。违反主键约束“pk_-bo”。无法在对象“dbo.bo”中插入重复键。重复的键值是(921,012)。@RubenTeixeira这就是您在未指定ID时得到的错误?你确定它没有标识列吗?db作为另外两个主键—文档序列号和年份,当我没有提供文档编号的键时,它会抛出此错误。看起来你的自动递增字段不是主键的一部分。你能发布表格定义和你的insert语句吗?你是说你的表格上有一个?如果是这样的话,您有什么确切的问题没有在文档或本网站关于使用它们的讨论中讨论?在下面的评论中,您提到了一个错误,但您没有确切说明它是什么。理想情况下,请显示您的
CREATE TABLE
脚本、您的INSERT
语句以及由此产生的错误消息。此线程解决了我所有的难题,代码正在重新编译。为什么ppl对此投了反对票?谢谢!!!现在有了一个解决方案,它不是一个函数,但我可以通过子查询进行管理,比两步过程更好。谢谢。SERIALIZABLE
相当于HOLDLOCK
,这是一个良好的开端,但还不够。在高并发情况下,查询仍然可能失败。您必须添加UPDLOCK、TABLOCKX
。查询的各个部分会随着时间的推移而执行,锁也会随着时间的推移而获取——因此INSERT
位于SELECT
之后。两个客户机可以使用完全兼容的读锁同时选择,然后第二个客户机被阻止,而第一个客户机为其插入转换为,第二个客户机在块结束后具有旧值。您需要选择来阻止所有读卡器!最终,这种SELECT max()+1
模式不是最佳实践,不能推荐。标识列的存在正是出于这个原因。使用它们。@ErikE,你说得对,我忘了上锁。我确实更新了答案但是,不需要TABLOCKX。我们只需要停止读取相同的查询,而不需要停止任何查询。然后,我们只需要确保任何插入都使用此模式。不遵循此模式的并发插入将被可序列化查询提示阻止,并最终失败。-虽然这不是最好的解决方案,但它是一个可用的解决方案。有时标识列不是一个选项。如果同步过程一次插入一条记录,则可以使用相同的模式。如果您需要能够在单个insert语句中插入多行,那么如果您将此模式与ROW_NUMBER()函数结合使用,则仍然可以使用此模式。重要的是,SELECT max()+1在此表的所有(!)插入上同时使用SERIALIZABLE和UPDLOCK。如果该选择不是我的示例中的子选择,那么您还需要将其与事务中的insert一起包装(如果在过程中发生这种情况,请首先阅读:)+1当然,如果这是一个活动系统,您将希望在显式事务中执行此操作。否则,在插入之后但在重命名之前,会有将一些数据放入您的原始表的危险。很抱歉,这不是我的数据库,我无法进行任何更改,它是为与ERP应用程序一起使用而设计的。只需按照问题中解释的程序进行操作,谢谢。