如何在 SQL Server 中重新设置标识列?
Posted
技术标签:
【中文标题】如何在 SQL Server 中重新设置标识列?【英文标题】:How to reseed the identity column in SQL Server? 【发布时间】:2014-05-02 17:47:02 【问题描述】:我在 SQL Server 中有一个名为 Personal_Info
的表。此表有一个名为Vol_ID
的列,(Is Identity)
属性为Yes
。
现在我插入了大约 175568 行作为测试。然后我删除了大约 568 行,但是当我再次插入数据时,列 Vol_ID
从 175569 开始而不是从 175001 开始。
我想插入数据并让Vol_ID
列从其中的最后一个数字开始。例如,如果最后一行是 15,则下一行应该从 16 开始,即使我已经插入但我删除了它。
我需要一个存储过程或触发器,它可以强制插入操作填充缺失的 id,检查最后存在的行,如果在存在之后有缺失的 id,然后填充它。
我有这个程序来进行插入
USE [VolunteersAffairs]
go
/****** Object: StoredProcedure [dbo].[AddVolunteer] Script Date: 05/02/2014 21:12:36 ******/
SET ansi_nulls ON
go
SET quoted_identifier ON
go
ALTER PROCEDURE [dbo].[Addvolunteer] @Vol_Name NVARCHAR(255),
@Vol_Zone NVARCHAR(255),
@vol_street NVARCHAR(255),
@Vol_Sex INT,
@Vol_Date_of_Birth DATE,
@Vol_Home_Phone INT,
@Vol_Work_Phone INT,
@Vol_Mobile1 INT,
@Vol_Mobile2 INT,
@Vol_Email NVARCHAR(255),
@Vol_Job NVARCHAR(255),
@Vol_Affiliation NVARCHAR(255),
@vol_Education INT,
@vol_Education_Place NVARCHAR(255),
@vol_Education_Department NVARCHAR(255),
@vol_Interesting INT,
@vol_Notes NVARCHAR(255),
@Team_ID INT
AS
INSERT INTO personal_info
(vol_name,
vol_zone,
vol_street,
vol_sex,
vol_date_of_birth,
vol_home_phone,
vol_work_phone,
vol_mobile1,
vol_mobile2,
vol_email,
vol_job,
vol_affiliation,
vol_education,
vol_education_place,
vol_education_department,
vol_interesting,
team_id,
vol_notes)
VALUES (@Vol_Name,
@Vol_Zone,
@vol_street,
@Vol_Sex,
@Vol_Date_of_Birth,
@Vol_Home_Phone,
@Vol_Work_Phone,
@Vol_Mobile1,
@Vol_Mobile2,
@Vol_Email,
@Vol_Job,
@Vol_Affiliation,
@vol_Education,
@vol_Education_Place,
@vol_Education_Department,
@vol_Interesting,
@Team_ID,
@vol_Notes)
请帮我写下丢失的身份证
【问题讨论】:
您需要重新设置身份列。 一句忠告:不要这样做!你应该永远不要 “回收”以前用于新行的标识值。不要这样做 - 如果你这样做,你最终会陷入数据库地狱! Stop making assumptions aboutIDENTITY
,别再担心差距了 - 它们真的不是问题!
【参考方案1】:
您需要像下面这样重新设置身份列
DBCC CHECKIDENT(Personal_Info, RESEED, 175001)
引用自 MSDN
权限:
调用者必须拥有该表,或者是 sysadmin 固定服务器的成员 角色、db_owner 固定数据库角色或 db_ddladmin 固定 数据库角色。
所以。它是表的所有者(或)DBA 可以执行标识列的reseed
而不是普通用户。此外,您为什么还要允许您的应用程序用户重新设定身份列的值?这根本没有意义。
编辑:
在这种情况下,请查看下面的@Brennan 答案。简而言之,您应该从存储过程执行插入。我的意思是你的APP应该调用SP并执行插入。如下所示(示例代码)。此外,在这种情况下,删除 vol_id 列的标识属性(vol_id 应该只是 vol_id int not null unique
)
create procedure sp_insert-person
@name varchar(10)
as
begin
declare @last_id int;
select @last_id = top 1 Vol_ID from Personal_Info order by Vol_ID desc;
insert into Personal_Info(Vol_ID,name)
values(@last_id+1,@name);
end
您的应用程序将调用类似的过程
exec sp_insert-person @name = 'user2251369'
最终编辑:
请参阅此帖子 RESEED identity columns on the database,了解为什么应避免使用 reseeding
IDENTITY 值(marc_s 给出的一个很好的小解释)。
您的最终程序应如下所示
USE [VolunteersAffairs]
GO
/****** Object: StoredProcedure [dbo].[AddVolunteer]
Script Date: 05/02/2014 21:12:36 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[AddVolunteer]
@Vol_Name nvarchar(255),
@Vol_Zone nvarchar(255),
@vol_street nvarchar(255),
@Vol_Sex int,
@Vol_Date_of_Birth date,
@Vol_Home_Phone int,
@Vol_Work_Phone int,
@Vol_Mobile1 int,
@Vol_Mobile2 int,
@Vol_Email nvarchar(255),
@Vol_Job nvarchar(255),
@Vol_Affiliation nvarchar(255),
@vol_Education int,
@vol_Education_Place nvarchar(255),
@vol_Education_Department nvarchar(255),
@vol_Interesting int,
@vol_Notes nvarchar(255),
@Team_ID int
As
BEGIN
DECLARE @last_vol_id int;
select top 1 @last_vol_id = Vol_ID from Personal_Info order by Vol_ID desc;
insert into Personal_Info
(Vol_Id,
Vol_Name,
Vol_Zone,
vol_street,
Vol_Sex,
Vol_Date_of_Birth,
Vol_Home_Phone,
Vol_Work_Phone,
Vol_Mobile1,
Vol_Mobile2,
Vol_Email,
Vol_Job,
Vol_Affiliation,
vol_Education,
vol_Education_Place,
vol_Education_Department,
vol_Interesting,
Team_ID,
vol_Notes)
values
(@last_vol_id+1,
@Vol_Name,
@Vol_Zone,
@vol_street,
@Vol_Sex,
@Vol_Date_of_Birth,
@Vol_Home_Phone,
@Vol_Work_Phone,
@Vol_Mobile1,
@Vol_Mobile2,
@Vol_Email,
@Vol_Job,
@Vol_Affiliation,
@vol_Education,
@vol_Education_Place,
@vol_Education_Department,
@vol_Interesting,
@Team_ID,
@vol_Notes);
END
【讨论】:
这对我有用,不适用于应该使用该应用程序的普通用户,如果他/她插入一些行然后删除它,那么当他们插入新数据时,应该检查最后一行然后重新播种。谢谢 @user2251369,请参阅编辑后的答案。您根本不应该允许您的应用用户执行此任务。 谁让我建立这个应用程序告诉我序列号是最重要的,它应该自动插入。 @user2251369,在这种情况下,请查看下面的 Brennan 答案。简而言之,您应该从存储过程执行插入。我的意思是你的APP应该调用SP并执行插入。【参考方案2】:您尝试做的不是标识列的用途 - 不能保证不会有间隙,删除记录不会重新使用丢失的标识。
如果您确实需要一个连续的、自动递增的 id 字段,并且没有间隙,那么您最好使用存储过程进行插入(您需要添加逻辑以重用丢失的 id) , 或者定义一个触发器来强制执行您想要的操作 - 但尝试强制标识列执行您正在尝试执行的操作是错误的方法。
【讨论】:
谢谢,但如果可以编写一个存储过程或触发器的示例,将强制应用程序写入丢失的 id,这将是有帮助的,再次感谢【参考方案3】:正如其他人所说,您可以重新设定身份。但是,这仅在您最后删除时才有效。填补身份的空白将非常具有挑战性,您最终将不得不关闭身份。
如果这是种子数据的小案例,您可以打开身份插入。 enter link description here
SET IDENTITY_INSERT your table ON
Here is another question highlighting the other concerns
【讨论】:
这绝不是一个好主意。如果你这样做..那么最好不要有标识列。 设置 Identity_Insert On 永远不是一个好主意?任何绝对都很难捍卫。当我需要在开发过程中播种表格并清除某些内容时,我经常使用它。它可供我们使用,但我同意这种情况很少见。 与not good idea
;我的意思是,不要强制写入身份,而是重新设置身份值或其他方式。 SET IDENTITY_INSERT
默认为OFF
。这背后肯定有一些很好的理由。
哦,我明白了,我同意。我想说的是重新植入身份并不能解决全部问题。 如果用户有可能从列表中间删除项目,然后重新设置身份并不能解决这些差距。【参考方案4】:
这就是魔法。在插入之前执行此操作。
declare @i int
select @i=max(id) from Personal_Info
DBCC CHECKIDENT (Personal_Info, RESEED, @i)
【讨论】:
以上是关于如何在 SQL Server 中重新设置标识列?的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法确保 SQL Server 标识列值即使在多次服务器重新启动后也始终保持一致?
如何在不删除sql server表中数据的情况下,让自增的id列从1开始