Select 每个用户的前三名总和

Select sum of top three scores for each user

我在为以下问题编写查询时遇到问题。我已经尝试了一些现有的查询,但无法获得我需要的结果。

我有这样的结果 table:

userid  score timestamp
1       50    5000
1       100   5000 
1       400   5000 
1       500   5000 
2       100   5000 
3       1000  4000 

查询的预期输出是这样的:

userid  score
3       1000
1       1000
2       100

我想要 select 一个顶部列表,其中我为每个用户汇总了 n 个最佳分数,如果有平局,则时间戳最低的用户最高。我真的试图查看所有旧帖子,但找不到对我有帮助的帖子。

这是我尝试过的:

SELECT sum(score) FROM (
   SELECT score 
   FROM results 
   WHERE userid=1 ORDER BY score DESC LIMIT 3
) as subquery

这给了我一个用户的结果,但我想要一个按顺序获取所有结果的查询。

从 table 中选择前三名分数的查询。

SELECT score FROM 结果 分组 idscore 描述排序 限制 3;

你能试试这个吗?

SELECT score FROM result GROUP BY id ORDER BY score DESC, timestamp ASC LIMIT 3;

如果2个用户的分数相同则按时间排序

您可以使用子查询

SELECT r.userid,
(  SELECT sum(r2.score)
   FROM results r2
   WHERE r2.userid = r.userid 
   ORDER BY score DESC 
   LIMIT 3
) as sub
FROM result r
GROUP BY r.userid
ORDER BY sub desc

这是一个非常典型的 greatest-n-per-group 问题。当我看到这些时,我通常使用这样的相关子查询:

SELECT *
FROM myTable m
WHERE(
  SELECT COUNT(*)
  FROM myTable mT
  WHERE mT.userId = m.userId AND mT.score >= m.score) <= 3;

这不是完整的解决方案,因为它只为您提供其所在行中每个用户的前三名得分。要获得总数,您可以像这样使用 SUM() 环绕该子查询:

SELECT userId, SUM(score) AS totalScore
FROM(
  SELECT userId, score
  FROM myTable m
  WHERE(
    SELECT COUNT(*)
    FROM myTable mT
    WHERE mT.userId = m.userId AND mT.score >= m.score) <= 3) tmp
GROUP BY userId;

这是一个 SQL Fiddle 示例。

编辑

关于排序(我第一次忘记了),你可以按totalScore降序排序,然后按MIN(timestamp)升序排序,这样时间戳最小的用户就会出现在列表中的第一位.这是更新后的查询:

SELECT userId, SUM(score) AS totalScore
FROM(
  SELECT userId, score, timeCol
  FROM myTable m
  WHERE(
    SELECT COUNT(*)
    FROM myTable mT
    WHERE mT.userId = m.userId AND mT.score >= m.score) <= 3) tmp
GROUP BY userId
ORDER BY totalScore DESC, MIN(timeCol) ASC;

这是更新后的 Fiddle link.

编辑 2

正如 JPW 在评论中指出的那样,如果用户对多个问题的得分相同,则此查询将不起作用。要解决这个问题,您可以在子查询中添加一个附加条件,以按时间戳为用户排序三行,如下所示:

SELECT userId, SUM(score) AS totalScore
FROM(
  SELECT userId, score, timeCol
  FROM myTable m
  WHERE(
    SELECT COUNT(*)
    FROM myTable mT
    WHERE mT.userId = m.userId AND mT.score >= m.score 
      AND mT.timeCol <= m.timeCol) <= 3) tmp
GROUP BY userId
ORDER BY totalScore DESC, MIN(timeCol) ASC;

我仍在研究解决方案,以找出如何处理用户标识、分数和时间戳都相同的情况。在这种情况下,您将不得不寻找另一个决胜局。也许你有一个主键列,你可以选择取higher/lower个主键?

你应该这样做

SELECT SUM(score) as total, min(timestamp) as first, userid FROM scores
GROUP BY userid
ORDER BY total DESC, first ASC

这比子查询更有效。如果要提取的字段多于 userid,则需要将它们添加到 group by.

这个will当然不会限制pr user的积分数,看来确实需要子查询才能解决。