重置SQL Server中的标识列

7

我正在制作一个存储联系人的SQL数据库。我希望能够删除联系人,每个联系人的正确ID对于我的软件连接至关重要。假设我有一个名为James的联系人,他是第一个,他的ID是0。我添加了Mary,她的ID是1。如果我删除James,如何将Mary的ID设置为0而不是保持1?因为现在她是第一个,所以必须重置。换句话说,当某人被删除时,如何重置数据库中所有ID?谢谢。


你为什么想要这样做呢?如果你需要按照输入顺序保持它们的顺序,你可以添加一个日期时间戳或者添加一列来保持排名。 - achinda99
2
点赞这个问题。虽然我同意OP试图做的事情是不明智的,但这个问题对于新手程序员来说是一个很好的标志,告诉他们什么是不应该做的以及为什么。得到很多赞的答案似乎很好地解决了这个问题,并且非常有教育意义。 - JohnFx
1
这是初学者常犯的错误。他们会有一种感觉,认为他们会用完ID,所以想要减缓增长速度。 - Wadih M.
一个普通的整数只有大约21.87亿的空间。因此,很容易用完并需要重新组织ID。 - djangofan
@djangofan:你已经因为这个问题遇到过多少次了?... - Mitch Wheat
10个回答

17

在很多方面来说,这是一个非常糟糕的想法。我在考虑是否应该告诉你如何做这件事。一旦行的身份被设置,就不应该有更改其身份的原因。

如果确实需要更改身份,则您可能使用了错误的字段作为主键标识符。我在这里做出一个假设,即您正在谈论作为主键字段的PK字段,该字段也是标识列。

请记住,如果您创建任何链接到联系人表的表,并且开始更改Id,则还需要更新所有这些表。这将变得非常昂贵...


6

如果数据库中有大量记录,使用自增长列会使查询变得非常缓慢。自增长列对您没有帮助,您需要使用一些自定义的T-SQL来更改所有数字 - 但在我看来这是一个非常糟糕的想法。

如果您需要跟踪添加顺序,为什么不使用日期/时间戳呢?

您需要重新考虑您的设计。


5

这不是ID的工作方式,也不应该是ID的工作方式。ID不应该改变,否则所有链接的信息都将指向错误的行。

相反,为什么不添加一个由你控制的“External_ID”列? 或者在查询中动态编号(使用计算列?)


4
在自增主键列上这样做没有任何意义,即使可以轻易地实现,如果没有相关表的大规模更新,您会影响数据完整性。要这样做,您可能需要从该列中删除索引和主键约束(此时您的应用程序可能会崩溃),重新编号所有后续记录,重新编号所有相关表,然后重新应用主键约束和索引。
如果您真的必须拥有某种始终从0开始的线性标识符(这可能表示软件设计存在问题),那么除了主键之外,您还可以拥有一个二级ID列,然后使用类似以下语句的语句更新以将较高值向下移动一行:
UPDATE table
SET secondaryID = secondaryID - 1
WHERE secondaryID > (SELECT secondaryID FROM table WHERE primaryID = [id to delete]);

DELETE FROM table
WHERE primaryID = [id to delete];

我强烈反对这样的做法 - 如果你的ID是由于删除记录而出现“缺失”值,软件应该测试这些值是否存在,而不是只是出现错误。


4
ID是行的唯一标识符。它可用于将一行链接到另一个表中的另一行。ID的缺失本身就包含信息,因为它明确表示已删除。开始循环使用ID号码完全违背了具有唯一标识符的目的,并且真的没有任何意义。一旦将ID分配给一行,就不应该随意更改它。想象一下,当某人去世时,他们将社会保险号(ID)交给其他人。这将导致将所有与死者社会保险号相关联的旧信息转移到新人身上,这是没有意义的。如果重新分配ID,则会继承先前与其关联的任何旧数据。

3

每次删除一行时重新编号自增列并不是解决这个问题的最佳方法。最好使用其他方法来解决。

如果不知道您的应用程序为何需要这样做,很难确定需要采取哪些方法。但是,您的应用程序需要这种功能可能表明某个地方存在设计问题。


2

您正在将id用作不仅仅是标识符。如果是这种情况,您将无法使用自动增量字段。您需要在代码中处理此问题。


1
一分钟的谷歌搜索给了我一个无法显示的页面。在2009年6月1日之前,如果你谷歌搜索“tsql fix 'identity column'”,它将是你的第一个链接。
基本上,我建议在重新编号之前,在所有关系字段和涉及到的ID字段之间添加外键约束(如果有任何关系,重新编号也是一个可怕的想法,严格来说,因为如果你问这个问题,你会遇到很多麻烦)。
如果你的联系人表是你唯一的表或者基于这个ID字段没有任何关系,你可以将Identity属性设置为NO,将值从1到COUNT(ID)重新编号,然后将Identity属性设置为YES,并使用以下命令完成重新标识:
DECLARE @MaxID INT
SELECT @MaxID = COUNT(ID) FROM TableID
DBCC CHECKIDENT('TableID', RESEED, @MaxID)
在这种情况下,您可以在每次删除后使用以上重新生成脚本(但一旦所有内容最初正确设置,将COUNT(ID)更改为MAX(ID),随着表变得越来越大,这会增加一些速度),在任何其他插入或外键约束更新之前。确保在删除和重新生成块周围使用TRANSACTIONS,并确保表只允许同步事务,这将防止重新生成过程中的任何数据故障。

复杂吧?这就是为什么最好从一开始就做好准备;)(我从经验中学到了这个)如果您有任何更多问题,请发送电子邮件至mraarone et yahoo d0t com。


0

我编写了一个应用程序来处理多级销售计划。 当然,人们会退出。在我们的计划中,还需要插入新人。

你已经走在正确的轨道上,只需要做出一些修改。

身份证号(ID)和序列号(seq)是两个不同的概念。 它们之间没有任何关系。

永远不要更改ID。一旦分配,就永久保留。

在你的表中创建一个列(cNEXT)用于序列,并使用ID填充它。 “下一个序列中的ID是什么?”

随时重新排列cNEXT中的ID,重新分配cNEXT。 任何存储过程都可以完成这项任务。

这样,你也可以灵活地创建非连续的ID链。 当人们转移到不同的地区或晋升到不同的组时,这非常有用。

希望这能帮到你! :)


0

所有答案都假设这是生产环境。如果您正在测试数据库设计,然后想要快速截断所有表,应该有一种简单的方法来完成此操作:

DBCC CHECKIDENT({表名},重新生成,0)

*首先使用ID从所有表中删除所有行


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接