SQL从min开始按顺序查找缺失的数字?

时间:2014-08-29 09:39:23

标签: sql oracle

我找到了几个SQL查询示例,它们会在序列中找到缺少的数字。例如这一个:

Select T1.val+1 
from table T1 
where not exists(select val from table T2 where T2.val = T1.val + 1);

这只能找到现有序列中的空白。我想从最小值开始找到序列中的间隙。

例如,如果我的序列中的值是2,4,那么上面的查询将返回3,5。

我想指定我的序列必须从0开始,所以我希望查询返回0,1,3,5。

如何在查询中添加最小值?

  • 以下问题的几个答案:
    • 没有最大值,只有最小值
    • 数据库是oracle

3 个答案:

答案 0 :(得分:5)

在Postgres中这很容易:

select x.i as missing_sequence_value
from (
   select i
   from generate_series(0,5) i -- 0,5 are the lower and upper bounds you want
) x
  left join the_table t on t.val = x.i 
where t.val is null;

SQLFiddle:http://www.sqlfiddle.com/#!15/acb07/1

修改

Oracle解决方案有点复杂,因为生成数字需要一个解决方法

with numbers as (
   select level - 1 as val
   from dual
   connect by level <= (select max(val) + 2 from the_table) -- this is the maximum
), number_range as (
   select val
   from numbers 
   where val >= 0 -- this is the minimum
)
select nr.val as missing_sequence_value
from number_range nr
  left join the_table t on t.val = nr.val
where t.val is null;

SQLFiddle:http://www.sqlfiddle.com/#!4/71584/4

这个想法(在两种情况下)都是生成一个您感兴趣的数字列表(从0到5),然后对表中的值进行外连接。外部联接不会从表中返回某些内容的行(条件where t.val is null)是缺少的值。

Oracle解决方案需要两个常用的表表达式(&#34; CTE&#34;,&#34;有&#34;事物),因为您无法在第一个CTE中添加where level >= x产生数字。

请注意,connect by level <= ...依赖于使用connect by的未记录(且不受支持)的方式。但是有这么多人正在使用它来获得一个数字生成器&#34;我怀疑Oracle实际上会删除它。

答案 1 :(得分:2)

如果您必须选择使用common table expression,您可以生成一系列数字并将其用作数字来源。

变量@start@end定义数字的范围(您可以轻松地使用来自yourtable的max(val)作为结束。)

此示例适用于MS SQL Server(但CTE是许多数据库支持的SQL 99功能):

declare @start int, @end int
select @start=0, @end=5

;With sequence(num) as
(
    select @start as num
        union all
    select num + 1
        from sequence
        where num < @end
)

select * from sequence seq
where not exists(select val from YourTable where YourTable.val = seq.num)
Option (MaxRecursion 1000)

Sample SQL Fiddle

答案 2 :(得分:2)

仅针对上述建议提出两个小变体,两者都适用于Oracle。


首先是jpw使用recursive公用表格表达式(CTE)呈现的小变体;只是为了证明这种技术在Oracle中也可用。

WITH
      seq (val)
      AS (
            SELECT 0 FROM dual
            UNION ALL
                  SELECT val + 1
                  FROM seq
                  WHERE val < (
                              SELECT MAX(val) FROM the_table -- note below
                              )
            )
SELECT
      seq.val AS missing_sequence_value
FROM seq
      LEFT JOIN the_table t
                  ON seq.val = t.val
WHERE t.val IS NULL
ORDER BY
      missing_sequence_value
;

This variation at SQLfiddle

与SQL Server的显着区别:您可以使用子查询来限制递归

此外,Oracle文档通常引用子查询因子,例如subquery_factoring_clause::=代替CTE


其次是a_horse_with_no_name

使用按级别连接的变体

Level是Oracle hierarchical queries中可用的伪列,层次结构的根是1.当按层次使用连接时,默认情况下这将从1开始

对于这种变化,我只是希望证明它根本不需要与CTE结合,因此语法可以非常简洁。

SELECT
      seq.val AS missing_sequence_value
FROM (
            SELECT
                  level - 1 AS val
            FROM dual
            CONNECT BY LEVEL <= (SELECT max(val) FROM the_table)
      ) seq
      LEFT JOIN the_table t
                  ON seq.val = t.val
WHERE t.val IS NULL
ORDER BY
      missing_sequence_value
;

This variation at SQLfiddle