【问题标题】:Mysql Find multiple rows from each groupMysql 从每个组中查找多行
【发布时间】:2013-12-07 00:29:49
【问题描述】:

我有一个包含 3 列的表,student_idsection_idmarks,每列都包含整数值,student_id 是具有唯一值的主字段。现在我需要为以下 3 个场景编写查询(PS:这仅用于学习目的,所以如果可能的话,如果您能告诉我一些替代的逻辑方法,那就太好了):

  1. 找出每个部分排名第三的学生。
  2. 找出每个部分排名第 2、3、4 的学生。
  3. 找到每个部分中排名第 4 的学生(如果有的话),如果一个部分中有多个分数相同的学生,则跳过下一个排名。假设有 3 名学生获得相同的分数,他们将在一个部分中排名第二,然后跳过第三和第四名,下一个分数低于他们的学生将排名第五。

对于我尝试的第一个:

SELECT * FROM `students` s 
 WHERE s.student_id=
(
  SELECT student_id 
    FROM students 
   WHERE s.section_id=section_id 
   ORDER BY marks DESC 
   LIMIT 2,1
) 
 GROUP BY section_id 
 ORDER BY marks DESC

虽然我不确定优化是否可行。

对于我尝试使用IN 的下一个,否则我无法在子查询中获取多于一行,但它说mysql 在IN 子句中不支持LIMIT,有没有为第二种情况修改此查询的方法?

最后,我不知道如何处理第三个。

我在http://sqlfiddle.com/#!2/6442fb/1创建了一个测试表

任何帮助表示赞赏。

【问题讨论】:

标签: mysql sql


【解决方案1】:

不幸的是,MySQL 仍然缺乏对分析函数的支持。特别是RANK()RANK_DENSE() 会很有帮助。模拟它们的一种方法是使用用户变量:

SELECT student_id, section_id, marks
  FROM
(
  SELECT s.*, @n := IF(@s = section_id, IF(@m = marks, @n, @n + 1), 1) rank, 
         @s := section_id, @m := marks
    FROM students s CROSS JOIN (SELECT @n := 0, @s := NULL, @m := NULL) i
   ORDER BY section_id, marks DESC
) q
 WHERE rank = 3
 ORDER BY marks DESC;

SELECT student_id, section_id, marks
  FROM
(
  SELECT s.*, @n := IF(@s = section_id, IF(@m = marks, @n, @n + 1), 1) rank, 
         @s := section_id, @m := marks
    FROM students s CROSS JOIN (SELECT @n := 0, @s := NULL, @m := NULL) i
   ORDER BY section_id, marks DESC
) q
 WHERE rank BETWEEN 2 AND 4
 ORDER BY section_id, marks DESC;

SELECT student_id, section_id, marks
  FROM
(
  SELECT s.*, @n := IF(@s = section_id, @n + 1, 1),
         @rn := IF(@m = marks, @rn, @n) rank,
         @s := section_id, @m := marks
    FROM students s CROSS JOIN (SELECT @n := 0, @rn := 0, @s := NULL, @m := NULL) i
   ORDER BY section_id, marks DESC
) q
 WHERE rank = 4
 ORDER BY marks DESC;

这里是SQLFiddle演示

【讨论】:

  • 哇,看起来很棒!但是你能解释一下这个查询吗?我尝试查找用户变量,但随后在上面的交叉连接中迷路了。
  • @Bluemagica CROSS JOIN 仅用于初始化变量。在内部选择中,我们正确地对结果集进行排序,并且在选择行时,我们通过将section_idmarks 的当前值与前一行的值(@s@m)进行比较来计算排名;如果我们遇到一个新的部分 id,我们将计数器重置为 1,否则我们检查标记的当前值是否等于前一行的值,而不是保持排名相同,否则我们将 1 添加到它。在外部选择中,我们只过滤掉除目标排名之外的所有内容。前两个查询模拟 RANK_DENSE() 和第三个 `RAN
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-24
  • 1970-01-01
  • 2012-05-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多