如何在 Oracle 中找到两个大小范围之间缺失的大小范围?

Posted

技术标签:

【中文标题】如何在 Oracle 中找到两个大小范围之间缺失的大小范围?【英文标题】:How to find the missing size range between two size ranges in Oracle? 【发布时间】:2020-04-26 15:00:26 【问题描述】:

我想验证两个尺寸范围之间缺少的尺寸范围。例如,现在我有一个名为 AQL 的表,其中包含以下列:

    ID  TYPE        SIZE_FROM  SIZE_TO
    --  ----------  ---------  -------
    68  NORMAL      2          150
    69  NORMAL      501        1200
    70  REDUCED     1201       3200
    71  REDUCED     151        500

我需要找出缺失的范围:

    TYPE       SIZE_FROM  SIZE_TO
    ---------  ---------  -------
    NORMAL     151        500
    REDUCED    2          150
    REDUCED    501        1200

我已经处理了重叠,那么我应该怎么做才能选择以下缺失的范围?

【问题讨论】:

不太清楚如何识别范围。查看预期的输出,带有过滤条件的 where 子句似乎很简单。 真的只是用where子句找出范围吗?怎么样? 当您说范围时,您的实际意思是什么?当你说范围时,我看不到任何相关性。 比如1-5, 11-15, 16-20, 26-30,所以我想找出缺失的范围是从6到10和从21到25。这是我的意思。 在这种情况下REDUCED 501 1200 应该是NORMAL 501 1200.. 不是吗?你也改变了类型。 【参考方案1】:

select ... from dual connect by level <= 语法可用于在每种类型的极值之间生成行,并且在再次为每种类型的每个范围( size_from 和 size_to )之间按行生成整数之后,通过使用 left join 消除这些行通过使用上述语法:

with  aql2 as
(
 select type, min(size_from) as size_from , max(size_to) as size_to
   from aql
  group by type
)
select a2.type, min(a2.lvl) as size_from, max(a2.lvl) as size_to
  from (select a2.type, a2.size_from + level - 1 as lvl
          from aql2 a2
         cross join dual d
        connect by level <= a2.size_to - a2.size_from + 1
            and prior a2.type =a2.type
            and prior sys_guid() is not null) a2
  left join (select distinct a.type, a.size_from + level - 1 as lvl
               from aql a
              cross join dual d
             connect by level <= a.size_to - a.size_from + 1
              group by a.type, a.size_from + level - 1) a
    on a2.type = a.type
   and a2.lvl = a.lvl 
 where a.lvl is null
 group by a2.type  

Demo

【讨论】:

我试过你的代码,但是加载数据花了很长时间,仍然没有检索到数据。【参考方案2】:

对于示例数据,看看这是否有帮助(在代码中读取 cmets):

SQL> with
  2  aql (id, type, size_from, size_to) as
  3    -- Your current data
  4    (select 68, 'NORMAL' ,   2,  150  from dual union all
  5     select 69, 'NORMAL' ,  501, 1200 from dual union all
  6     select 70, 'REDUCED', 1201, 3200 from dual union all
  7     select 71, 'REDUCED',  151,  500 from dual
  8    ),
  9  existing_sizes as
 10    -- list all existing sizes, one-by-one, per type
 11    (select  type, size_from + column_value - 1 csize
 12     from aql cross join table(cast(multiset(select level from dual
 13                                             connect by level <= size_to - size_from + 1
 14                                            ) as sys.odcinumberlist))
 15    ),
 16  minmax as
 17    -- find MIN and MAX size valze per type - will be used in ALLSIZES CTE
 18    (select type, min(size_from) size_from, max(size_to) size_to
 19     from aql
 20     group by type
 21    ),
 22  allsizes as
 23    -- list all sizes (per type) between MIN and MAX value
 24    (select type, size_from + column_value - 1 csize
 25     from minmax cross join table(cast(multiset(select level from dual
 26                                                connect by level <= size_to - size_from + 1
 27                                               ) as sys.odcinumberlist))
 28    ),
 29  missing_sizes as
 30    -- missing sizes can be found with MINUS set operator
 31    (select a.type, a.csize from allsizes a
 32     minus
 33     select e.type, e.csize from existing_sizes e
 34    )
 35  -- the final result
 36  select type, min(csize) size_from, max(csize) size_to
 37  from missing_sizes
 38  group by type;

TYPE     SIZE_FROM    SIZE_TO
------- ---------- ----------
NORMAL         151        500
REDUCED        501       1200

SQL>

但是,如果涉及更多差距,这将失败(但这不是您的示例数据所暗示的)。

【讨论】:

是的,你说得对,我特意为 Normal Type 添加了另一条记录,它只是可以检索第一个缺失的间隙。

以上是关于如何在 Oracle 中找到两个大小范围之间缺失的大小范围?的主要内容,如果未能解决你的问题,请参考以下文章

如何在数组中找到两个缺失值? [复制]

如何在两个表之间找到缺失的代码?

MySQL:查找日期范围之间的缺失日期

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

如何获取日期范围内的缺失值?

SQL Challenge ——快速找到1-100之间缺失的数