繁体   English   中英

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

[英]SQL to find missing numbers in sequence starting from min?

我找到了几个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。

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

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

这在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解决方案需要两个公用表表达式(“CTE”,“with”事物),因为您无法在生成数字的第一个CTE中添加where level >= x

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

如果必须选择使用公用表表达式 ,则可以生成一系列数字并将其用作数字源。

变量@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)

示例SQL小提琴

只是为上面的建议提出了2个小变化,两者都是针对Oracle的。


首先是jpw使用递归公用表表达式(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
;

SQLfiddle的这种变化

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

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


第二个是a_horse_with_no_name使用的按级别连接的使用的a_horse_with_no_name

Level是Oracle的分层查询中可用的伪列, 层次结构的根是1.当按级别使用connect时,默认情况下这将从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
;

SQLfiddle的这种变化

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM