SQL查询有不必要的结果 - 问题出在哪里?

时间:2010-01-01 23:47:08

标签: sql mysql

我有一张表记录用户在游戏中的得分(用户可以提交5,10,20,他想要的分数)。 我需要显示一个游戏的20个最高分,但是每个用户。 (因为用户可能已根据其他用户的分数提交了例如4个分数,这是最高分) 我写的查询是:

SELECT DISTINCT
    `table_highscores`.`userkey`,
    max(`table_highscores`.`score`),
    `table_users`.`username`,
    `table_highscores`.`dateachieved` 
FROM
    `table_highscores`, `table_users` 
WHERE
    `table_highscores`.`userkey` = `table_users`.`userkey`
AND
    `table_highscores`.`gamekey` = $gamekey  
GROUP BY
    `userkey` 
ORDER BY
    max(`table_highscores`.`score`) DESC,
LIMIT 0, 20;

输出结果没问题,但是有问题。当我计算天数的差异(今天 - dateachieved的这个)时,结果是错误的。 (例如,而不是说“分数是在22天前提交的,它说的是43天前)所以,我必须对每个分数进行第二次查询,以便找到真实的日期(意味着+20个查询)。有没有更短的方式找到正确的日期?  感谢。

4 个答案:

答案 0 :(得分:3)

  

有问题。当我计算天数的差异(今天 - 这个日期的差异)时,结果是错误的。

有两个问题

  1. dateachieved不太可能是与高分相关的值
  2. 您可以使用MySQL's DATEDIFF返回当前日期与dateachieved值之间的天数。
  3. 使用:

    SELECT u.username,
           hs.userkey,
           hs.score,
           DATEDIFF(NOW(), hs.dateachieved) 
      FROM TABLE_HIGHSCORES hs
      JOIN TABLE_USERNAME u ON u.userkey = hs.userkey
      JOIN (SELECT ths.userkey,
                   ths.gamekey,
                   ths.max_score,
                   MAX(ths.date_achieved) 'max_date'
              FROM TABLE_HIGHSCORES ths
              JOIN (SELECT t.userkey,
                           t.gamekey,
                           MAX(t.score) 'max_score'
                      FROM TABLE_HIGHSCORES t
                  GROUP BY t.userkey, t.gamekey) ms ON ms.userkey = ths.userkey
                                                   AND ms.gamekey = ths.gamekey
                                                   AND ms.max_score = ths.score
           ) x ON x.userkey = hs.userkey
              AND x.gamekey = hs.gamekey
              AND x.max_score = hs.score
              AND x.max_date = hs.dateachieved
     WHERE hs.gamekey = $gamekey
     ORDER BY hs.score DESC
     LIMIT 20
    

    我还将您的查询更改为使用ANSI-89 JOIN语法,来自ANSI-89语法。它具有相同的性能,但它更容易阅读,Oracle / SQL Server / Postgres /等支持语法,并提供一致的LEFT JOIN支持。

    另一件事 - 当表和/或列名是MySQL关键字时,你只需要使用反引号。

答案 1 :(得分:2)

在您的查询中,您应该使用显式JOIN,而不需要DISTINCT关键字。

此查询应解决您的问题。我在这里假设用户可以在不同的日期多次提交相同的高分,如果发生这种情况,那么你想要最早的日期:

SELECT T1.userkey, T1.score, username, dateachieved FROM (
    (SELECT userkey, max(score) AS score
    FROM table_highscores
    WHERE gamekey = $gamekey
    GROUP BY userkey) AS T1
    JOIN
    (SELECT userkey, score, min(dateachieved) as dateachieved
    FROM table_highscores
    WHERE gamekey = $gamekey
    GROUP BY userkey, score) AS T2
    ON T1.userkey = T2.userkey AND T1.score = T2.score
) JOIN table_users ON T1.userkey = table_users.userkey
LIMIT 20

答案 2 :(得分:1)

你没有说出你用什么语言来计算差异但是我猜它是PHP因为你在那里使用$gamekey(应该正确转义,顺便说一下)。

如果您的datepaieved字段是DATETIME格式,您可以像这样计算差异:

$diff = round((time() - strtotime($row['dateachieved'])) / 86400);

答案 3 :(得分:0)

我认为你需要更好地澄清你的问题。您能否提供一些数据和预期产出,然后我应该能够为您提供进一步的帮助?