奇怪的窗口函数行为

Posted

技术标签:

【中文标题】奇怪的窗口函数行为【英文标题】: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

给定两个时间范围:

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

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

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

我想出的原始算法是:

    使用两个值执行SELECT,通过将每个时间段的分数集分成两个来得出 在第一个 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 个问题:

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

【问题讨论】:

为什么将日期存储为字符串而不是DATE?更糟糕的是,为什么要将它们存储在第一个日期(或月份)和最后一个年份? 我们(和 SQL-Server)如何知道 '02-06-2014' 是 6 月 2 日还是 2 月 6 日?您是否意识到,如果您将日期存储为字符串并使用这种格式,SQL-Server 将认为'02-06-2014' 的“日期”晚于“日期”'01-01-2020' 【参考方案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 的文章,它还提到了为什么不应该将日期存储为字符串。

以上是关于奇怪的窗口函数行为的主要内容,如果未能解决你的问题,请参考以下文章

使用 PostgreSQL 用户定义函数实现类似窗口函数的行为?

尝试重用弹出窗口时的奇怪行为

GBQ中的窗口函数按顺序排序行为规范

为啥从独立函数生成的 pyplot 窗口与从事件处理程序调用的函数生成时的行为不同?

错误结果绘图窗口 FFT

使用 VS2010 的 libsndfile 奇怪行为