SQL中的相干间隔?

Posted

技术标签:

【中文标题】SQL中的相干间隔?【英文标题】:Coherent intervals in SQL? 【发布时间】:2021-04-22 09:11:38 【问题描述】:

考虑一个简单的日记表:

 Date   Mood
 ----   ----
 1      Good
 2      Good
 3      Good
 4      Bad
 5      Bad
 6      Good

我对情绪间隔感兴趣,所以我会得到如下结果:

 Mood   BeginDate   EndDate
 ----   ---------   -------
 Good   1           3
 Bad    4           5 
 Good   6           6

在不使用迭代的情况下,这在 SQL 中是否可行?

【问题讨论】:

SQL 中几乎不需要迭代。这种类型的问题称为gaps and islands 问题。您正在尝试识别具有相同 mood 值的范围/岛 @PanagiotisKanavos 谢谢!这是确切的一般问题,我试图通过举例来解决。 【参考方案1】:

如果你从每个心情开始的天数中减去一个序列号,当值相邻时你会得到一个常数:

 Date   Mood    Seqnum
 1      Good       1
 2      Good       2
 3      Good       3
 4      Bad        1
 5      Bad        2
 6      Good       4

然后你可以使用聚合来做你想做的事。如果date 真的是一个数字:

select mood, min(date), max(date)
from (select t.*,
             row_number() over (partition by mood order by date) as seqnum
      from t
     ) t
group by mood, (date - seqnum);

如果date 真的是date

select mood, min(date), max(date)
from (select t.*,
             row_number() over (partition by mood order by date) as seqnum
      from t
     ) t
group by mood, dateadd(day, - seqnum, date)

【讨论】:

明确的答案。谢谢你。据我所知,这被认为是 SQL 中的间隙和孤岛问题的一般方法。 @Mal 。 . .没有“通用”的方法。对于问题的不同变体,有一系列不同的解决方案。认为存在“1”的差距和孤岛问题完全是一种误解。【参考方案2】:

回应 Gordon Linoff 回答中的此评论:

如果date 真的是一个数字:

如果它不是怎么办?您还有前进的道路,只需稍作调整即可。

WITH d AS (
    SELECT * FROM (VALUES
        (cast('2021-04-22 00:00' as datetime2(0)), 'Good'),
        (cast('2021-04-22 00:05' as datetime2(0)), 'Good'),
        (cast('2021-04-22 00:07' as datetime2(0)), 'Good'),
        (cast('2021-04-22 00:10' as datetime2(0)), 'Bad'),
        (cast('2021-04-22 00:25' as datetime2(0)), 'Bad'),
        (cast('2021-04-22 01:43' as datetime2(0)), 'Good')
    ) AS x([date], mood)        
), t AS (
    SELECT *, 
        ROW_NUMBER() OVER (ORDER BY [date]) AS a,
        ROW_NUMBER() OVER (PARTITION BY mood ORDER BY [date]) AS seqnum
    FROM d
)
select mood, min(date), max(date)
from t
group by mood, a - seqnum
order by min(date)

分解一下,第一个 cte 只是您的数据,但现在使用日期时间列而不是 date 的整数。请注意,连续行之间的间隔不是恒定的(可以,但我这样做是为了表明它不需要是)。从那里,我们使用row_number() 函数计算两个值——一个枚举整个集合,另一个按心情分区。其余部分(在精神上)与 Gordon 的回答相同。

【讨论】:

我实际上在我的实际问题中最终做到了这一点,但 Gordon 的回答帮助我理解了解决方案并得出了相同的结论。基本上我需要了解PARTITION 和相关的观察,即相邻行具有恒定的行数差异。 当然。以上内容旨在帮助其他人在他们的数据不如您提供的示例数据整洁的情况下。干杯!

以上是关于SQL中的相干间隔?的主要内容,如果未能解决你的问题,请参考以下文章

从 Sql 中的表中选择不同的日期间隔

根据一列/SQL Oracle 中的值创建时间间隔

Databricks SQL - 间隔中的最大同时事件计数

如何使用间隔 1 分钟在两个日期之间将时间序列数据生成到 Oracle PL/SQL 中的表中?

pyspark中的间隔类型

SQL:仅选择以给定间隔与其他结果分隔的值的行