查找用户的最高分数和相关详细信息

发布于 2024-08-26 21:22:50 字数 297 浏览 10 评论 0原文

我有一个表,用户在其中存储分数和有关该分数的其他信息(例如分数注释或所用时间等)。我想要一个 mysql 查询来查找每个用户的个人最佳分数及其相关的注释和时间等。

我尝试使用的是这样的:

SELECT *, MAX(score) FROM table GROUP BY (user)

问题是虽然您可以从该查询 [MAX(score)] 中额外获得用户的个人最佳成绩,但返回的注释和时间等与最高分数无关,而是与不同的分数相关联(特别是 * 中包含的分数)。有没有办法编写一个查询来选择我想要的内容?或者我必须在 PhP 中手动完成?

I have a table in which users store scores and other information about said score (for example notes on score, or time taken etc). I want a mysql query that finds each users personal best score and it's associated notes and time etc.

What I have tried to use is something like this:

SELECT *, MAX(score) FROM table GROUP BY (user)

The problem with this is that whilst you can extra the users personal best from that query [MAX(score)], the returned notes and times etc are not associated with the maximum score, but a different score (specifically the one contained in *). Is there a way I can write a query that selects what I want? Or will I have to do it manually in PhP?

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

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

发布评论

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

评论(3

你是暖光i 2024-09-02 21:22:51

我假设您只希望每个玩家获得一个结果,即使他们多次获得相同的最高分。我还假设您希望每个玩家第一次获得个人最佳成绩,以防出现重复。

有几种方法可以做到这一点。这是一种 MySQL 特定的方法:

SELECT user, scoredate, score, notes FROM (
    SELECT *, @prev <> user AS is_best, @prev := user
    FROM table1, (SELECT @prev := -1) AS vars
    ORDER BY user, score DESC, scoredate
) AS T1
WHERE is_best

这是一种使用普通 SQL 的更通用的方法:

SELECT T3.* FROM table1 AS T3
JOIN (
    SELECT T1.user, T1.score, MIN(scoredate) AS scoredate
    FROM table1 AS T1
    JOIN (SELECT user, MAX(score) AS score FROM table1 GROUP BY user) AS T2
    ON T1.user = T2.user AND T1.score = T2.score
    GROUP BY T1.user
) AS T4
ON T3.user = T4.user AND T3.score = T4.score AND T3.scoredate = T4.scoredate

结果:

1, '2010-01-01 17:00:00', 50, 'Much better'
2, '2010-01-01 14:00:00', 100, 'Perfect score'

测试数据 我用来测试这个:

CREATE TABLE table1 (user INT NOT NULL, scoredate DATETIME NOT NULL, score INT NOT NULL, notes NVARCHAR(100) NOT NULL);
INSERT INTO table1 (user, scoredate, score, notes) VALUES
(1, '2010-01-01 12:00:00', 10, 'First attempt'),
(1, '2010-01-01 17:00:00', 50, 'Much better'),
(1, '2010-01-01 22:00:00', 30, 'Time for bed'),
(2, '2010-01-01 14:00:00', 100, 'Perfect score'),
(2, '2010-01-01 16:00:00', 100, 'This is too easy');

I'm assuming that you only want one result per player, even if they have scored the same maximum score more than once. I am also assuming that you want each player's first time that they got their personal best in the case that there are repeats.

There's a few ways of doing this. Here's a way that is MySQL specific:

SELECT user, scoredate, score, notes FROM (
    SELECT *, @prev <> user AS is_best, @prev := user
    FROM table1, (SELECT @prev := -1) AS vars
    ORDER BY user, score DESC, scoredate
) AS T1
WHERE is_best

Here's a more general way that uses ordinary SQL:

SELECT T3.* FROM table1 AS T3
JOIN (
    SELECT T1.user, T1.score, MIN(scoredate) AS scoredate
    FROM table1 AS T1
    JOIN (SELECT user, MAX(score) AS score FROM table1 GROUP BY user) AS T2
    ON T1.user = T2.user AND T1.score = T2.score
    GROUP BY T1.user
) AS T4
ON T3.user = T4.user AND T3.score = T4.score AND T3.scoredate = T4.scoredate

Result:

1, '2010-01-01 17:00:00', 50, 'Much better'
2, '2010-01-01 14:00:00', 100, 'Perfect score'

Test data I used to test this:

CREATE TABLE table1 (user INT NOT NULL, scoredate DATETIME NOT NULL, score INT NOT NULL, notes NVARCHAR(100) NOT NULL);
INSERT INTO table1 (user, scoredate, score, notes) VALUES
(1, '2010-01-01 12:00:00', 10, 'First attempt'),
(1, '2010-01-01 17:00:00', 50, 'Much better'),
(1, '2010-01-01 22:00:00', 30, 'Time for bed'),
(2, '2010-01-01 14:00:00', 100, 'Perfect score'),
(2, '2010-01-01 16:00:00', 100, 'This is too easy');
聽兲甴掵 2024-09-02 21:22:51

您可以使用子查询进行连接,如下例所示:

SELECT   t.*,
         sub_t.max_score
FROM     table t
JOIN     (SELECT   MAX(score) as max_score,
                   user
          FROM     table
          GROUP BY user) sub_t ON (sub_t.user = t.user AND
                                   sub_t.max_score = t.score);

上述查询可以解释如下。它以:

SELECT t.* FROM table t;

...这本身显然会列出表的所有内容。目标是仅保留代表特定用户最高分数的行。因此,如果我们有以下数据:

+------------------------+
| user | score |  notes  | 
+------+-------+---------+
|    1 |    10 |  note a |
|    1 |    15 |  note b |    
|    1 |    20 |  note c |
|    2 |     8 |  note d |
|    2 |    12 |  note e |
|    2 |     5 |  note f |
+------+-------+---------+

...我们只想保留“note c”和“note e”行。

要找到我们想要保留的行,我们可以简单地使用:

SELECT MAX(score), user FROM table GROUP BY user;

请注意,我们无法从上面的查询中获取 Notes 属性,因为正如您已经注意到的,对于未使用 聚合函数,如 MAX() 或不是 GROUP BY 子句的一部分。要进一步阅读此主题,您可能需要检查:

现在我们只需要保留第一个查询中与第二个查询匹配的行。我们可以使用INNER JOIN来做到这一点:

...
JOIN     (SELECT   MAX(score) as max_score,
                   user
          FROM     table
          GROUP BY user) sub_t ON (sub_t.user = t.user AND
                                   sub_t.max_score = t.score);

子查询的名称为sub_t。它是所有具有个人最好成绩的用户的集合。 JOINON 子句将限制应用于相关字段。请记住,我们只想保留属于此子查询的行。

You can join with a sub query, as in the following example:

SELECT   t.*,
         sub_t.max_score
FROM     table t
JOIN     (SELECT   MAX(score) as max_score,
                   user
          FROM     table
          GROUP BY user) sub_t ON (sub_t.user = t.user AND
                                   sub_t.max_score = t.score);

The above query can be explained as follows. It starts with:

SELECT t.* FROM table t;

... This by itself will obviously list all the contents of the table. The goal is to keep only the rows that represent a maximum score of a particular user. Therefore if we had the data below:

+------------------------+
| user | score |  notes  | 
+------+-------+---------+
|    1 |    10 |  note a |
|    1 |    15 |  note b |    
|    1 |    20 |  note c |
|    2 |     8 |  note d |
|    2 |    12 |  note e |
|    2 |     5 |  note f |
+------+-------+---------+

...We would have wanted to keep just the "note c" and "note e" rows.

To find the rows that we want to keep, we can simply use:

SELECT MAX(score), user FROM table GROUP BY user;

Note that we cannot get the notes attribute from the above query, because as you had already noticed, you would not get the expected results for fields not aggregated with an aggregate function, like MAX() or not part of the GROUP BY clause. For further reading on this topic, you may want to check:

Now we only need to keep the rows from the first query that match the second query. We can do this with an INNER JOIN:

...
JOIN     (SELECT   MAX(score) as max_score,
                   user
          FROM     table
          GROUP BY user) sub_t ON (sub_t.user = t.user AND
                                   sub_t.max_score = t.score);

The sub query is given the name sub_t. It is the set of all the users with the personal best score. The ON clause of the JOIN applies the restriction to the relevant fields. Remember that we only want to keep rows that are part of this subquery.

樱娆 2024-09-02 21:22:51
SELECT *
FROM table t
ORDER BY t.score DESC
GROUP BY t.user
LIMIT 1

旁注:指定字段比使用 SELECT * 更好

SELECT *
FROM table t
ORDER BY t.score DESC
GROUP BY t.user
LIMIT 1

Side note: It is better to specify the fields than use SELECT *

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