PostgreSQL:如何在周表中查找具有最大资金的 id

发布于 2024-10-07 03:02:37 字数 1075 浏览 2 评论 0原文

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

# 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

谢谢! Alex

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

I have the following table holding virtual money for weekly tournaments:

# 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)

In my PHP script listing users, I need to know who has been a weekly winner, so that I can show medals near their names. So I'm trying this SQL statement:

# 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']]++;

This mostly works, but sometimes I get false positives, when a user happens to have the same amount of money in some week (but not max there) as the winner in another week.

Does anybody have an idea how to change the SQL statement, so that really only winner ids are being selected?

When I try the following, I get an error:

# 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

Thank you!
Alex

UPDATE: PostgreSQL 8.4.5 / CentOS and there can be ties :-)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

活泼老夫 2024-10-14 03:02:37

哪个版本的 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()

Which version PostgreSQL? This is easy with windowing functions introduced in 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

This will just about do in older versions:

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

But observe that weeks where two users tie for the maximum money will be shown twice in the output. If that's actually what you want, you can do with with the windowing functions too, using rank() instead of row_number()

淡淡の花香 2024-10-14 03:02:37

假设 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 列,以防万一想要/需要按列过滤。

Assuming PostgreSQL 8.4+, and no one ties for the winner position in a given week -- this will list the weekly winners:

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

If there can be ties, use:

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

I included the yw column, in case you want/need to filter by the column.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文