这是@Erwin 对 Postgres 中的高效时间序列查询的回答中的后续问题。
为了简单起见,我将使用与该问题相同的表结构
id | widget_id | for_date | score |
最初的问题是获取某个范围内每个日期的每个小部件的分数。如果某个日期没有小部件条目,则显示该小部件上一个条目的分数。如果所有数据都包含在您查询的范围内,则使用交叉连接和窗口函数的解决方案效果很好。我的问题是我想要以前的分数,即使它在我们正在查看的日期范围之外。
示例数据:
INSERT INTO score (id, widget_id, for_date, score) values
(1, 1337, '2012-04-07', 52),
(2, 2222, '2012-05-05', 99),
(3, 1337, '2012-05-07', 112),
(4, 2222, '2012-05-07', 101);
当我查询 2012 年 5 月 5 日至 5 月 10 日的范围(即generate_series('2012-05-05'::date, '2012-05-10'::date, '1d')
)时,我想得到以下信息:
DAY WIDGET_ID SCORE
May, 05 2012 1337 52
May, 05 2012 2222 99
May, 06 2012 1337 52
May, 06 2012 2222 99
May, 07 2012 1337 112
May, 07 2012 2222 101
May, 08 2012 1337 112
May, 08 2012 2222 101
May, 09 2012 1337 112
May, 09 2012 2222 101
May, 10 2012 1337 112
May, 10 2012 2222 101
迄今为止最好的解决方案(也是@Erwin)是:
SELECT a.day, a.widget_id, s.score
FROM (
SELECT d.day, w.widget_id
,max(s.for_date) OVER (PARTITION BY w.widget_id ORDER BY d.day) AS effective_date
FROM (SELECT generate_series('2012-05-05'::date, '2012-05-10'::date, '1d')::date AS day) d
CROSS JOIN (SELECT DISTINCT widget_id FROM score) AS w
LEFT JOIN score s ON s.for_date = d.day AND s.widget_id = w.widget_id
) a
LEFT JOIN score s ON s.for_date = a.effective_date AND s.widget_id = a.widget_id
ORDER BY a.day, a.widget_id;
但正如您在此SQL Fiddle中看到的那样,它在前两天为小部件 1337 生成空分数。我希望看到第 1 行中较早的 52 分代替它。
是否有可能以有效的方式做到这一点?