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