如何计算条纹长度?

问题描述 投票:0回答:2

我有以下数据:

date          unit     status
2023-04-30    unit1    1
2023-05-31    unit1    1
2023-08-31    unit1    1
2023-09-30    unit1    1
2023-11-30    unit1    1
2023-12-31    unit1    1
2024-01-31    unit1    1
2024-02-28    unit1    1

作为参考日期,我想知道第一个即将到来的“streak”的长度(在 MSSQL 上,用于生产,在 sqlite 上,用于单元测试)

示例1:

对于日期2023-05-15我想要的输出是:

unit     streak
unit1    3

这样做的原因是2023-05之后第一个月status=1是2023-08,然后我只统计每个连续的月份。

示例2:

对于日期2023-11-01我想要的输出是:

unit     streak
unit1    3

原因是 2023-11 后第一个 status=1 的月份是 2023-12,并且连续在 2024-02 结束,因为 status=0 的月份没有记录,下一个 status=1 的月份多于还有一个月。

sql sql-server sqlite window-functions consecutive-months
2个回答
1
投票

对于 SQL Server 和 SQLite,计算 streak 需要结合使用公共表表达式 (CTE)、窗口函数和联接。让我们来解决这个问题:

SQL Server 解决方案:

WITH RankedData AS (
    SELECT [date], [unit], [status],
           ROW_NUMBER() OVER (PARTITION BY [unit] ORDER BY [date]) - 
           MONTH([date]) AS GroupingID
    FROM YourTableName
    WHERE [date] > '2023-05-15' AND [status] = 1
)
SELECT TOP 1 [unit], COUNT(*) AS streak
FROM RankedData
GROUP BY [unit], GroupingID
ORDER BY MIN([date]);

SQLite 解决方案: SQLite 缺乏 SQL Server 的一些高级窗口功能,但您可以通过连接和子查询实现类似的效果:

WITH RankedData AS (
    SELECT [date], [unit], [status],
           strftime('%m', [date]) + 0 - (ROW_NUMBER() OVER (PARTITION BY [unit] ORDER BY [date])) AS GroupingID
    FROM YourTableName
    WHERE [date] > '2023-05-15' AND [status] = 1
)
SELECT [unit], COUNT(*) AS streak
FROM RankedData
GROUP BY [unit], GroupingID
ORDER BY MIN([date])
LIMIT 1;

这些脚本应提供给定参考日期的第一个即将到来的连续的长度。只需根据需要调整 WHERE 子句中的日期即可。


1
投票

这是一个

gaps and islands
问题,可以通过(值减去row_number)来解决,因为它在连续序列中是不变的。开始和结束日期只是该组的 MIN() 和 MAX() :

with cte as (
  SELECT  *, GroupingSet = FORMAT(DATEADD(
                             MONTH, - ROW_NUMBER() OVER(PARTITION BY unit ORDER BY [date]), 
                             [date]
                           ), 'yyyy-MM-01')
  FROM    mytable
  WHERE MONTH([date]) > MONTH('2023-05-15') AND [status] = 1
)
SELECT  TOP 1 unit,
        StartDate = MIN([date]),
        EndDate = MAX([date]),
        streak = COUNT(*)
FROM    CTE
GROUP BY unit, GroupingSet
ORDER BY StartDate;

注意:给出的日期已转换为该月的第一天,因此 GroupingSet 可以在同一个月内匹配!

演示在这里

© www.soinside.com 2019 - 2024. All rights reserved.