简体   繁体   English

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

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

I have found several examples of SQL queries which will find missing numbers in a sequence. 我找到了几个SQL查询的例子,它们会在序列中找到缺失的数字。 For example this one: 例如这一个:

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

This will only find gaps in an existing sequence. 这只会在现有序列中找到空白。 I would like to find gaps in a sequence starting from a minimum. 我想从最小值开始找到序列中的间隙。

For example, if the values in my sequence are 2, 4 then the query above will return 3,5. 例如,如果我的序列中的值是2,4,那么上面的查询将返回3,5。

I would like to specify that my sequence must start at 0 so I would like the query to return 0,1,3,5. 我想指定我的序列必须从0开始,所以我希望查询返回0,1,3,5。

How can I add the minimum value to my query? 如何在查询中添加最小值?

  • A few answers to questions below: 以下问题的几个答案:
    • There is no maximum, only a minimum 没有最大值,只有最小值
    • The DB is oracle DB是oracle

This is quite easy in Postgres: 这在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 SQLFiddle: http ://www.sqlfiddle.com/#!15 / acb07 / 1

Edit 编辑

The Oracle solution is a bit more complex because generating the numbers requires a workaround 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 SQLFiddle: http ://www.sqlfiddle.com/#!4/71584/4

The idea (in both cases) is to generate a list of numbers you are interested in (from 0 to 5) and then doing an outer join against the values in your table. 这个想法(在两种情况下)都是生成一个您感兴趣的数字列表(从0到5),然后对表中的值进行外连接。 The rows where the outer join does not return something from your table (that's the condition where t.val is null ) are the values that are missing. 外连接不从表中返回某些内容的行(这是where t.val is null的条件)是缺少的值。

The Oracle solution requires two common table expressions ("CTE", the "with" things) because you can't add a where level >= x in the first CTE that generates the numbers. Oracle解决方案需要两个公用表表达式(“CTE”,“with”事物),因为您无法在生成数字的第一个CTE中添加where level >= x

Note that the connect by level <= ... is relies on an undocumented (and unsupported) way of using connect by . 请注意, connect by level <= ...依赖于使用connect by的未记录(且不受支持)的方式。 But so many people are using that to get a "number generator" that I doubt that Oracle will actually remove this. 但是有这么多人使用它来获得一个“数字生成器”,我怀疑Oracle实际上会删除它。

If you have to option to use a common table expression you can generate a sequence of numbers and use that as the source of numbers. 如果必须选择使用公用表表达式 ,则可以生成一系列数字并将其用作数字源。

The variables @start and @end defines the range of numbers (you could easily use max(val) from yourtable as end instead). 变量@start@end定义了数字的范围(您可以轻松地使用来自yourtable的max(val)作为结束)。

This example is for MS SQL Server (but CTEs is a SQL 99 feature supported by many databases): 此示例适用于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 示例SQL小提琴

Just presenting 2 small variations to suggestions above, both are for Oracle. 只是为上面的建议提出了2个小变化,两者都是针对Oracle的。


First is a small variation to one presented by jpw using a recursive Common Table Expression (CTE); 首先是jpw使用递归公用表表达式(CTE)呈现的小变化; simply to demonstrate that this technique is also available in Oracle. 只是为了证明这种技术在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 SQLfiddle的这种变化

Notable difference to SQL Server: you can use a subquery to limit the recursion 与SQL Server的显着区别:您可以使用子查询来限制递归

Also, Oracle documentation often refers to Subquery Factoring eg subquery_factoring_clause::= instead of CTE 此外,Oracle文档通常引用子查询因子,例如subquery_factoring_clause::=而不是CTE


Second is a variation on the use of connect by level as used by a_horse_with_no_name 第二个是a_horse_with_no_name使用的按级别连接的使用的a_horse_with_no_name

Level is a pseudo column available in Oracle's hierarchical queries and the root of a hierarchy is 1. When using connect by level, by default this will commence at 1 Level是Oracle的分层查询中可用的伪列, 层次结构的根是1.当按级别使用connect时,默认情况下这将从1开始

For this variation I just wished to demonstrate that it does not need to be coupled with CTE's at all, and hence the syntax can be quite concise. 对于这种变化,我只是希望证明它根本不需要与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 SQLfiddle的这种变化

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

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