Обновление верхних значений N с помощью PostgreSQL
Я хочу обновить верхние 10 значений столбца в таблице. У меня три колонки;id
, account
и accountrank
. Чтобы получить 10 лучших значений, я могу использовать следующее:
SELECT * FROM accountrecords
ORDER BY account DESC
LIMIT 10;
что я хотел бы сделать, это установить значение в accountrank
серией 1 - 10
, исходя из величины account
. Возможно ли это сделать в PostgreSQL?
2 ответов
WITH cte AS (
SELECT id, row_number() OVER (ORDER BY account DESC NULLS LAST) AS rn
FROM accountrecords
ORDER BY account DESC NULLS LAST
LIMIT 10
)
UPDATE accountrecords a
SET accountrank = cte.rn
FROM cte
WHERE cte.id = a.id;
объединение в табличном выражении обычно происходит быстрее, чем коррелированные подзапросы. Он также короче.
С функция окна row_number()
различные номера гарантированы. Использовать rank()
(или dense_rank()
) Если вы хотите строки с равными значениями для account
чтобы разделить тот же номер.
только если может быть NULL
значения account
, вам необходимо добавить NULLS LAST
для нисходящего порядка сортировки или NULL
значения сортировки сверху:
если может быть одновременный доступ на запись, вышеуказанный запрос подлежит гонки. Подумайте:
однако, если это было так, вся концепция жесткого кодирования первой десятки начать с того, что это сомнительный подход.
используйте CTE вместо простого подзапроса (как у меня было сначала), чтобы принудить LIMIT
надежно. См. ссылки выше.
конечно, вы можете использовать оператор select в подзапросе. Создание рангового порядка не является тривиальным, но вот, по крайней мере, один способ сделать это. Я не тестировал это, но с верхней части моей головы:
update accountrecords
set accountrank =
(select count(*) + 1 from accountrecords r where r.account > account)
where id in (select id from accountrecords order by account desc limit 10);
это имеет причуду, что если две записи имеют одинаковое значение для account
, то они получат одинаковый ранг. Вы можете считать это особенностью... :-)