如何在oracle中将数字丢失100s

Posted

技术标签:

【中文标题】如何在oracle中将数字丢失100s【英文标题】:How to missing numbers by 100s in oracle 【发布时间】:2020-11-06 09:23:22 【问题描述】:

我需要在 oracle 的表格列中查找缺失的数字,其中缺失的数字必须取 100s ,这意味着如果在 2000 和 2099 之间找到至少 1 个数字,则 2000 和 2099 之间的所有缺失数字必须是返回等等。

这是一个说明我需要什么的例子:

create table test1 ( a number(9,0));

insert into test1 values (2001);
insert into test1 values (2002);
insert into test1 values (2004);
insert into test1 values (2105);
insert into test1 values (3006);
insert into test1 values (9410);
commit;

结果必须是 2000,2003,2005 到 2099,2100 到 2104,2106 到 2199,3000 到 3005,3007 到 3099,9400 到 9409,9411 到 9499。

我从这个查询开始,但它显然没有返回我需要的内容:

SELECT Level+(2000-1) FROM dual  CONNECT BY LEVEL  <= 9999 
MINUS SELECT a FROM test1;

【问题讨论】:

是否有确定最低(2000)和最高(9499)值的逻辑......? 【参考方案1】:

您可以按如下方式使用层次结构查询:

SQL> SELECT A FROM (
  2  SELECT A + COLUMN_VALUE - 1 AS A
  3    FROM ( SELECT DISTINCT TRUNC(A, - 2) A
  4         FROM TEST_TABLE) T
  5   CROSS JOIN TABLE ( CAST(MULTISET(
  6  SELECT LEVEL FROM DUAL CONNECT BY LEVEL <= 100
  7     ) AS SYS.ODCINUMBERLIST) ) LEVELS
  8  )
  9  MINUS
 10  SELECT A FROM TEST_TABLE;

         A
----------
      2000
      2003
      2005
      2006
      2007
      2008
      2009
.....
.....

【讨论】:

您不需要表集合表达式,只需CROSS JOIN 查询即可。 db<>fiddle【参考方案2】:

假设你为范围定义了固定的上下界,那么只需要使用NOT EXISTS来消除当前查询的结果如

SQL> exec :min_val:=2000
SQL> exec :min_val:=2499
SQL> SELECT *
       FROM
       (
        SELECT level + :min_val - 1 AS nr
          FROM dual        
       CONNECT BY level <= :max_val - :min_val + 1
       )
      WHERE NOT EXISTS ( SELECT * FROM test1 WHERE a = nr ) 
      ORDER BY nr;
      /

Demo

【讨论】:

【参考方案3】:

我喜欢为此使用标准递归查询。

with nums (a, max_a) as (
    select min(a), max(a) from test1
    union all 
    select a + 1, max_a from nums where a < max_a
)
select n.a
from nums n
where not exists (select 1 from test1 t where t.a = n.a)
order by n.a

with 子句取表中a 的最小值和最大值,并生成两者之间的所有数字。然后,外部查询过滤表中不存在的那些。

如果你想生成缺失数字的范围而不是一个完整的列表,你可以使用窗口函数来代替:

select a + 1 start_a, lead_a - 1 end_a
from (
    select a, lead(a) over(order by a) lead_a
    from test1
) t
where lead_a <> a + 1

Demo on DB Fiddle


编辑

如果您希望缺失值在数千范围内,那么我们可以稍微调整递归解决方案:

with nums (a, max_a) as (
    select distinct floor(a / 100) * 100 a, floor(a / 100) * 100 + 100 from test1
    union all 
    select a + 1, max_a from nums where a < max_a
)
select n.a
from nums n
where not exists (select 1 from test1 t where t.a = n.a)
order by n.a

【讨论】:

以上是关于如何在oracle中将数字丢失100s的主要内容,如果未能解决你的问题,请参考以下文章

如何在sql中将数字转换为日期

如何在没有外部库的任何lua中将双精度转换为小字符串表示而不会丢失数据?

在Oracle数据库中将一个14位的数字转化为一个完整的日期时间

如何在JavaScript中将值为1.10的数字转换为无损浮点值[重复]

如何在带有彩色条的格式表中将数字显示为美元金额

如何在Oracle中将表行拆分为固定大小的块