我最近继承了一个数据库,其中一个表的主键由编码值组成(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扩展。
答案 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;