【问题标题】:mySQL query, for discrete results limited and ordered by a joined columnmySQL 查询,用于由连接列限制和排序的离散结果
【发布时间】:2010-01-29 13:54:37
【问题描述】:

我有两张桌子

User
  id
  name

Result
  id
  user_id
  score
  created_at

cron 作业每小时运行一次,并将数据放入每个用户的结果表中 - 根据一些外部变量参数为他们分配分数。

因此 Result 表包含每个用户的许多记录。

我想在任何给定时间检索“前十名”用户。所以每个用户应该只返回一行,它应该包含他们最近的可用分数,理想情况下只有 10 行与得分最高的十个用户相关。

我目前获取所有结果并使用 php 进行腿部工作,我相当肯定如果由数据库处理会更快、更高效。但我不知道从哪里开始。

【问题讨论】:

  • 用户的得分是最近的记录还是所有记录的总和?
  • 分数只是最近的记录。

标签: mysql join


【解决方案1】:
SELECT u.id,
       u.name,
       r.score
FROM Result r
JOIN
  (SELECT user_id, MAX(created_at) AS max_date
   FROM Result
   GROUP BY user_id) lr ON r.user_id=lr.user_id
JOIN User u ON u.id=r.user_id
WHERE r.created_at=lr.max_date
ORDER BY r.score DESC LIMIT 10;

示例运行:

mysql> insert into User (name) values ('foo'), ('bar');
mysql> insert into Result (user_id, score, created_at) values (1,100,'2010-01-20'), (2,150,'2010-01-20'),(1,150,'2010-01-21'),(2,100,'2010-01-21');
mysql> SELECT u.id,        u.name,        r.score FROM Result r JOIN   (SELECT user_id, MAX(created_at) AS max_date    FROM Result    GROUP BY user_id) lr ON r.user_id=lr.user_id JOIN User u ON u.id=r.user_id WHERE r.created_at=lr.max_date ORDER BY r.score DESC LIMIT 10;
+----+------+-------+
| id | name | score |
+----+------+-------+
|  1 | foo  |   150 | 
|  2 | bar  |   100 | 
+----+------+-------+
2 rows in set (0.00 sec)

【讨论】:

  • +1 我们以相同的语句结束,但我添加了 DISTINCT 子句
  • 警告:当一个用户可能有多个相同的created_at 时,这将无法正常工作。如果这在逻辑上不能发生,我会通过在user_id,created_at 上创建一个唯一索引来确保它。这也将加快查询速度。
  • :) 不错。我已经把它放进去并通过了结果,它看起来确实正确。那太棒了。干杯。感谢所有帮助过的人!
  • @Tomalak 谢谢 - 不应该是个问题,除非其他事情发生了可怕的错误。
【解决方案2】:

好的,获取每个用户的最后创建日期,然后从那里选择不同的用户,他们的分数按后代顺序排序,并取第 10 行

SELECT DISTINCT u.id, u.name, r.score, md.max_date
FROM user u
INNER JOIN result r ON (u.id=r.user_id)
INNER JOIN (
 SELECT user_id, MAX(created_at) max_date
 FROM result
 GROUP BY user_id
) md ON (md.user_id=r.user_id AND r.created_at=md.max_date)
ORDER BY r.score DESC
LIMIT 10

【讨论】:

  • 我刚试过那个 patrick,我以为我明白了,但它只返回 1 个结果,尽管有大量用户,而且许多用户的分数来自最后一个 cron 条目。跨度>
  • 我已经修改了它更好吗?
  • @patrick:你的 sql 在我的 mysql 上不起作用,它在没有 group by 命令的情况下给出了无效的 group 命令组合。但是在内部连接选择中添加 group by 会导致结果,但它是错误的。 (不知道cr0wn3r使用的是哪个DB)
  • 内部联接中的 GROUP BY id 不正确,因为我认为 id 是结果表的主键。它需要按 user_id 分组。
  • 嗯。现在这似乎返回了 10 个结果,排序正确,但都是针对同一个用户的。
【解决方案3】:

这可能有效:

从中选择 u.id、u.name、x.score 用户 u, (select user_id, sum(score) score from results) x 其中 u.id = x.user_id 按 x.score 排序 限制 10

【讨论】:

  • 您忘记了日期条件(最近的分数),您正在对所有分数结果求和
  • 是的 - 肯定只需要最近的分数,而不是总和。
【解决方案4】:

这应该可以完成工作:

SELECT user.id, user.name, MAX(result.score) maxscore FROM user
Left Join result on result.user_id=user.id
GROUP By user.id
ORDER By maxscore DESC
LIMIT 0,10

第二次尝试还不确定...

SELECT user.id, user.name, result.score, result.created_at FROM user
LEFT JOIN result ON result.user_id = user.id
WHERE result.id IN (SELECT r.id FROM result r GROUP By r.user_id ORDER By MAX(r.created_at))
ORDER By score DESC
LIMIT 0,10

【讨论】:

  • 没有必要是左连接,因为他正在寻找前十名的分数,不应该返回没有分数的用户。
  • 这不会给出玩家最近的分数。它将给出玩家的最高分数。
  • 哇。那太棒了。刚刚测试,它的工作原理。我想加入很好,因为这意味着我可以使用 user.name,否则我不会。我想。
  • 啊,是的,好的。我认为这是他们迄今为止的最高分。
  • 这个想法是它应该比较每个用户的最新结果,并返回该组最新结果中得分最高的十个用户。
猜你喜欢
  • 1970-01-01
  • 2015-11-26
  • 2011-01-17
  • 2011-08-11
  • 2020-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多