【问题标题】:Redshift SQL Window Function frame_clause with days带天数的 Redshift SQL 窗口函数 frame_clause
【发布时间】:2017-08-14 10:32:56
【问题描述】:

我正在尝试对 Redshift 中的数据集执行窗口函数,使用天数作为前行的间隔。 示例数据:

date        ID      score
3/1/2017    123     1
3/1/2017    555     1
3/2/2017    123     1
3/3/2017    555     3
3/5/2017    555     2

最近 3 个分数的平均分数的 SQL 窗口函数:

select
      date,
      id,
      avg(score) over 
         (partition by id order by date rows 
              between preceding 3 and 
                      current row) LAST_3_SCORES_AVG,
from DATASET

结果:

date        ID      LAST_3_SCORES_AVG
3/1/2017    123     1
3/1/2017    555     1
3/2/2017    123     1
3/3/2017    555     2
3/5/2017    555     2

问题是我想要最近 3 天(移动平均)的平均分数,不是最近三个测试。我已经查看了 Redshift 和 Postgre 文档,但似乎找不到任何方法。

期望的结果:

date        ID      3_DAY_AVG
3/1/2017    123     1
3/1/2017    555     1
3/2/2017    123     1
3/3/2017    555     2
3/5/2017    555     2.5

任何方向都将不胜感激。

【问题讨论】:

  • 编辑您的问题并显示您想要的结果。

标签: sql amazon-redshift window-functions


【解决方案1】:

您可以使用lag() 并明确计算平均值。

select t.*,
       (score +
        (case when lag(date, 1) over (partition by id order by date) >=
                   date - interval '2 day'
              then lag(score, 1) over (partition by id order by date)
              else 0
         end) +
        (case when lag(date, 2) over (partition by id order by date) >=
                   date - interval '2 day'
              then lag(score, 2) over (partition by id order by date)
              else 0
         end)
        )
       ) /
       (1 +
        (case when lag(date, 1) over (partition by id order by date) >=
                   date - interval '2 day'
              then 1
              else 0
         end) +
        (case when lag(date, 2) over (partition by id order by date) >=
                   date - interval '2 day'
              then 1
              else 0
         end)
       )
from dataset t;

【讨论】:

  • 首先,谢谢!读你的书,好好读!我希望会有一个动态的答案,在 3 天内不需要硬编码的解决方案。
【解决方案2】:

在很多(或所有)情况下,可以使用以下方法代替 RANGE 窗口选项。 您可以为每个输入记录引入“到期”。到期记录将否定原始记录,因此当您汇总所有先前的记录时,只会考虑所需范围中的记录。 AVG 有点难,因为它没有直接的对立面,所以我们需要将其视为 SUM/COUNT 并对两者取反。

SELECT id, date, running_avg_score
FROM
(
    SELECT id, date, n,
            SUM(score) OVER (PARTITION BY id ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
            / NULLIF(SUM(n) OVER (PARTITION BY id ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), 0) as running_avg_score
    FROM
    (
        SELECT date, id, score, 1 as n   
        FROM DATASET
        UNION ALL
        -- expiry and negate
        SELECT DATEADD(DAY, 3, date), id, -1 * score, -1
        FROM DATASET
    )
) a
WHERE a.n = 1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-26
    • 2017-01-15
    相关资源
    最近更新 更多