题目:输出2021年里,所有每次试卷得分都能到85分的人以及至少有一次用了一半时间就完成高难度试卷且分数大于80的人的id和活动号,按用户ID排序输出


条件:

1)2021年

2)每次都能有85分 OR 至少有一次用小于等于限定时间,且分数大于80 完成高难度试卷

3)按照用户ID升序输出


解题思路

步骤一:找出,2021年中,每次试卷都有85分的人

一开始想着用各种复杂的办法解决,比如说去判别COUNT(uid) 是否与 score>=85 的记录数相等,来选取符合条件的uid,语句如下(不推荐使用,无必要):

# 方法一
SELECT uid, 
       (CASE WHEN COUNT(uid) = SUM(CASE WHEN score >= 85 THEN 1 ELSE 0 END) 
            THEN 'activity1' ELSE NULL END) AS activity
FROM exam_record 
GROUP BY uid

# 方法二
SELECT uid, 'activity1' AS activity
FROM exam_record AS e1
GROUP BY uid
HAVING COUNT(uid) = (SELECT COUNT(uid) FROM exam_record AS e2
                    WHERE e1.uid = e2.uid AND e2.score >= 85)

后来仔细审题,便发现,只需要确认每个uid的最低分数是否大于等于85即可!!审题的重要性!!最终语句如下:

SELECT uid, 'activity1' AS activity
FROM exam_record
WHERE YEAR(start_time) = 2021
GROUP BY uid
HAVING MIN(score) >= 85

步骤二:找出,2021年中,至少有一次用小于等于限定时间且分数大于80 完成高难度试卷

这一步骤还算简单,需要把exam_record和examination_info两个表进行联立,然后选出来:“时间为2021年”、“试卷难度为高难度”、“分数大于80”、“实际完成时间 小于等于 试卷限定时间”,四个条件皆符合的uid

但有一点需要额外注意,这里需要用到TIMESTAMPDIFF()去计算完成时间,但是第一个参数并不能直接使用MINUTE,而是使用SECOND,原因是:当某些完成时间处于30min与31min之间时(e.g. 30.8分钟),也会被归为30min —— 因此,使用SECOND为参数时,则能够得到更加准确的完成时间(e.g. 30.8分钟会转化成1,848秒),大家可以自己尝试一下去看下区别。查询语句如下:

/* 之所以使用“DISTINCT uid, activity”是因为:下面的查询结果中,uid未必只出现一次(即,同一个uid
有可能会出现多行)—— 有可能会存在某个用户(e.g. 1004)有三次能使用一半时间且分数大于80来完成高难度
试卷。因此,DISTINCT可以对这种结果带来的重复行进行去重 */
SELECT DISTINCT uid, 'activity2' AS activity 

FROM exam_record AS e INNER JOIN examination_info AS i
ON e.exam_id = i.exam_id‘

# 找出完成时间只有限定时间一半的记录;duration * 30是 (duration * 60) / 2的结果
WHERE TIMESTAMPDIFF(SECOND, e.start_time, e.submit_time) <= i.duration * 30
AND e.score > 80
AND YEAR(e.start_time) = 2021
AND i.difficulty = 'hard'

步骤三:使用UNION将前两次结果合并,再对最终合并结果进行排序

这一步就非常简单了,不多说

(SELECT uid, 'activity1' AS activity
FROM exam_record
WHERE YEAR(start_time) = 2021
GROUP BY uid
HAVING MIN(score) >= 85)

UNION 

(SELECT DISTINCT uid, 'activity2' AS activity
FROM exam_record AS e INNER JOIN examination_info AS i
ON e.exam_id = i.exam_id
WHERE TIMESTAMPDIFF(SECOND, e.start_time, e.submit_time) <= i.duration * 30
AND e.score > 80
AND YEAR(e.start_time) = 2021
AND i.difficulty = 'hard')

ORDER BY uid ASC;