2012-06-29 50 views
3

可能重复:
SQL ORDER BY total within GROUP BYSQL组和排序两列

更新:我发现我的解决方案,我已经张贴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忽略了订单 - 只是重写了这些值。

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

那么,我该如何选择用户的最高分和关联的时间,名称等,然后按时间顺序排列结果?

在此先感谢!

+1

WHERE条件严重缺失。当使用'GROUP BY'时,引擎有权从分组项中选择绝对的任何列,即使从每列的不同行开始。 – biziclop

+1

'ORDER BY'在'GROUP BY'之后__。 – vyegorov

+0

'select ...,max(score)'? – teran

回答

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,得分,时间)为每个用户获得一行。

你需要聚合两次,这是关键;一次找到用户的最低分数,再次找到该用户和分数的最短时间。你可以颠倒聚合的顺序,但我希望这会过滤得最快,因此效率最高。

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

1

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

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

谢谢你。这虽然不是我想要的,但是它将输出所有参赛者的所有分数。我只希望每个用户的最高分和与之相关的时间。 我一直在为它奋斗一整天..我敢肯定我错过了一些愚蠢简单的事情。 –

+0

如果用户有两个相同的分数,但时间不同,那么情况会更好还是更低? –

+0

更低的时间是最好的。 –

3

您的查询实际上没有意义,因为顺序应该在组之后。你使用的是什么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 

您还可以使用窗口功能做到这一点,但是这取决于您的数据库。

+0

对不起,我上面的声明是不正确的 - Order By是在群组之后。我会试试这个。 –

2

您需要分钟得分

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

嗨@菲尔 - 我已经尝试过这个和今天的一些变化。不幸的是,它会返回用户所做的每个条目 - 它不会为每个用户选择最高分数。 –

+0

从组中删除ID和时间并选择。对不起,最初的答案我会编辑 –

2

使用此:

enter image description here

这:

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

我得到这个:

enter image description here

+0

嗨@Adnan Shammout - 谢谢你。这很好,除了我还需要按时间排序作为次要排序 - 并且Group By功能意味着在特定用户的数据库中第一次在该行中使用,而不一定是正确的时间。 –

+0

嗨@Adnan - 如果您将第1行中的时间更改为200,那么您会将结果作为结果第一行中的时间,这是不正确的。 我已经找到了解决方案,并添加了我的答案。再次感谢 –

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 

谢谢!