If you want multiple rows like that in the result, I would use a crosstab()
function.
But according to your description you want a single row. I would solve that with the window functions lead()
or lag()
.
The major trick is to use a subquery or CTE to generate all columns before you apply your WHERE clause and narrow the result down to a single row. I would use a CTE here:
Given the following table (which you should have provided):
CREATE TABLE tbl(
tbl_id serial PRIMARY KEY
,ts timestamp NOT NULL
,value int
);
One row per day guaranteed
The query could look like this:
WITH x AS (
SELECT tbl_id, ts, value
,lag(value, 1) OVER w AS value_day_before_1
,lag(value, 2) OVER w AS value_day_before_2
-- ...
,lead(value, 1) OVER w AS value_day_after_1
,lead(value, 2) OVER w AS value_day_after_2
-- ...
FROM tbl
WINDOW w AS (ORDER BY ts)
)
SELECT *
FROM x
WHERE ts = '2013-02-14 0:0'::timestamp
At most one row per day, but days can be missing:
Also timestamp can be any time during the day.
Generate a list of days with generate_series()
and LEFT JOIN
your table to it:
WITH x AS (
SELECT tbl_id, ts, value
,lag(value, 1) OVER w AS value_day_before_1
,lag(value, 2) OVER w AS value_day_before_2
-- ...
,lead(value, 1) OVER w AS value_day_after_1
,lead(value, 2) OVER w AS value_day_after_2
-- ...
FROM (
SELECT generate_series ('2013-02-01'::date
,'2013-02-28'::date
,interval '1d') AS day
) d
LEFT JOIN tbl t ON date_trunc('day', t.ts) = d.day
WINDOW w AS (ORDER BY day)
)
SELECT *
FROM x
WHERE ts = '2013-02-14 0:0'::timestamp;
->sqlfiddle