PostgreSQL:如何在每周表中找到最大钱的id

时间:2010-12-12 18:27:05

标签: sql postgresql

我有下表持有每周锦标赛的虚拟货币:

# select * from pref_money limit 5;
       id       | money |   yw
----------------+-------+---------
 OK32378280203  |   -27 | 2010-44
 OK274037315447 |   -56 | 2010-44
 OK19644992852  |     8 | 2010-44
 OK21807961329  |   114 | 2010-44
 FB1845091917   |   774 | 2010-44
(5 rows)

在我的PHP脚本列出用户中,我需要知道谁是每周获胜者,以便我可以在他们的名字附近显示奖牌。所以我正在尝试这个SQL语句:

# find the weekly winners
$sth = $db->prepare('select id from pref_money 
    where money in 
    (select max(money) from pref_money group by yw)');

$sth->execute();
while ($row = $sth->fetch(PDO::FETCH_ASSOC))
        @$medals[$row['id']]++;

这主要是有效的,但有时候我会得到误报,当用户在某个星期(而不是最大值)在一周内获得相同数量的金额作为另一周的赢家时。

是否有人知道如何更改SQL语句,以便只选择赢家ID?

当我尝试以下操作时,出现错误:

# select id, max(money) from pref_money group by yw;
ERROR:  column "pref_money.id" must appear in the 
  GROUP BY clause or be used in an aggregate function

谢谢! 亚历

更新:PostgreSQL 8.4.5 / CentOS并且可能存在联系: - )

2 个答案:

答案 0 :(得分:3)

PostgreSQL的哪个版本?使用8.4中引入的窗口函数很容易:

select id, yw from (
    select id,
           yw,
           row_number() over(partition by yw order by money desc) as ranking
    from pref_money
) x
where x.ranking = 1

这在旧版本中也是如此:

select id, yw
from pref_money
     join (select yw, max(money) max_money
           from pref_money
           group by yw) max_money
          on pref_money.yw = max_money.yw and pref_money.money = max_money.max_money

但请注意,两个用户并列最高金额的周将在输出中显示两次。如果这实际上是您想要的,您也可以使用rank()代替row_number()

来处理窗口函数

答案 1 :(得分:2)

假设PostgreSQL 8.4+,并且没有人在某一周内获得胜利者位置 - 这将列出每周获胜者:

WITH sample AS (
  SELECT t.id,
         t.yw,
         ROW_NUMBER() OVER(PARTITION BY t.yw
                               ORDER BY t.money DESC) AS rank
    FROM PREF_MONEY t)
SELECT s.id
  FROM sample s
 WHERE s.rank = 1

如果可以有联系,请使用:

WITH sample AS (
  SELECT t.id,
         t.yw,
         DENSE_RANK() OVER(PARTITION BY t.yw
                               ORDER BY t.money DESC) AS rank
    FROM PREF_MONEY t)
SELECT s.id
  FROM sample s
 WHERE s.rank = 1

我添加了yw列,以防您需要/需要按列进行过滤。