查找自动递增值中的间隙

时间:2014-10-27 11:38:07

标签: sql sql-server tsql

想象一下如下表所示:

create table test (
   id int auto_increment, 
   some int, 
   columns int
)

然后这个表得到了很多使用。插入行并删除行,随着时间的推移,一旦自动递增的数量可能存在间隙。例如,如果我在某个时候进行以下查询:

select top 10 id from test

我可能会得到像

这样的东西
3
4
6
7
9
10
13
14
18
19

如何设计一个返回缺失值1,2,5,8等的查询?

3 个答案:

答案 0 :(得分:0)

最简单的方法是获取缺失值的范围

select (id + 1) as firstmissing, (nextid - 1) as lastmissing
from (select t.id, lead(id) over (order by id) as nextid
      from test t
     ) t
where nextid is not null and nextid <> id + 1;

请注意,这使用lead()函数,该函数可在SQL Server 2012+中使用。您可以使用apply或早期版本中的子查询执行类似的操作。这是一个例子:

select (id + 1) as firstmissing, (nextid - 1) as lastmissing
from (select t.id, tt.id as nextid
      from test t cross apply
           (select top 1 id
            from test t2
            where t2.id > t.id
            order by id
           ) tt
     ) t
where nextid is not null and nextid <> id + 1;

答案 1 :(得分:0)

简单的方法是使用cte ..

;WITH cte
     AS (SELECT 1 id
         UNION ALL
         SELECT id + 1 id from cte
         WHERE  id < (SELECT Max(id)
                      FROM   tablename))
SELECT *
FROM   cte
WHERE  id NOT IN(SELECT id
                 FROM   tablename) 

注意:这将从1开始。如果您想从表的最小值开始,只需替换

"SELECT 1 id" to "SELECT Min(id) id FROM   tablename"

答案 2 :(得分:0)

为什么重要?我并不是想偷偷摸摸,但这个问题通常是在“我想填补空白”或“我想压缩我的id值为连续”的背景下提出的。在任何一种情况下,答案都是“不要这样做”。在您的示例中,某个时候有一行id = 5.如果您要执行上述任一操作,您将分配一组不同的,不相关的业务数据ID。如果有任何引用数据库外部id的内容,那么现在你刚刚发明了一个之前没有的问题。对于所有意图和目的,应将id视为不可变且任意。如果你真的要求它是无间隙的,不要使用身份并且永远不要进行硬删除(即如果你需要停用一行,你需要一个列,说明它是否有效)。