【问题标题】:Postgres windowing (determine contiguous days)Postgres 窗口化(确定连续天数)
【发布时间】:2016-05-31 05:29:43
【问题描述】:

使用 Postgres 9.3,我试图计算某种天气类型的连续天数。如果我们假设我们有定期的时间序列和天气报告:

date|weather
"2016-02-01";"Sunny"
"2016-02-02";"Cloudy"
"2016-02-03";"Snow"
"2016-02-04";"Snow"
"2016-02-05";"Cloudy"
"2016-02-06";"Sunny"
"2016-02-07";"Sunny"
"2016-02-08";"Sunny"
"2016-02-09";"Snow"
"2016-02-10";"Snow"

我想要计算同一天气的连续天数。结果应如下所示:

date|weather|contiguous_days 
"2016-02-01";"Sunny";1
"2016-02-02";"Cloudy";1
"2016-02-03";"Snow";1
"2016-02-04";"Snow";2
"2016-02-05";"Cloudy";1
"2016-02-06";"Sunny";1
"2016-02-07";"Sunny";2
"2016-02-08";"Sunny";3
"2016-02-09";"Snow";1
"2016-02-10";"Snow";2

我一直在努力尝试使用窗口函数。起初,它似乎应该是显而易见的,但后来我发现它比预期的要困难得多。

这是我尝试过的...

Select date, weather, Row_Number() Over (partition by weather order by date)
  from t_weather

将当前行与下一行进行比较会更好吗?在保持计数的同时,您将如何做到这一点?任何想法、想法甚至解决方案都会有所帮助! -基普

【问题讨论】:

  • 你不能简单地按天气做一个计数(日期)组

标签: sql postgresql window-functions gaps-and-islands


【解决方案1】:

您需要确定天气相同的连续区域。您可以通过添加分组标识符来做到这一点。有一个简单的方法:从日期中减去一个递增的数字序列,对于连续的日期它是恒定的。

一个你有分组,其余的是row_number()

Select date, weather,
       Row_Number() Over (partition by weather, grp order by date)
from (select w.*, 
             (date - row_number() over (partition by weather order by date) * interval '1 day') as grp
      from t_weather w
     ) w;

SQL Fiddle 是 here

【讨论】:

  • 这不起作用:SQL Fiddle。 (我没有投反对票。)
  • 我总是忘记 Postgres 日期算法的怪异之处。编辑有效。我想反对票本身就是恶意的。这个错误更多是代码中的错字而不是逻辑错误,逻辑应该是正确的。
  • 尝试了查询,但它不正确:row_number() 计算特定weather 的总出现次数,无需重置。例如,“Feb 5, Cloudy”应该有 row_number() 1,因为“Feb 4”是“Snow”。
  • @肯尼。 . .哎呀,子查询也应该有partition by weather
  • 啊,这很简单!可能是最有效的答案,只有两个选择。
【解决方案2】:

您可以使用递归 CTE 完成此操作,如下所示:

WITH RECURSIVE CTE_ConsecutiveDays AS
(
    SELECT
        my_date,
        weather,
        1 AS consecutive_days
    FROM My_Table T
    WHERE
        NOT EXISTS (SELECT * FROM My_Table T2 WHERE T2.my_date = T.my_date - INTERVAL '1 day' AND T2.weather = T.weather)
    UNION ALL
    SELECT
        T.my_date,
        T.weather,
        CD.consecutive_days + 1
    FROM
        CTE_ConsecutiveDays CD
    INNER JOIN My_Table T ON
        T.my_date = CD.my_date + INTERVAL '1 day' AND
        T.weather = CD.weather
)
SELECT *
FROM CTE_ConsecutiveDays
ORDER BY my_date;

这是要测试的 SQL Fiddle:http://www.sqlfiddle.com/#!15/383e5/3

【讨论】:

  • 这是几乎正确的。 (分号的位置是 Postgres 中的语句之后)
【解决方案3】:

我不确定查询引擎在对同一数据集进行多次扫描时会做什么(有点像计算曲线下的面积),但这很有效...

WITH v(date, weather) AS (
VALUES 
('2016-02-01'::date,'Sunny'::text),
('2016-02-02','Cloudy'),
('2016-02-03','Snow'),
('2016-02-04','Snow'),
('2016-02-05','Cloudy'),
('2016-02-06','Sunny'),
('2016-02-07','Sunny'),
('2016-02-08','Sunny'),
('2016-02-09','Snow'),
('2016-02-10','Snow') ),
changes AS (
SELECT date, 
    weather, 
    CASE WHEN lag(weather) OVER () = weather THEN 1 ELSE 0 END change
FROM v)
SELECT date
    , weather
    ,(SELECT count(weather) -- number of times the weather didn't change
      FROM changes v2 
      WHERE v2.date <= v1.date AND v2.weather = v1.weather
        AND v2.date >= ( -- bounded between changes of weather
            SELECT max(date) 
            FROM changes v3 
            WHERE change = 0 
            AND v3.weather = v1.weather 
            AND v3.date <= v1.date)  --<-- here's the expensive part
    ) curve
FROM changes v1

【讨论】:

    【解决方案4】:

    这是基于this answer 的另一种方法。

    首先,我们添加一个change 列,即10,具体取决于天气是否与前一天不同。
    然后我们通过将changeorder by date 相加来引入group_nr 列。这将为每个连续的相同天气日序列生成一个唯一的组号,因为总和仅在每个序列的第一天递增。
    最后,我们执行row_number() over (partition by group_nr order by date) 来生成每组的运行计数。

    select date, weather, row_number() over (partition by group_nr order by date)
    from (
      select *, sum(change) over (order by date) as group_nr
      from (
        select *, (weather != lag(weather,1,'') over (order by date))::int as change
        from tmp_weather
      ) t1
    ) t2;
    

    sqlfiddle(使用等效的WITH 语法)

    【讨论】:

    • 非常感谢您有一个组 ID !像魅力一样工作!
    猜你喜欢
    • 1970-01-01
    • 2019-02-16
    • 2010-11-13
    • 1970-01-01
    • 2022-11-25
    • 1970-01-01
    • 1970-01-01
    • 2022-07-19
    • 1970-01-01
    相关资源
    最近更新 更多