如何对由任意表达式描述的事件进行分组/窗口日期排序?

Posted

技术标签:

【中文标题】如何对由任意表达式描述的事件进行分组/窗口日期排序?【英文标题】:How can I group / window date ordered events delineated by an arbitrary expression? 【发布时间】:2016-05-10 17:46:52 【问题描述】:

我想根据日期和一些(可能是任意的)指标将一些数据组合在一起:

Date       | Ind
================
2016-01-02 | 1
2016-01-03 | 5
2016-03-02 | 10
2016-03-05 | 15
2016-05-10 | 6
2016-05-11 | 2

我想将后续(按日期排序)行组合在一起,但在 Indicator >= 10 之后打破组:

Date       | Ind | Group
========================
2016-01-02 | 1   |   1
2016-01-03 | 5   |   1
2016-03-02 | 10  |   1

2016-03-05 | 15  |   2

2016-05-10 | 6   |   3
2016-05-11 | 2   |   3

我确实在博客文章的末尾找到了一种很有前途的技术:“Use this Neat Window Function Trick to Calculate Time Differences in a Time Series”(最后一个小节,“额外奖励”),但查询的重要部分使用了一个关键字 (FILTER) '似乎在 SQL Server 中不受支持(稍后快速谷歌,我不确定它在哪里支持!)。

我仍然希望使用窗口函数的技术可能是答案。我只需要一个可以添加到每一行的计数器(就像RANKROW_NUMBER 一样),但只有在某些任意条件评估为true 时才会增加。有没有办法在 SQL Server 中做到这一点?

【问题讨论】:

指标是什么,如何计算? 这不是真实数据(我知道,我知道)。实际上,我正在使用LEAD() 计算后续日期之间的差距,并且我想在差距大于特定值(例如 30 天)时划分组。出于求知欲/未来灵活性的原因,我希望得到一个适用于一般情况的答案(即“指标”可以是任意真/假表达式)。 【参考方案1】:

解决办法如下:

DECLARE @t TABLE ([Date] DATETIME, Ind INT)

INSERT INTO @t 
VALUES
('2016-01-02', 1),
('2016-01-03', 5),
('2016-03-02', 10),
('2016-03-05', 15),
('2016-05-10', 6),
('2016-05-11', 2)

SELECT [Date],
       Ind,
       1 + SUM([Group]) OVER(ORDER BY [Date]) AS [Group]
FROM 
(
    SELECT  *, 
            CASE WHEN LAG(ind) OVER(ORDER BY [Date]) >= 10 
                THEN 1 
                ELSE 0 
            END AS [Group] 
      FROM @t
) t

当前一个大于10 时,只需将行标记为1,否则标记为0。然后运行总和将为您提供所需的结果。

【讨论】:

不应该花这么多时间来格式化我的答案。好吧,这几乎与日期差异检查相同:sqlfiddle.com/#!6/162ab/1 @JamesZ,几乎一样:) 我非常喜欢你的回答,所以我用更易于阅读的格式对其进行了编辑(至少对我而言)。希望你不要介意! 谢谢!非常简洁,比我担心的要简单得多(实际上几乎令人尴尬),甚至结合了我的示例编号系统和选择不当的列名:)【参考方案2】:

将这个想法完全归功于 Giorgi,但我修改了他的答案(为了我的利益和未来的读者)。

只需更改 CASE 语句即可查看自上次记录以来是否已过去 30 天或更长时间:

DECLARE @t TABLE ([Date] DATETIME)

INSERT INTO @t 
VALUES
('2016-01-02'),
('2016-01-03'),
('2016-03-02'),
('2016-03-05'),
('2016-05-10'),
('2016-05-11')

SELECT [Date],
       1 + SUM([Group]) OVER(ORDER BY [Date]) AS [Group]
FROM 
(
    SELECT  [Date], 
            CASE WHEN DATEADD(d, -30, [Date]) >= LAG([Date]) OVER(ORDER BY [Date])
                THEN 1 
                ELSE 0 
            END AS [Group] 
      FROM @t
) t

【讨论】:

感谢您关注我的实际需求:为您点赞。显然,Giorgi 回答了所提出的问题,并且(如承认的那样)启发了您的回答。

以上是关于如何对由任意表达式描述的事件进行分组/窗口日期排序?的主要内容,如果未能解决你的问题,请参考以下文章

如何对 JSON 项目进行排序/分组

BigQuery:如何在滚动时间戳窗口内对行进行分组和计数?

当子窗口具有递增值时如何增加父组编号?

如何在 SQL 中按多列分组并按日期排序?

分组日期之间的间隔

Mongodb:按元素分组并根据条件显示子文档计数并按日期对文档进行排序