Заполнить строку предыдущим значением
Как в таблице заполнить следующие строки, у которых null последним не нулевым значением?
sum1 | sum2 | date1 | date2 | total
------------+----------+---------------------+---------------------+-------
51 | 10 | 2016-12-31 00:00:00 | 2016-12-31 00:00:00 | 510
49 | 20 | 2017-01-01 00:00:00 | 2017-01-01 00:00:00 | 980
50 | 20 | 2017-01-01 00:00:00 | 2017-01-01 00:00:00 | 1000
| 30 | | 2017-01-02 00:00:00 |
| 40 | | 2017-01-03 00:00:00 |
| 50 | | 2017-01-04 00:00:00 |
| 60 | | 2017-01-06 00:00:00 |
55 | | 2017-01-10 00:00:00 | |
51 | 5 | 2017-01-11 00:00:00 | 2017-01-11 00:00:00 | 255
52 | 5 | 2017-01-11 00:00:00 | 2017-01-11 00:00:00 | 260
53 | 6 | 2017-01-12 00:00:00 | 2017-01-12 00:00:00 | 318
53 | 5 | 2017-01-12 00:00:00 | 2017-01-12 00:00:00 | 265
54 | | 2017-01-13 00:00:00 | |
Т.е. если в sum1 у меня null, то я его заполняю последним значением из предыдущей строки:
sum1 | sum2 | date1 | date2 | total
------------+----------+---------------------+---------------------+-------
51 | 10 | 2016-12-31 00:00:00 | 2016-12-31 00:00:00 | 510
49 | 20 | 2017-01-01 00:00:00 | 2017-01-01 00:00:00 | 980
50 | 20 | 2017-01-01 00:00:00 | 2017-01-01 00:00:00 | 1000
50 | 30 | | 2017-01-02 00:00:00 | 1500
50 | 40 | | 2017-01-03 00:00:00 | 2000
50 | 50 | | 2017-01-04 00:00:00 | 2500
50 | 60 | | 2017-01-06 00:00:00 | 3000
55 | | 2017-01-10 00:00:00 | |
51 | 5 | 2017-01-11 00:00:00 | 2017-01-11 00:00:00 | 255
52 | 5 | 2017-01-11 00:00:00 | 2017-01-11 00:00:00 | 260
53 | 6 | 2017-01-12 00:00:00 | 2017-01-12 00:00:00 | 318
53 | 5 | 2017-01-12 00:00:00 | 2017-01-12 00:00:00 | 265
54 | | 2017-01-13 00:00:00 | |
Для того, чтобы конкретизировать вопрос, я заменю исходную таблицу на следующую:
course_sum | trxn_sum | date | total
------------+----------+---------------------+-------
51 | 10 | 2016-12-31 00:00:00 | 510
49 | 20 | 2017-01-01 00:00:00 | 980
50 | 20 | 2017-01-01 00:00:00 | 1000
| 30 | 2017-01-02 00:00:00 |
| 40 | 2017-01-03 00:00:00 |
| 50 | 2017-01-04 00:00:00 |
| 60 | 2017-01-06 00:00:00 |
55 | | 2017-01-10 00:00:00 |
51 | 5 | 2017-01-11 00:00:00 | 255
52 | 5 | 2017-01-11 00:00:00 | 260
53 | 6 | 2017-01-12 00:00:00 | 318
53 | 5 | 2017-01-12 00:00:00 | 265
54 | | 2017-01-13 00:00:00 |
Сортировка должна происходить по date.
Ответы (1 шт):
(Ответ является модифицированным переводом вот этого ответа с английского сайта. Возможно, есть более элегантный способ, но я его не нашёл, а этот работает.)
Ещё более упрощённая версия вашей таблицы для ясности примера:
sum1 | date1
------+------------------------
NULL | 2020-01-01 00:00:00+00
1 | 2020-01-01 00:00:01+00
2 | 2020-01-01 00:00:02+00
NULL | 2020-01-01 00:00:03+00
NULL | 2020-01-01 00:00:04+00
NULL | 2020-01-01 00:00:05+00
5 | 2020-01-01 00:00:06+00
Есть техника, заключающаяся в том, что сначала вы получаете
колонку, которая возрастает на 1 каждый раз,
когда значение ненулевое:
SELECT sum1
, date1
, SUM(CAST(sum1 IS NOT NULL AS INTEGER))
OVER (ORDER BY date1) AS inc
FROM t_1
;
sum1 | date1 | inc
------+------------------------+-----
NULL | 2020-01-01 00:00:00+00 | 0
1 | 2020-01-01 00:00:01+00 | 1
2 | 2020-01-01 00:00:02+00 | 2
NULL | 2020-01-01 00:00:03+00 | 2
NULL | 2020-01-01 00:00:04+00 | 2
NULL | 2020-01-01 00:00:05+00 | 2
5 | 2020-01-01 00:00:06+00 | 3
После чего второй запрос просто забирает первое значение в группе
с этим inc, плюс значение по умолчанию
0 на случай, если первое значение в оригинальной
таблице является нулевым:
WITH t_2 AS (
SELECT sum1
, date1
, SUM(CAST(sum1 IS NOT NULL AS INTEGER))
OVER (ORDER BY date1) AS inc
FROM t_1
)
SELECT COALESCE(
sum1
, FIRST_VALUE(sum1) OVER (PARTITION BY inc)
, 0
) AS sum1
, date1
FROM t_2
ORDER BY date1
;
sum1 | date1
------+------------------------
0 | 2020-01-01 00:00:00+00
1 | 2020-01-01 00:00:01+00
2 | 2020-01-01 00:00:02+00
2 | 2020-01-01 00:00:03+00
2 | 2020-01-01 00:00:04+00
2 | 2020-01-01 00:00:05+00
5 | 2020-01-01 00:00:06+00