SELECT UID,
       round(avg(new_socre)) AS avg_score,       round(avg(time_diff), 1) AS avg_time_tookFROM  (SELECT er.uid,          IF (er.submit_time IS NOT NULL, TIMESTAMPDIFF(MINUTE, start_time, submit_time), ef.duration) AS time_diff,          IF (er.submit_time IS NOT NULL,er.score,0) AS new_socre   FROM exam_record er   LEFT JOIN user_info uf ON er.uid = uf.uid   LEFT JOIN examination_info ef ON er.exam_id = ef.exam_id   WHERE uf.LEVEL = 0 AND ef.difficulty = 'hard' ) tGROUP BY UIDORDER BY UID
  • 1.
  • 2.

这个查询使用了 IF 函数来处理 exam_record 表中的数据。IF 函数在这里用来决定当某些条件满足时应该返回什么值。下面是这个查询的逐行解释:

  1. 子查询:
  • SELECT er.uid, ... 这一行指定了子查询选择哪些字段。
  • IF (er.submit_time IS NOT NULL, TIMESTAMPDIFF(MINUTE, start_time, submit_time), ef.duration) AS time_diff: 这个表达式检查 submit_time 是否为 NULL
  • 如果 submit_time 不是 NULL,则使用 TIMESTAMPDIFF 函数计算考试开始时间 (start_time) 到提交时间 (submit_time) 的分钟数。
  • 如果 submit_timeNULL,则使用 ef.duration 作为考试持续时间。
  • IF (er.submit_time IS NOT NULL, er.score, 0) AS new_score: 这个表达式检查 submit_time 是否为 NULL
  • 如果 submit_time 不是 NULL,则使用 er.score 作为分数。
  • 如果 submit_timeNULL,则使用 0 作为分数。
  1. 外部查询:
  • SELECT UID, round(avg(new_score)) AS avg_score, round(avg(time_diff), 1) AS avg_time_took: 这一行指定了外部查询选择哪些字段。
  • FROM ( ... ) t: 这里使用了之前定义的子查询结果,并将其命名为 t
  • GROUP BY UID: 按照 UID 对结果进行分组。
  • ORDER BY UID: 按照 UID 对最终结果进行排序。
整体解释

这个查询的目标是从 exam_record 表中获取每个用户的平均分数和平均完成时间,但只针对那些难度为 “hard” 的考试,并且用户级别为 0 的用户。

  • 首先,它从 exam_record 表中选择了用户 ID (uid),并使用 IF 函数来确定完成时间 (time_diff) 和分数 (new_score)。
  • 对于完成时间,如果考试被提交了,则计算提交时间与开始时间之间的差值;如果没有提交,则使用 duration 字段。
  • 对于分数,如果考试被提交了,则使用实际的分数;如果没有提交,则分数为 0
  • 接着,外部查询对子查询的结果进行分组和聚合,计算每个用户的平均分数和平均完成时间。
  • 最后,按照 UID 对结果进行排序。

这样,查询就生成了一个列表,列出了每个用户的平均分数和平均完成时间,特别关注的是那些完成了难度为 “hard” 的考试的用户。