【问题标题】:Get all missing values between two limits in SQL table column获取 SQL 表列中两个限制之间的所有缺失值
【发布时间】:2017-10-29 03:35:41
【问题描述】:

我正在尝试为插入到 SQL Server 2005 数据库表中的记录分配 ID 号。由于可以删除这些记录,因此我希望为这些记录分配表中的第一个可用 ID。例如,如果我有下表,我希望在 ID 4 处输入下一条记录,因为它是第一个可用的。

    | ID | Data |
    | 1  | ...  |
    | 2  | ...  |
    | 3  | ...  |
    | 5  | ...  |

我希望这样做的方式是通过 SQL 查询建立可用 ID 的列表。从那里,我可以在我的应用程序代码中进行所有检查。

因此,总而言之,我想要一个 SQL 查询,它可以从特定表列中检索 1 到 99999 之间的所有可用 ID。

【问题讨论】:

标签: sql identity


【解决方案1】:

首先建立一个包含所有 N 个 ID 的表。

declare @allPossibleIds table (id integer)
declare @currentId integer

select @currentId = 1
while @currentId < 1000000
begin
    insert into @allPossibleIds
    select @currentId

    select @currentId = @currentId+1
end

然后,将该表左连接到您的真实表。您可以根据需要选择 MIN,或者您可以将 allPossibleID 限制为小于最大表 id

select a.id 
from @allPossibleIds a  
left outer join YourTable t
on a.id = t.Id
where t.id is null 

【讨论】:

  • 遗憾的是,我收到一条错误消息,提示我超出了 MAXRECURSION 最大值:为 MAXRECURSION 选项指定的值 1000000 超过了允许的最大值 32767。
  • 嗯。然后我想你可以在一个while循环中构建一个@Table。我会调整答案。
  • @user1326091 maxrecursion 是 1 到 32k-1 或 0 表示没有限制。查看更正后的回复。请注意,此 CTE 可能需要很长时间。如果您要在线运行它,我建议您使用其他方法
  • 啊哈!使用 Luis 对 Bill 最初建议的修复似乎有效,但完成查询需要 36 秒。这比我希望的要长,但我可以限制通过代码检索到的记录数,所以这不是什么大问题。干杯!
  • "...但它需要 36 秒才能完成...." 因此,为什么我说不建议这样做,并且对于尝试这样做的人来说都是浪费时间和资源做这样的事情,以及 SQL 服务器花费的处理能力来做一些对它来说毫无意义的事情。
【解决方案2】:

不要追求身份,

让我给你一个简单的选择,而我正在做一个合适的选择。

将 1-999999 的 int 存储在一个表中,比如 Insert_sequence。

尝试写一个Sp用于插入,

您可以轻松识别 Insert_sequence 中存在的最小值,而不是

您的主表,将此值存储在一个变量中,并从变量中插入带有 ID 的行..

问候

阿舒托什·艾莉亚

【讨论】:

    【解决方案3】:

    您也可以循环访问这些键。当你点击一个空的时,选择它并退出循环。

    DECLARE @intStart INT, @loop bit
    SET @intStart = 1 
    SET @loop = 1
    
    WHILE (@loop = 1)
    BEGIN
        IF NOT EXISTS(SELECT [Key] FROM [Table] Where [Key] = @intStart)
            BEGIN
            SELECT @intStart as 'FreeKey'
            SET @loop = 0
            END
    
    SET @intStart = @intStart + 1
    END
    GO
    

    从那里您可以随意使用密钥。设置@intStop 来限制循环字段是没有问题的。

    【讨论】:

      【解决方案4】:

      为什么你需要一个来自 1..999999 的表你需要的所有信息都在你的源表中。这是一个查询,它为您提供最小的 ID 以插入间隙。 它适用于所有组合:

      (2,3,4,5) - > 1
      (1,2,3,5) - > 4
      (1,2,3,4) - > 5
      

      SQLFiddle demo

      select min(t1.id)+1 from 
      (
        select id from t 
        union 
        select 0
       )
      
      t1 
      left join t as t2 on t1.id=t2.id-1
      where t2.id is null
      

      【讨论】:

      • 由于事务,我无法在插入点查询数据库。这就是为什么我需要 ID 列表开始,以及为什么我不能对每个单独的插入进行检查。
      【解决方案5】:

      许多人使用自增整数或长整数值作为表的主键,通常称为ID 或MyEntityID 或类似名称。此列,因为它只是一个自增整数,通常与存储的数据本身无关。

      这些类型的“主键”称为代理键。它们没有任何意义。许多人喜欢这些类型的 ID 是连续的,因为它“美观”,但这是浪费时间和资源。数据库可能不太关心哪些 ID 正在使用,哪些未使用。

      我强烈建议您忘记尝试这样做,而让 ID 列自动递增。您还应该在表上创建一个索引,该索引由可以唯一标识表中每条记录的那些(子集)列组成(甚至考虑使用此索引作为主键索引)。在需要使用所有列来完成此操作的极少数情况下,自动递增的主键 ID 非常有用——因为在表中的所有列上创建索引可能性能不佳。即便如此,数据库引擎也可能不太关心这个 ID(例如,哪些 ID 正在使用,哪些未在使用等)。

      还要考虑基于整数的 ID 最多有 42 亿个 ID。您不太可能在短时间内耗尽基于整数的 ID 的供应,这进一步支持了为什么这种事情是浪费时间和资源的论点。

      【讨论】:

      • 我同意你的观点,不鼓励 OP 认为有必要保持 ID 连续,但他的问题很明显这是他的意图。因此,这并不是真正的答案。更像是一个长评论。
      • 好吧,我们不应该仅仅因为有人想做某事而盲目回答问题。我更愿意鼓励其他人使用良好的做法,以期提高他们的手艺。抱歉,你不得不为此投反对票——这不太公平。如果我告诉你如何因为你想跳桥,即使我告诉你你会死,你愿意吗?那不是很聪明。
      猜你喜欢
      • 2023-03-21
      • 2017-09-17
      • 2022-01-04
      • 2015-05-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-12
      • 2022-11-15
      • 1970-01-01
      相关资源
      最近更新 更多