不使用BETWEEN的SQL中的滚动平均值

时间:2019-02-02 18:54:59

标签: sql

让我们说我有一个表signups的格式为:

| date       | sign_ups |
|------------|----------|
| 2018-01-01 | 34       |
| 2018-01-02 | 23       |
| 2018-01-03 | 2        |
| ...        | ...      |

我现在想要写一个查询来计算前述7天平均注册等的,即对于给定的一天,平均其注册等的和符号起坐为前六天值。此blog post提供了这种解决方案:

select
  date,
  avg(sign_ups) 
    over (order by date asc
          rows between 6 preceding and current row) as avg,
from signups

我不喜欢使用SQL的BETWEEN,所以我写此溶液代替:

SELECT 
  a.date, 
  AVG(b.sign_ups)
FROM 
  signups a 
JOIN 
  signups b ON a.date <= b.date + interval '7 days'
GROUP BY 
  a.date

只是想确认两者是等价的,如果有这个问题更简洁/更有效的解决方案。

2 个答案:

答案 0 :(得分:3)

首先,假设你真的是:

on b.date <= a.date and
   b.date > interval '7 days'

然后他们只是如果你有每个日期只有一行等价的。

您的版本有很大不同-您在join中的日期之后,但在Windows函数中的日期之前获取值。你必须在一种情况下,并在其他一些未知数量的8个值。但我得到这个问题的要点。

在窗口功能版本很多很多,很多,很多在自连接优选的。从性能和可理解性的角度来看,这简直是更好的。而且,正如您的代码充分说明的那样,Windows版本使表达您的实际意图变得更加容易。

答案 1 :(得分:2)

两个查询是不等效的:

1)作为回答@GordonLinoff,第一查询返回一样多条记录,因为有在表中,同时通过日期第二聚集体。为了使结果相同,每个日期应该只有一行

2)该:

rows between 6 preceding and current row

不等同于:

a.date <= b.date + interval '7 days'

首先,如由Dnoeth评论,所述第二形式是将平均当前的日期和过去7天,其表示的8天总计

此外,第二个表单将在最近N天内记录帐户记录,并且还会记录当前日期之后的所有记录

您需要更改该子句以为日期范围添加上限,例如:

a.date <= b.date + interval '6 days' AND a.date >= b.date

这基本上模拟BETWEEN ...并且还可以拼写:

b.date BETEWEEN a.date - interval '6 days' AND a.date