The special difficulty here is that you need to number days after aggregating rows. You can do this in a single query level with the window function row_number()
, since window functions are applied after aggregation by GROUP BY
.
Also, use a CTE to avoid executing the same subquery multiple times:
WITH q AS (
SELECT name, ts::date AS day
,avg(x) AS avg_x, sum(y) AS sum_y
,row_number() OVER (PARTITION BY name ORDER BY ts::date) AS rn
FROM data
GROUP BY 1,2
)
SELECT q1.name, q1.day, q1.avg_x, q1.sum_y
,q2.day AS day2, q2.avg_x AS avg_x2, q2.sum_y AS sum_y2
FROM q q1
LEFT JOIN q q2 ON q1.name = q2.name
AND q1.rn = q2.rn + 1
ORDER BY 1,2;
Using the simpler cast to date (ts::date
) instead of date_trunc('day', ts)
to get "days".
LEFT [OUTER] JOIN
(as opposed to [INNER] JOIN
) is instrumental to preserve the corner case of the first row, where there is no previous day.
And ORDER BY
should be applied to the outer query.