如何find与SQL运行计数器“差距”?

我想find一个SQL表中的第一个“差距”在柜台列。 例如,如果有值1,2,4和5我想找出3。

我当然可以按顺序获取值并手动执行,但是我想知道是否有办法在SQL中执行此操作。

另外,它应该是相当标准的SQL,与不同的DBMS一起工作。

MySQLPostgreSQL

 SELECT id + 1 FROM mytable mo WHERE NOT EXISTS ( SELECT NULL FROM mytable mi WHERE mi.id = mo.id + 1 ) ORDER BY id LIMIT 1 

SQL Server

 SELECT TOP 1 id + 1 FROM mytable mo WHERE NOT EXISTS ( SELECT NULL FROM mytable mi WHERE mi.id = mo.id + 1 ) ORDER BY id 

Oracle

 SELECT * FROM ( SELECT id + 1 AS gap FROM mytable mo WHERE NOT EXISTS ( SELECT NULL FROM mytable mi WHERE mi.id = mo.id + 1 ) ORDER BY id ) WHERE rownum = 1 

ANSI (无处不在,效率最低):

 SELECT MIN(id) + 1 FROM mytable mo WHERE NOT EXISTS ( SELECT NULL FROM mytable mi WHERE mi.id = mo.id + 1 ) 

支持滑动窗口function的系统:

 SELECT -- TOP 1 -- Uncomment above for SQL Server 2012+ previd FROM ( SELECT id, LAG(id) OVER (ORDER BY id) previd FROM mytable ) q WHERE previd <> id - 1 ORDER BY id -- LIMIT 1 -- Uncomment above for PostgreSQL 

你的答案一切工作正常,如果你有第一个值id = 1,否则这个差距将不会被检测到。 例如,如果您的表ID值是3,4,5,您的查询将返回6。

我做了这样的事情

 SELECT MIN(ID+1) FROM ( SELECT 0 AS ID UNION ALL SELECT MIN(ID + 1) FROM TableX) AS T1 WHERE ID+1 NOT IN (SELECT ID FROM TableX) 

第一件事进入我的脑海。 不知道这样做是否是一个好主意,但应该工作。 假设表是t ,列是c

SELECT t1.c+1 AS gap FROM t as t1 LEFT OUTER JOIN t as t2 ON (t1.c+1=t2.c) WHERE t2.c IS NULL ORDER BY gap ASC LIMIT 1

编辑:这可能是一个更快的(和更短!):

SELECT min(t1.c)+1 AS gap FROM t as t1 LEFT OUTER JOIN t as t2 ON (t1.c+1=t2.c) WHERE t2.c IS NULL

这在SQL Server中工作 – 不能在其他系统中testing,但它似乎标准…

 SELECT MIN(t1.ID)+1 FROM mytable t1 WHERE NOT EXISTS (SELECT ID FROM mytable WHERE ID = (t1.ID + 1)) 

你也可以添加一个起点到where子句…

 SELECT MIN(t1.ID)+1 FROM mytable t1 WHERE NOT EXISTS (SELECT ID FROM mytable WHERE ID = (t1.ID + 1)) AND ID > 2000 

所以,如果你有2000年,2001年,2002年和2005年,2003年和2004年不存在,它将返回到2003年。

有没有一个非常标准的SQL方法来做到这一点,但有一些forms的限制条款,你可以做

 SELECT `table`.`num` + 1 FROM `table` LEFT JOIN `table` AS `alt` ON `alt`.`num` = `table`.`num` + 1 WHERE `alt`.`num` IS NULL LIMIT 1 

(MySQL,PostgreSQL)

要么

 SELECT TOP 1 `num` + 1 FROM `table` LEFT JOIN `table` AS `alt` ON `alt`.`num` = `table`.`num` + 1 WHERE `alt`.`num` IS NULL 

(SQL Server)

要么

 SELECT `num` + 1 FROM `table` LEFT JOIN `table` AS `alt` ON `alt`.`num` = `table`.`num` + 1 WHERE `alt`.`num` IS NULL AND ROWNUM = 1 

(Oracle)的

内部连接到具有所有可能值的视图或序列。

没有桌子? 制作一张桌子。 为了这个,我总是保留一张虚拟桌子。

 create table artificial_range( id int not null primary key auto_increment, name varchar( 20 ) null ) ; -- or whatever your database requires for an auto increment column insert into artificial_range( name ) values ( null ) -- create one row. insert into artificial_range( name ) select name from artificial_range; -- you now have two rows insert into artificial_range( name ) select name from artificial_range; -- you now have four rows insert into artificial_range( name ) select name from artificial_range; -- you now have eight rows --etc. insert into artificial_range( name ) select name from artificial_range; -- you now have 1024 rows, with ids 1-1024 

然后,

  select a.id from artificial_range a where not exists ( select * from your_table b where b.counter = a.id) ; 

我猜:

 SELECT MIN(p1.field) + 1 as gap FROM table1 AS p1 INNER JOIN table1 as p3 ON (p1.field = p3.field + 2) LEFT OUTER JOIN table1 AS p2 ON (p1.field = p2.field + 1) WHERE p2.field is null; 

对于PostgreSQL

一个使用recursion查询的例子。

这可能是有用的,如果你想find一个特定的范围内的差距(它将工作,即使表是空的,而其他的例子不会)

 WITH RECURSIVE a(id) AS (VALUES (1) UNION ALL SELECT id + 1 FROM a WHERE id < 100), -- range 1..100 b AS (SELECT id FROM my_table) -- your table ID list SELECT a.id -- find numbers from the range that do not exist in main table FROM a LEFT JOIN b ON b.id = a.id WHERE b.id IS NULL -- LIMIT 1 -- uncomment if only the first value is needed 

这个是迄今为止提到的一切。 它包含0作为起始点,如果不存在任何值,则默认为0。 我还为多值键的其他部分添加了适当的位置。 这只在SQL Server上进行过testing。

 select MIN(ID) from ( select 0 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 
 select min([ColumnName]) from [TableName] where [ColumnName]-1 not in (select [ColumnName] from [TableName]) and [ColumnName] <> (select min([ColumnName]) from [TableName]) 

这里是标准的SQL解决scheme,可以在所有的数据库服

 select min(counter + 1) FIRST_GAP from my_table a where not exists (select 'x' from my_table b where b.counter = a.counter + 1) and a.counter <> (select max(c.counter) from my_table c); 

参见行动

  • PL / SQL通过Oracle的livesql ,
  • MySQL通过sqlfiddle ,
  • PostgreSQL通过sqlfiddle
  • MS Sql通过sqlfiddle

它适用于空表或负值。 刚刚在SQL Server 2012中testing过

  select min(n) from ( select case when lead(i,1,0) over(order by i)>i+1 then i+1 else null end n from MyTable) w 

如果你使用火鸟3,这是最优雅和简单的:

 select RowID from ( select `ID_Column`, Row_Number() over(order by `ID_Column`) as RowID from `Your_Table` order by `ID_Column`) where `ID_Column` <> RowID rows 1