想象一下如下表所示:
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等的查询?
答案 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视为不可变且任意。如果你真的要求它是无间隙的,不要使用身份并且永远不要进行硬删除(即如果你需要停用一行,你需要一个列,说明它是否有效)。