如何在表格中找到“洞”

时间:2008-10-06 14:33:00

标签: sql

我最近继承了一个数据库,其中一个表的主键由编码值组成(Part1 * 1000 + Part2)。
我将该列标准化,但我无法更改旧值。 所以现在我有了

select ID from table order by ID
ID
100001
100002
101001
...

我希望在新表格中找到表格中的“洞”(更确切地说,是100000之后的第一个“洞”)。
我正在使用以下选择,但是有更好的方法吗?

select /* top 1 */ ID+1 as newID from table
where ID > 100000 and
ID + 1 not in (select ID from table)
order by ID

newID
100003
101029
...

数据库是Microsoft SQL Server 2000.我可以使用SQL扩展。

10 个答案:

答案 0 :(得分:15)

select ID +1 From Table t1
where not exists (select * from Table t2 where t1.id +1 = t2.id);

不确定此版本是否会比您原先提到的版本更快。

答案 1 :(得分:9)

SELECT (ID+1) FROM table AS t1
LEFT JOIN table as t2
ON t1.ID+1 = t2.ID
WHERE t2.ID IS NULL

答案 2 :(得分:5)

此解决方案应该为您提供您正在寻找的“洞”的第一个和最后一个ID值。我在Firebird 1.5中使用这个在500K记录的表上,尽管它需要一段时间,但它给了我想要的东西。

SELECT l.id + 1 start_id, MIN(fr.id) - 1 stop_id
FROM (table l
LEFT JOIN table r
ON l.id = r.id - 1)
LEFT JOIN table fr
ON l.id < fr.id
WHERE r.id IS NULL AND fr.id IS NOT NULL
GROUP BY l.id, r.id

例如,如果您的数据如下所示:

ID
1001
1002
1005
1006
1007
1009
1011

你会收到这个:

start_id   stop_id
1003       1004
1008       1008
1010       1010

我希望我可以完全赞同这个解决方案,但我在Xaprb找到了它。

答案 3 :(得分:1)

来自How do I find a "gap" in running counter with SQL?

select
    MIN(ID)
from (
    select
        100001 ID
    union all
    select
        [YourIdColumn]+1
    from
        [YourTable]
    where
        --Filter the rest of your key--
    ) foo
left join
    [YourTable]
    on [YourIdColumn]=ID
    and --Filter the rest of your key--
where
    [YourIdColumn] is null

答案 4 :(得分:1)

最好的方法是构建一个包含所有ID的临时表

比左连接。

declare @maxId int
select @maxId = max(YOUR_COLUMN_ID) from YOUR_TABLE_HERE


declare @t table (id int)

declare @i int
set @i = 1

while @i <= @maxId
begin
    insert into @t values (@i)
    set @i = @i +1
end

select t.id
from @t t
left join YOUR_TABLE_HERE x on x.YOUR_COLUMN_ID = t.id
where x.YOUR_COLUMN_ID is null

答案 5 :(得分:1)

最近考虑过这个问题,看起来这是最优雅的方式:

/etc/ssh/ssh_known_hosts

答案 6 :(得分:0)

此解决方案不会在表格中给出所有漏洞,只有下一个免费的漏洞+桌面上的第一个可用最大数量 - 如果你想填写id-es中的空白,可以使用+如果你没有,可以获得免费的id号码差距..

从temp中选择numb + 1 减去 从temp中选择麻木;

答案 7 :(得分:0)

这将为您提供完整的图片,'底部'代表差距开始'顶部'代表差距端

    select *
    from 
    ( 
       (select <COL>+1 as id, 'Bottom' AS 'Pos' from <TABLENAME> /*where <CONDITION*/>
       except
       select <COL>, 'Bottom' AS 'Pos' from <TABLENAME> /*where <CONDITION>*/)
    union
       (select <COL>-1 as id, 'Top' AS 'Pos' from <TABLENAME> /*where <CONDITION>*/
       except
       select <COL>, 'Top' AS 'Pos' from <TABLENAME> /*where <CONDITION>*/)
    ) t
    order by t.id, t.Pos

注意:首先上次结果是 错误 ,不应该被视为,但将其取出会使这个查询更复杂,所以现在这样做。

答案 8 :(得分:0)

之前的许多答案都非常好。然而,他们都错过了返回序列的第一个值和/或错过了考虑下限100000.它们都返回中间孔但不是第一个(如果丢失则为100001)。

问题的完整解决方案如下:

select id + 1 as newid from
    (select 100000 as id union select id from tbl) t
    where (id + 1 not in (select id from tbl)) and
          (id >= 100000)
    order by id
    limit 1;

如果序列的第一个数字是100001,则使用数字100000(如原始问题中所示);否则需要相应修改 &#34;限制1&#34;用于仅拥有第一个可用数字而不是完整序列

答案 9 :(得分:0)

对于使用Oracle的人,可以使用以下内容:

select a, b from (
  select ID + 1 a, max(ID) over (order by ID rows between current row and 1 following) - 1 b from MY_TABLE
) where a <= b order by a desc;