[英]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? 如何在查询中添加最小值?
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)
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
;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.