7

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 |

SQLFiddle.com

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?

2 Answers 2

6

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.

Sign up to request clarification or add additional context in comments.

Comments

4
    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;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.