Reputation: 1658
Consider the following table structure:
CREATE TABLE tb_log
(
id INTEGER PRIMARY KEY,
moment DATE,
old INTEGER,
actual INTEGER
);
Containing the data:
INSERT INTO
tb_log ( id, moment, old, actual )
VALUES
( 1, '2018-06-19', 10, 20 ),
( 2, '2018-06-21', 20, 30 ),
( 3, '2018-06-25', 30, 40 );
I'm trying to get from tb_log
the period (start date and end date) at which a value was in effect.
Trial #1 - Using lag()
function:
SELECT
lag( moment ) OVER (ORDER BY moment) date_start,
moment AS date_end,
old AS period_value
FROM
tb_log;
Which returns the following data:
| date_start | date_end | period_value |
|------------|------------|--------------|
| (null) | 2018-06-19 | 10 |
| 2018-06-19 | 2018-06-21 | 20 |
| 2018-06-21 | 2018-06-25 | 30 |
Trial #2 - Using lead()
function:
SELECT
moment AS date_start,
lead( moment ) OVER (ORDER BY moment) date_end,
actual AS period_value
FROM
tb_log;
Which returns the following data:
| date_start | date_end | period_value |
|------------|------------|--------------|
| 2018-06-19 | 2018-06-21 | 20 |
| 2018-06-21 | 2018-06-25 | 30 |
| 2018-06-25 | (null) | 40 |
Is there any trick using Window Functions
to return something like this:
| date_start | date_end | period_value |
|------------|------------|--------------|
| (null) | 2018-06-19 | 10 |
| 2018-06-19 | 2018-06-21 | 20 |
| 2018-06-21 | 2018-06-25 | 30 |
| 2018-06-25 | (null) | 40 |
Any Ideas?
Upvotes: 7
Views: 97
Reputation: 1270773
There is no trick using window functions, because window functions do not add a row to the data. It is much more natural (in my opinion) to use lead()
:
(SELECT moment, lead(moment) over (order by moment) as date_end,
actual AS period_value
FROM tb_log
)
UNION ALL
(SELECT null, moment, old
FROM tb_log
ORDER BY moment
LIMIT 1
);
In general, using union all
instead of union
is a good idea. Union
incurs overhead for removing duplicates.
Upvotes: 6
Reputation: 630
SELECT
lag( moment ) OVER (ORDER BY moment) date_start,
moment AS date_end,
old AS period_value
FROM
tb_log
union
SELECT
moment AS date_start,
lead( moment ) OVER (ORDER BY moment) date_end,
actual AS period_value
FROM
tb_log
order by 3;
Upvotes: 4