【问题标题】:Update top N values using PostgreSQL使用 PostgreSQL 更新前 N 个值
【发布时间】:2012-10-22 15:37:25
【问题描述】:

我想更新表中列的前 10 个值。我有三列; idaccountaccountrank。要获得前 10 个值,我可以使用以下方法:

SELECT  * FROM accountrecords    
ORDER BY account DESC
LIMIT 10;

我想做的是根据account 的大小将accountrank 中的值设置为一系列1 - 10。这可以在 PostgreSQL 中实现吗?

【问题讨论】:

  • 如果您的 poatgres 版本是 8.4 或更高版本,您可以使用窗口函数 + rank() 或 row_number()。

标签: sql postgresql sql-update sql-order-by sql-limit


【解决方案1】:
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;

加入表表达式通常比关联子查询快。它也更短。

window function row_number() 保证不同的数字。如果您希望 account 具有相同值的行共享相同的编号,请使用 rank()(或可能是 dense_rank())。

只有在account中可以有NULL值时,才需要附加NULLS LAST进行降序排序,或者NULL值在顶部排序:

如果可以同时进行写访问,则上述查询受制于竞态条件。考虑:

但是,如果是这样的话,硬编码前十名的整个概念将是一种可疑的方法。

使用 CTE 而不是普通的子查询(就像我一开始那样)来可靠地强制执行 LIMIT。请参阅上面的链接。

【讨论】:

    【解决方案2】:

    当然,您可以在子查询中使用您的 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 值,那么它们将获得相同的排名。您可以认为这是一个功能... :-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-27
      • 2010-10-18
      • 1970-01-01
      • 2011-11-19
      • 1970-01-01
      • 1970-01-01
      • 2017-04-04
      • 2021-12-31
      相关资源
      最近更新 更多