Обновление верхних значений 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, то они получат одинаковый ранг. Вы можете считать это особенностью... :-)