#sql #postgresql
Вопрос:
У меня есть таблица со столбцами:
id (PK),
low_value,
high_value
Идентификатор и значение high_value заполняются в этой таблице, а значение low_value должно быть заполнено с использованием заполненных данных.
Low_value должно быть предыдущим упорядоченным значением high_value в таблице.
Пример — данные таблицы перед обновлением low_value:
id | low_value | high_value
---------------------------------------
1 | | 1000
2 | | 1000
3 | | 2000
4 | | 5000
5 | | 7000
6 | | 10000
7 | | 10000
8 | | 20000
данные таблицы после обновления low_value должны быть:
id | low_value | high_value
---------------------------------------
1 | 0 | 1000
2 | 0 | 1000
3 | 1000 | 2000
4 | 2000 | 5000
5 | 5000 | 7000
6 | 7000 | 10000
7 | 7000 | 10000
8 | 10000 | 20000
Я подумываю о присвоении ранга (с помощью оконной функции rank()) каждой строке на основе значения high_value,
поэтому строки с одинаковым значением high_value будут иметь одинаковый ранг, а затем выберите значение с рангом меньше текущего ранга для обновляемой строки.
Но я не в состоянии построить sql. Может ли кто-нибудь помочь с sql с ранжированием строк или без него ?
Ответ №1:
Хммм … немного странно, что есть дубликаты. Предполагая, что значения упорядочены, вы можете использовать:
update t
set low_value = coalesce(prev_high_value, 0)
from (select high_value,
lag(high_value) over (order by high_value) as prev_high_value
from t
group by high_value
) tt
where tt.high_value = t.high_value
Комментарии:
1. Спасибо за публикацию, но это не работает, для первых 10000 значение prev_high_value = 7000, но для следующих 7000 это само по себе 7000.
2. @user10916892 . . . Как написано, произошла опечатка, и она не должна была запускаться. Однако возможно ли, что вы сохраняете значение в виде строки, а не в виде числа? Если это так, вам следует исправить данные . Не храните числа в виде строк!
Ответ №2:
Поскольку у вас есть дубликаты high_value
s в последовательных id
s LAG()
, не всегда будет возвращено правильное значение.
Для каждой строки вы должны получить high_value
строку с максимальным идентификатором with
, отличным high_value
от текущей строки:
WITH cte AS (
SELECT *, SUM(flag) OVER (ORDER BY id) grp
FROM (
SELECT *,
LAG(high_value, 1, 0) OVER (ORDER BY id) prev_high_value,
(high_value <> LAG(high_value, 1, 0) OVER (ORDER BY id))::int flag
FROM tablename
) t
)
UPDATE tablename t
SET low_value = new_value
FROM (
SELECT *, FIRST_VALUE(prev_high_value) OVER (PARTITION BY grp ORDER BY flag DESC) new_value
FROM cte
) c
WHERE t.id = c.id
Смотрите демонстрацию.