SQL组&按两列排序

时间:2012-06-29 14:09:43

标签: php sql database group-by sql-order-by

  

可能重复:
  SQL ORDER BY total within GROUP BY

更新:我找到了我的解决方案,我发布了here。感谢大家的帮助!


我正在开发一个需要排行榜的Facebook应用程序。记录完成游戏所花费的分数和时间,并且首先按分数组织,然后在两个相同分数的情况下,使用时间。如果用户多次播放,则使用他们的最佳分数。

得分越低,游戏中的表现越好。

我的表结构是:

id
facebook_id - (Unique Identifier for the user)
name
email
score
time - (time to complete game in seconds)
timestamp - (unix timestamp of entry)
date - (readable format of timestamp)
ip

我认为可行的查询是:

SELECT *
FROM entries
ORDER BY score ASC, time ASC
GROUP BY facebook_id

我遇到的问题是在某些情况下它会提取用户在数据库中的第一个分数,而不是他们的最高分。我认为这取决于GROUP BY声明。我原本以为ORDER BY语句会修复它,但显然不是。

例如:

----------------------------------------------------------------------------
|  ID  |       NAME       |  SCORE  |  TIME  |  TIMESTAMP  |  DATE  |  IP  |
----------------------------------------------------------------------------
|  1   |  Joe Bloggs      |  65     |   300  | 1234567890  |  XXX   |  XXX |
----------------------------------------------------------------------------
|  2   |  Jane Doe        |  72     |   280  | 1234567890  |  XXX   |  XXX |
----------------------------------------------------------------------------
|  3   |  Joe Bloggs      |  55     |   285  | 1234567890  |  XXX   |  XXX |
----------------------------------------------------------------------------
|  4   |  Jane Doe        |  78     |   320  | 1234567890  |  XXX   |  XXX |
----------------------------------------------------------------------------

当我使用上面的查询时,我得到以下结果:

 1. Joe Bloggs - 65 - 300 - (Joes First Entry, not his best entry) 
 2. Jane Doe - 72 - 280

我原以为......

 1. Joe Bloggs - 55 - 285 - (Joe's best entry)
 2. Jane Doe - 72 - 280 

就像Group By忽略了Order - 只是覆盖了这些值。

对组使用MIN(得分)选择最低得分,这是正确的 - 但是它会合并数据库中用户第一条记录的时间,因此经常返回错误。

那么,我如何选择用户的最高分以及相关的时间,名称等,并按分数排序结果,然后是时间?

提前致谢!

6 个答案:

答案 0 :(得分:3)

您的查询实际上没有意义,因为order by应该在group by之后。你使用什么SQL引擎?大多数都会出错。

我认为你想要的更像是:

select e.facebookid, minscore, min(e.time) as mintime -- or do you want maxtime?
from entries e join
     (select e.facebookid, min(score) as minscore
      from entries e
      group by facebookid
     ) esum
     on e.facebookid = esum.facebookid and
        e.score = e.minscore
group by e.facebookid, minscore

您也可以使用窗口函数执行此操作,但这取决于您的数据库。

答案 1 :(得分:2)

您需要将分数降至最低

    SELECT
      facebook_id,
      name,
      email,
      min(score) as high_score
    FROM
      entries
    GROUP BY
      facebook_id,
      name,
      email
   ORDER BY
     min(score) ASC

答案 2 :(得分:2)

使用此:

enter image description here

和此:

SELECT name, min( `score` ) , min( `time` )
FROM `entries`
GROUP BY `name`
ORDER BY `score`, `time`

我明白了:

enter image description here

答案 3 :(得分:2)

一种方法是:

SELECT entries.facebook_id, MIN(entries.score) AS score, MIN(entries.time) AS time
FROM entries
    INNER JOIN (
        SELECT facebook_id, MIN(score) AS score
        FROM entries
        GROUP BY facebook_id) highscores
    ON highscores.facebook_id = entries.facebook_id
    AND entries.score = highscores.score
GROUP BY entries.facebook_id
ORDER BY MIN(entries.score) ASC, MIN(entries.time) ASC

如果您需要条目表中的更多信息,则可以将其用作子查询,并再次加入所显示的信息(facebook_id,得分,时间)以获得每个用户一行。

你需要聚合两次,这是其中的症结所在;一次找到用户的最低分数,再次找到该用户的最短时间和分数。您可以反转聚合的顺序,但我希望这会过滤得最快,因此效率最高。

您可能还想检查哪个更快,第二次聚合:使用最低分数或使用分数进行分组。

答案 4 :(得分:2)

感谢您的帮助。 @Penguat得到了最接近的答案..这是我对可能有同样问题的任何人的最终查询...

SELECT f.facebook_id, f.name, f.score, f.time FROM
    (SELECT facebook_id, name, min(score)
    AS highscore FROM golf_entries
    WHERE time > 0
    GROUP BY facebook_id)
AS x
INNER JOIN golf_entries as f
ON f.facebook_id = x.facebook_id
AND f.score = x.highscore
ORDER BY score ASC, time ASC

再次感谢!

答案 5 :(得分:1)

如果你想要他们最好的时间,你想使用MIN()函数 - 你说得分越低,他们就越好。

SELECT facebook_id, MIN(score), time, name, ... 
FROM entries 
GROUP BY facebook_id, time, name, ...
ORDER BY score, time