Oracle - 沿间隔分组值

Posted

技术标签:

【中文标题】Oracle - 沿间隔分组值【英文标题】:Oracle - grouping values along interval 【发布时间】:2016-12-20 12:52:55 【问题描述】:

我需要查询一个表,其中包含一个步骤 id + 值。 结果将列出间隔及其相关值。 这里的区间被定义为“步骤的连续 id 的连续,共享相同的数据值”。

我很难用语言来描述它,所以请看这个:

从这张表

  Step ! Data
  ------------
   1   !  A
   2   !  A
   3   !  A
   5   !  A
   6   !  B
  10   !  A

我需要以下报告

  From ! To   ! Data
  -------------------
     1 !   3  !   A
     5 !   5  !   A
     6 ! null !   B
    10 ! null !   A

我认为lead() 会在这里帮助我,但没有成功。

【问题讨论】:

似乎数据是针对值 A 和 B 分别考虑的?那么:为什么该行的结果是 (5, 5),然后是 (6, NULL) 而不是 (6, 6)? 哦...所以,对于每个“数据”值的最后一次出现,间隔应该是开放式的,但所有其他间隔都是“封闭式”的? 你说得对,这还是有点过度指定:“To”值显示为“From”而不是 NULL 是完全可以接受的 如果我们也有A ! 11,您希望最后一个范围是 '10 吗?空`或`10! 11'? 【参考方案1】:
select      min (step)                                                   as "from"
           ,nullif (max (step),max(min(step)) over (partition by data))  as "to"
           ,data

from       (select      step,data
                       ,row_number () over (partition by data order by step) as n

            from        t
            ) 

group by    data
           ,step - n            

order by    "from"           

【讨论】:

样本结果,不应该是5 ! null ! A而不是5 ! 5 ! A吗? NULL 仅表示最后一个开放区间。正如你所看到的,对于值 A,一个新的间隔从第 10 步开始,这就是为什么从 5 开始的间隔也在那里结束。 请加'A! 11`到结果集,然后比较解决方案 非常感谢@Dudu Markovitz,您的解决方案完全满足了我最初的需求——空值确实为开放式区间带来了有用的信息。【参考方案2】:

您可以通过生成一个数字序列并从step 中减去来做到这一点。当值是连续的时,这将是一个常量:

select min(step) as from_step, max(step) as to_step, data
from (select t.*,
            row_number() over (partition by data order by step) as seqnum
     from t
    ) t
group by (step - seqnum), data;

编辑:

尚不清楚NULLs 的来源。如果我推测它们是每个值的最后一个值,您可以这样做:

select min(step) as from_step,
       (case when max(step) <> max_step then max(step) end) as to_step,
       data
from (select t.*,
             max(step) over (partition by data) as max_step
             row_number() over (partition by data order by step) as seqnum
     from t
    ) t
group by (step - seqnum), data, max_step;

【讨论】:

OP没有解释得很好,但是数据似乎是按值分区的(看步骤5-6)。 @mathguy 。 . .这就是这个解决方案的作用。 @GordonLinoff 不应该 row_numberpartition by data 或者至少在 order 克劳斯中使用 data 哇,这速度又快又高效 data 放入row_number() 绝对是一种选择。在这种情况下不需要这样做,因为这些步骤似乎是一个单调递增的序列。

以上是关于Oracle - 沿间隔分组值的主要内容,如果未能解决你的问题,请参考以下文章

在 Oracle 中对重叠的时间间隔进行分组

如何在 Oracle SQL 上进行查询以获取时间间隔,按特定字段分组

oracle语句 根据操作时间分组

如何将时间列分别分组为 5 分钟间隔和最大值/最小值 SQL?

在 Oracle SQL 中按时间间隔聚合数据

按 15 分钟间隔对 mysql 查询进行分组