【问题标题】:Table ID (PrimaryKey) does not increment in a proper sequence when a new record is inserted [duplicate]插入新记录时,表 ID(PrimaryKey)不会以正确的顺序递增 [重复]
【发布时间】:2013-07-11 09:39:17
【问题描述】:

当我使用 SQL Server 2008 及其 Management Studio 删除表中的记录,然后插入新记录时,主键列的顺序不正确。

假设我用record_id = 5 删除 Record5。表中剩下 4 条记录,即Record1,Record2,Record3,Record4

现在当我插入一条新记录时.. 它的ID(主键)自动设置为 6。我需要 SQL Server 将其设置为 5。

因为当我在 Asp.Net (c#) 的 gridView 中显示此表时看起来很奇怪,我的表的 record_id 列序列类似于 1, 2, 3, 17, 18, 29 等,

看起来很糟糕。请帮忙。

谢谢

【问题讨论】:

  • 您不应该向用户公开这些 ID 值 - 如果您需要一个用于显示目的的数字,请考虑在您的 SELECT 语句中调用 ROW_NUMBER()。您应该将标识值视为恰好能够存储在 int 中的不透明 blob - 您不应该以任何方式依赖它们的实际数值。
  • @Damien_The_Unbeliever :请帮助我摆脱我所处的这种奇怪情况......你的建议确实很有价值,但目前无法接受。我需要摆脱困境。请帮忙。
  • 我假设,如果记录 1 被删除,你希望所有现有的行也被 1 洗牌吗?如果是这样,当该列被标记为 IDENTITY 列时无法完成 - 所以 any 修复将需要在某处重新工作 - 为什么不正确修复?
  • 好吧,我根本不认为你在任何情况下,这里有任何问题。如果记录 5 被删除,它将保持删除状态。你不能再有 5 个,接下来是 6 个。我不同意它看起来很糟糕。
  • @RemusRusanu:原文问为什么身份列没有严格增加。这个问题询问您如何获得严格增加的数字。那是怎么复制的?

标签: sql sql-server-2008


【解决方案1】:

不保证 IDENTITY 值不会有间隙。事实上很可能会遇到这样的空白。您必须以适应和预期身份值中的此类差距的方式设计您的应用程序。到目前为止,要在网格中显示行号,最好的选择是使用本地客户端(ASP.Net 甚至浏览器端 JS)计数器。您可以使用ROW_NUMBER() 生成计数器服务器端,但与客户端相比不是最佳选择。

【讨论】:

    【解决方案2】:

    您需要将数据的显示与数据库中的标识列分开排序。标识列不是用于“显示顺序”的,实际上它没有任何可识别的顺序——它总会有孔。

    考虑一个有 4 行的表格。现在添加 5,然后删除 5 行。您输入的下一列的 ID 为 10,即使表中只有 5 行。

    所以,不要再依赖它了。而是使用 Container.ItemIndex 并使用它来显示正在显示的行数的适当计数。

    【讨论】:

    • +1 因为客户端编号的实用解决方案
    【解决方案3】:

    这听起来可能令人难以置信,但如果您想要一个递增的记录数,SQL Server 不支持您。回滚的事务或服务器重新启动可能会在数字上留下漏洞。

    对于严格递增的顺序,您必须滚动自己的实现。一种常见的解决方案是创建一个表格,其中包含最近分发的号码列表。如果您以原子方式检索和增加数字,那是线程安全的。例如:

    update  NumbersTable
    set     Nr = Nr + 1
    output  deleted.Nr
    where   Type = 'OrderNumber'
    

    另一个选项是动态检索最高订单号。使用适当的锁定提示,可以以线程安全的方式完成:

    insert  OrdersTable
            (OrderNr, col1, col2, col3)
    select  isnull((
            select  max(OrderNr) + 1
            from    OrdersTable with (tablock, holdlock)
            ), 1)
    ,       'value1'
    ,       'value2'
    ,       'value3'
    

    如果您删除一行,则必须手动实施。假设记录 1、2 和 3 存在。您删除了记录 2。新订单应该得到什么号码?如果你说 2,请记住,这意味着订单 2 是在订单 3 之后创建的,这会让很多人感到困惑。

    【讨论】:

    • @Andomar:没错。但是它在 MS Excel 中是如何工作的……你删除了一行……它下面的行接管了它的索引。我想如果我能以某种方式实现它,它有望解决我的情况。 (满足我的要求)
    • 您可以在删除语句之后运行update YourTable set NrColumn = NrColumn - 1 where NrColumn > @deletedNr。确保相关列未被用作外键或被任何用户依赖。
    • @RehanMehdi Excel 不是具有关系约束的数据库服务器。
    • @RehanMehdi - Excel 显示为显示目的计算的行号。它不会向您显示内部指针的值。如果您向用户公开IDENTITY 值,则相当于向用户展示了一个内部指针。
    • @Damien_The_Unbeliever 哈哈。诚然。现在已经开始隐藏了。哈哈 。感谢您的提示。
    【解决方案4】:

    在您的 Delete 语句之后运行此查询。

    declare @a int
    
    set @a =(select max(identity_column_name) from table_name)
    --print @a
    
    dbcc checkident(table_name,reseed,@a)
    

    【讨论】:

    • @downvoter 请帮我找出我的错误。
    • 不是我的反对意见,但这显然不是线程安全的
    • @Andomar 什么是线程安全的?
    • 线程安全意味着并发,即如果被多个客户端同时调用,它将工作。您可以使用在 SSMS 的多个选项卡中运行的 while 循环来模拟并发。
    • @Luv 无论如何我可以在我的表上发生删除过程时自动执行此查询?
    猜你喜欢
    • 2020-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多