选择最新的行并且恰好 2 行具有一个条件和 2 行具有不同的条件

Posted

技术标签:

【中文标题】选择最新的行并且恰好 2 行具有一个条件和 2 行具有不同的条件【英文标题】:Select the latest rows and exactly 2 rows with one condition and 2 with a different condition 【发布时间】:2020-02-03 19:18:02 【问题描述】:

我有一张桌子叫student_grades

╔════╤═══════╤═══════╤═════════════════════╗
║ id │ name  │ grade │ date_added          ║
╠════╪═══════╪═══════╪═════════════════════╣
║ 1  │ bob   │ 23    │ 2019-10-01 14:25:00 ║
╟────┼───────┼───────┼─────────────────────╢
║ 2  │ james │ 45    │ 2019-10-02 17:31:27 ║
╟────┼───────┼───────┼─────────────────────╢
║ 3  │ mike  │ 42    │ 2019-10-03 18:08:13 ║
╟────┼───────┼───────┼─────────────────────╢
║ 4  │ bob   │ 68    │ 2019-10-04 02:00:00 ║
╟────┼───────┼───────┼─────────────────────╢
║ 5  │ mike  │ 83    │ 2019-10-04 09:28:43 ║
╟────┼───────┼───────┼─────────────────────╢
║ 6  │ bob   │ 93    │ 2019-10-04 11:42:00 ║
╟────┼───────┼───────┼─────────────────────╢
║ 7  │ james │ 98    │ 2019-10-05 14:51:20 ║
╟────┼───────┼───────┼─────────────────────╢
║ 8  │ steph │ 72    │ 2019-10-05 15:31:20 ║
╟────┼───────┼───────┼─────────────────────╢
║ 9  │ john  │ 78    │ 2019-10-05 16:33:20 ║
╟────┼───────┼───────┼─────────────────────╢
║ 10 │ john  │ 74    │ 2019-10-05 17:42:23 ║
╟────┼───────┼───────┼─────────────────────╢
║ 10 │ nick  │ 92    │ 2019-10-05 17:59:12 ║
╚════╧═══════╧═══════╧═════════════════════╝

我使用此语句获取学生的最新记录。例如。 James 有 2 条记录。一个是id 2,一个是id 7。所以我想要带有id 7 的那个,因为 id 更大。

然后我随机化这些行并返回我

╔════╤═══════╤═══════╤═════════════════════╗
║ id │ name  │ grade │ date_added          ║
╠════╪═══════╪═══════╪═════════════════════╣
║ 7  │ james │ 86    │ 2019-10-05 12:11:20 ║
╟────┼───────┼───────┼─────────────────────╢
║ 5  │ mike  │ 83    │ 2019-10-04 09:28:43 ║
╚════╧═══════╧═══════╧═════════════════════╝

声明:

SELECT s1.*
FROM student_grade s1
JOIN (SELECT name, MAX(id) AS id
      FROM student_grade
      GROUP BY name) s2 ON s2.name = s1.name AND s2.id = s1.id
ORDER BY RAND()
LIMIT 2;

我的问题是,2个分数在70-80之间(随机选择)和2个分数在90-99之间(随机选择)的学生,我如何选择最新记录。 p>

SELECT s1.*
FROM student_grade s1
JOIN (SELECT name, MAX(id) AS id
      FROM student_grade
      WHERE (grade >= 70 and grade <= 80) or (grade >= 90 and grade <= 99)
      GROUP BY name) s2 ON s2.name = s1.name AND s2.id = s1.id
ORDER BY RAND()
LIMIT 4;

但如果我按照上面的说法,它可能给我 3 个得分为 70-80 的学生和 1 个得分为 90-99 的学生。我想要正好 2 个 70-80 岁的学生(随机选择)和 90-99 岁的正好 2 个(随机选择)。我该怎么做?

【问题讨论】:

【参考方案1】:

我的问题是,我如何选择 2 个分数在 70 到 80 之间的学生(随机选择)和 2 个分数在 90 到 99 之间的学生(随机选择)的最新记录。

mysql 8+ 中,最简单的方法是使用行号:

select sg.*
from (select sg.*
             row_number() over (partition by (case when grade between 70 and 80 then 1 when grade between 90 and 99 then 2 else 3 end)
                                order by rand()
                               ) as seqnum
      from student_grades sg
      where grade between 70 and 80 or grade between 90 and 99
     ) sg
where seqnum <= 2;

【讨论】:

【参考方案2】:

您可以将两个现有查询UNION ALL 一起获得您想要的结果:

(SELECT s1.*
 FROM student_grade s1
 JOIN (SELECT name, MAX(id) AS id
       FROM student_grade
       WHERE grade BETWEEN 70 AND 80
       GROUP BY name) s2 ON s2.name = s1.name AND s2.id = s1.id
 ORDER BY RAND()
 LIMIT 2)
UNION ALL
(SELECT s1.*
 FROM student_grade s1
 JOIN (SELECT name, MAX(id) AS id
       FROM student_grade
       WHERE grade BETWEEN 90 AND 99
       GROUP BY name) s2 ON s2.name = s1.name AND s2.id = s1.id
 ORDER BY RAND()
 LIMIT 2)

Demo on dbfiddle

我们可以使用UNION ALL,因为我们知道不会有任何重复,因为等级范围不同。

【讨论】:

谢谢。如果我想再次随机化整个结果怎么办。所以我从70-80 范围中选择2,从90-99 范围中选择2。在我得到这 4 个结果之后。我怎样才能随机化这 4 个的顺序。 @Mick 理论上UNION 的输出是不确定的,但要确保它是随机的,您可以将ORDER BY RAND() 添加到查询的末尾

以上是关于选择最新的行并且恰好 2 行具有一个条件和 2 行具有不同的条件的主要内容,如果未能解决你的问题,请参考以下文章

选择最新的行,然后随机化这些行,然后显示随机化的前 2 行

在匹配选择条件的行之前选择 n 行

SQL选择具有最大和最小日期的行

通过 id mysql 查找具有最新日期的行

如何有效地列出恰好具有“n”行的文件?

在 Table1 中查找与 Table2 中的条件行匹配的行