Окно PostgreSQL - PullRequest
       11

Окно PostgreSQL

0 голосов
/ 06 июля 2018

Рассмотрим следующую структуру таблицы:

CREATE TABLE tb_log
(
  id INTEGER PRIMARY KEY,
  moment DATE,
  old INTEGER,
  actual INTEGER
);

Содержит данные:

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

Я пытаюсь получить от tb_log период (начальная и конечная даты), в котором действовало значение.

Trial # 1 - Использование функции lag():

SELECT
  lag( moment ) OVER (ORDER BY moment) date_start,
  moment AS date_end,
  old AS period_value
FROM
   tb_log;

, который возвращает следующие данные:

| 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 - Использование функции lead():

SELECT
  moment AS date_start,
  lead( moment ) OVER (ORDER BY moment) date_end,
  actual AS period_value
FROM
   tb_log;

, который возвращает следующие данные:

| 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

Есть ли какой-нибудь трюк, использующий Window Functions, чтобы вернуть что-то вроде этого:

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

Есть идеи?

Ответы [ 2 ]

0 голосов
/ 06 июля 2018

Нет хитрости с использованием оконных функций, потому что оконные функции не добавляют строку к данным. Гораздо более естественно (на мой взгляд) использовать 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
);

В целом, использование union all вместо union - хорошая идея. Union накладные расходы на удаление дубликатов.

0 голосов
/ 06 июля 2018
    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;
...