【问题标题】:Strange window function behaviour奇怪的窗口函数行为
【发布时间】:2014-02-14 23:19:27
【问题描述】:

我有以下一组数据:

 player | score |        day   
--------+-------+------------
   John |     3 | 02-01-2014
   John |     5 | 02-02-2014
   John |     7 | 02-03-2014
   John |     9 | 02-04-2014
   John |    11 | 02-05-2014
   John |    13 | 02-06-2014
   Mark |     2 | 02-01-2014
   Mark |     4 | 02-02-2014
   Mark |     6 | 02-03-2014
   Mark |     8 | 02-04-2014
   Mark |    10 | 02-05-2014
   Mark |    12 | 02-06-2014

给定两个时间范围:

  1. 02-01-2014..02-03-2014
  2. 02-04-2014..02-06-2014

我需要在给定的时间范围内获得每个玩家的平均分数。我想要达到的最终结果是:

 player | period_1_score | period_2_score
--------+----------------+----------------
   John |              5 |             11
   Mark |              4 |             10

我想出的原始算法是:

  1. 使用两个值执行SELECT,通过将每个时间段的分数集分成两个来得出
  2. 在第一个 SELECT 之上,执行另一个,按玩家名称分组。

我被困在第 1 步:运行以下查询:

SELECT
  player,
  AVG(score) OVER (PARTITION BY day BETWEEN '02-01-2014' AND '02-03-2014') AS period_1,
  AVG(score) OVER (PARTITION BY day BETWEEN '02-04-2014' AND '02-06-2014') AS period_2;

得到不正确的结果(注意period1period2 的平均分数是一样的:

 player | period_1_score | period_2_score
--------+----------------+----------------
   John |              5 |              5
   John |              5 |              5
   John |              5 |              5
   John |              5 |              5
   John |              5 |              5
   John |              5 |              5
   Mark |              4 |              4
   Mark |              4 |              4
   Mark |              4 |              4
   Mark |              4 |              4
   Mark |              4 |              4
   Mark |              4 |              4

我想我并不完全了解窗口函数的工作原理......我有 2 个问题:

  1. 我的查询有什么问题?
  2. 我该如何正确操作?

【问题讨论】:

  • 为什么将日期存储为字符串而不是DATE?更糟糕的是,为什么要将它们存储在第一个日期(或月份)和最后一个年份?
  • 我们(和 SQL-Server)如何知道 '02-06-2014' 是 6 月 2 日还是 2 月 6 日?您是否意识到,如果您将日期存储为字符串并使用这种格式,SQL-Server 将认为'02-06-2014' 的“日期”晚于“日期”'01-01-2020'

标签: sql postgresql window-functions


【解决方案1】:

您不需要窗口功能。 试试:

select 
player
,avg(case when day BETWEEN '02-01-2014' AND '02-03-2014' then score else null end) as period_1_score
,avg(case when day BETWEEN '02-04-2014' AND '02-06-2014' then score else null end) as period_1_score
from <your data>
group by player

【讨论】:

  • Yakshemash。我建议你在 - sqlblog.com/blogs/aaron_bertrand/archive/2011/10/19/…chenqui 之间小心一点。
  • @BoratSagdiyev 无关 - 这个问题不涉及日期时间。
  • 非常感谢@user102890!
  • @user1509107。一点都不相关。这些是日期,适用相同的原则。为什么您可以将BETWEEN 与日期一起使用,闭-开间隔提供更多优势,即使是日期也是如此。另请查看 Aaron 的文章,它还提到了为什么不应该将日期存储为字符串。
猜你喜欢
  • 1970-01-01
  • 2013-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-12
  • 2011-05-24
  • 1970-01-01
相关资源
最近更新 更多