Обновлять значения столбцов последовательно, если новое значение основано на обновленных значениях в «предыдущей» строке - PullRequest
0 голосов
/ 18 мая 2019

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

select id, val, newval from test1;
 id | val | newval
----+-----+--------
  1 |   1 |      0
  2 |   2 |      0
  3 |   5 |      0
  4 |   9 |      0
  5 |  10 |      0

Я ищу запрос на обновление, который может последовательно обновлять значения в столбце newval , где обновленное значение - это разница между val и val.prev (значение val в предыдущей строке) плюс значение UDATED newval из предыдущей строки.Результат будет:

select id, val, newval from test1;
 id | val | newval
----+-----+--------
  1 |   1 |      0 = set to zero since result would be NULL (no previous row exists)
  2 |   2 |      1 = 2  - 1 + 0
  3 |   5 |      4 = 5  - 2 + 1
  4 |   9 |      8 = 9  - 5 + 4
  5 |  10 |      9 = 10 - 9 + 8
                              ^ - uses updated value of newval

Я подошел к решению со следующим:

WITH tt AS (
    SELECT id, COALESCE(val - lag(val) OVER w + lag(newval) OVER w,0) as nv 
    FROM test1
    WINDOW w AS (ORDER BY id)
    )
UPDATE test1 SET newval = tt.nv FROM tt
WHERE test1.id = tt.id;

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

select id, val, newval from test1;
 id | val | newval
----+-----+--------
  1 |   1 |      0
  2 |   2 |      1 = 2  - 1 + 0
  3 |   5 |      3 = 5  - 2 + 0
  4 |   9 |      4 = 9  - 5 + 0
  5 |  10 |      1 = 10 - 9 + 0
                              ^ - uses old value of newval

, но этоРешение не использует обновленные значения newval .Он использует старые значения.

Я знаю, что могу написать функцию для циклического прохождения таблицы по одной строке за раз, но из того, что я прочитал, этот метод будет неэффективным и обычно не рекомендуется.Мое реальное приложение более сложное и включает большие таблицы, поэтому эффективность важна.

1 Ответ

2 голосов
/ 18 мая 2019

Я почти уверен, что ваша логика сводится к:

select id, val, (val - 1) as newval
from t;

Почему?Вы берете совокупную сумму разницы между val и val в предыдущем ряду.Кумулятивная разница оказывается самым последним значением минус первое значение.

Первое значение 1.Вышеуказанные жесткие коды это значение.Было бы достаточно легко настроить логику для первого значения:

select id, val,
       (val - first_value(val) over (order by id) as newval
from t;
...