我有下表持有每周锦标赛的虚拟货币:
# 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并且可能存在联系: - )
答案 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
列,以防您需要/需要按列进行过滤。