【问题标题】:SQL Server identity number is not consecutiveSQL Server 标识号不连续
【发布时间】:2021-05-20 04:27:09
【问题描述】:

我正在为每一行创建一个带有索引号 (CustRef) 的数据库表。

索引从 1 开始,每新行增加 1。查询语言如下:

CREATE TABLE [dbo].[CustDetails]
(
    [CustRef] [int] IDENTITY(1,1) NOT NULL,
    [LName] [nchar](25) NOT NULL,
    [FName] [nchar](25) NOT NULL,
    [Address] [nchar](80) NULL,
    [Suburb] [nchar](25) NULL,
    [State] [nchar](5) NULL,
    [PCode] [nchar](5) NULL,

    CONSTRAINT [PK_CustDetails] 
        PRIMARY KEY CLUSTERED ([CustRef] ASC)
                    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                          IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                          ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

表已成功创建,我正在通过插入一些示例数据对其进行测试。在一个阶段,我删除了一行,索引号(CustRef)为 6。删除索引 6 行后,继续插入示例数据。

很遗憾,索引号不是连续的。换句话说,我期待新的数据内容将使用索引 6 作为其行索引号。但是,新条目跳过索引 6,它从索引 7 开始。

从上面的截图可以看出,在索引 5 和 7 之间,缺少索引 6。

如何解决这个问题?提前致谢。

【问题讨论】:

  • SQL Server 中的标识列就是这样工作的——这是怎么回事?你不应该关心你的 ID 是什么。
  • 删除的身份值不会被“回收”是一件好事!不要再浪费精力尝试这样做了....首先,身份需要唯一
  • 另外根据问题指南,请不要发布代码、数据、错误消息等的图像 - 复制或在问题中键入文本。请保留将图像用于图表或演示渲染错误,无法通过文本准确描述的事情。
  • 没有问题。这就是身份列被记录为工作的方式。它们肯定会增加,但并非没有间隙。这是一项提高性能的功能。

标签: sql sql-server tsql


【解决方案1】:
1. Create the table

 CREATE TABLE [dbo].[CustDetails]
 (
 [CustRef] [int] IDENTITY(1,1) NOT NULL,
 [LName] [nchar](25) NOT NULL,
 [FName] [nchar](25) NOT NULL,
 [Address] [nchar](80) NULL,
 [Suburb] [nchar](25) NULL,
 [State] [nchar](5) NULL,
 [PCode] [nchar](5) NULL,


 ) 
GO
  1. 插入记录

  2. 删除了最后一条记录。就我而言,这是第四条记录。

  3. 设置身份插入

    SET IDENTITY_INSERT [dbo].[CustDetails] ON;

  4. 插入了包含标识列的记录。

    插入 [dbo].[CustDetails] ([CustRef] , [LName], [FName] , [Address],
    [郊区],[州],[PCode])值(4,'test4', '测试','测试','测试','测试','测试')

这种方法很适合测试。但通常,除非您截断表,否则您的索引不会在 SQL Server 的标识列中重置,因为它已经分配。所以这是一种解决方案。使用 Identity insert 可以获得行数,并根据 max(row count) 在插入记录时设置标识列值。

【讨论】:

    【解决方案2】:

    在您的表 CustDetails 列中,CustRef 是标识列。它在 1、2、3、4、5、6 处自动递增,现在您删除了最后一行,即从 CustDetails 中删除 CustRef=6。从技术上讲,下一行将插入 7,因为 SQL 已经将值 6 分配给前一行。在其他情况下,如果您输入了最多 1、2、3、4、5、6、7、8、9,现在删除第 6 行。根据您的要求,您期望下一个值是多少? 10 还是 6?

    当客户要求提供仅删除最后一行并且没有要跳过的数字时,我已经实现了逻辑,我已经为下一行编写了 maxvalue + 1 的逻辑。您可以在插入时写为 remove identity 和 max(CustRef)+1 。或者,您可以在每次删除后使用 dbcc reseed

    declare @id int = 0
    SELECT @id =  MAX(CustRef) FROM CustDetails
    DBCC CHECKIDENT ('dbo.CustDetails', reseed, @id)
    

    这将告诉 sql 将值重置为上一个最大值。这根本不是推荐的方法。这只是一个选项,但是是的,您可以在插入语句之前选择删除标识并为 get max(CustRef) 编写逻辑,然后将其递增并插入到表 CustDetails 中。

    【讨论】:

      【解决方案3】:

      好吧,如果它没有那样工作,那么你会遇到这个:

      insert custRef ...; // id = 1
      insert custRef ...; // id = 2
      
      insert custRef (fName, lName)
      values ('Jane', 'Goodall'); 
      // id = 3
      

      简·古道尔!她应该得到奖励。

      declare @giveAPrizeTo int = (
          select   id 
          from     custRef 
          where    fname = 'Jane'
          and      lname = 'Goodall'
      );
      

      我们实际上会在稍后交付。

      但首先,另一个任务。无法联系到的客户并没有真正的用处。老板要求我们保持餐桌清洁。

      delete custRef where address is null;
      alter table custRef alter column address nchar(80) not null;
      

      好的,好吧,继续,添加下一个人。

      insert custRef (fName, lName, address)
      values ('Jeffrey', 'Dahmer', '1234 W Somewhere; Milwaukee, Wisconsin 12345');
      

      在这个 id 被回收的假设方言中,Jeffrey Dahmer 现在的 id = 3。

      嗯,这很有趣。我应该小心最新的客户。好吧,我分心了,我在做什么?哦对了,这个奖!我最好送货上门。

      declare @message nvarchar(max) = (
      
          select    'Congratulations ' + fName + ' ' + lName ', ' + 
                    'we support your good works.  Have a prize!' 
          from      custRef
          where     id = @giveAPrizeTo;
      
      );
      
      print (@message);
      

      恭喜 Jeffrey Dahmer,我们支持您的出色工作。有奖!

      哎呀!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-19
        • 1970-01-01
        • 1970-01-01
        • 2018-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多