思路
select * from (SELECT distinct(r.id) rid,r.id as examinationRecordId,u.nick_name,d.dept_name,r.exam_score,r.exam_start_time,r.exam_id FROM `examination_record` r
inner JOIN user u on u.user_id = r.user_id
inner join ept d on u.dept_id = d.dept_id
where r.del_flag = 0 and r.exam_id in (select id from `plan_exam` where plan_son_exam_id = 1 )
order by r.exam_start_time desc ) a
group by a.exam_id
思路:先进行排序,然后再进行分组,获取每组的第一条。
写distinct(r.id)是为了防止合并的构造(derived_merge)(derived_merge指的是一种查询优化技术,作用就是把派生表合并到外部的查询中,提高数据检索的效率。这个特性在MySQL5.7版本中被引入.)
什么是DERIVED_MERGE ?
derived_merge指的是一种查询优化技术,作用就是把派生表合并到外部的查询中,提高数据检索的效率。这个特性在MySQL5.7版本中被引入,可以通过如下SQL语句进行查看/开启/关闭等操作。
- 查看是否开启
mysql> show global variables like '%optimizer_switch%'\G
*************************** 1. row ***************************
Variable_name: optimizer_switch
Value: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on
1 row in set (0.00 sec)
derived_merge=on表示开启,如果是off的话表示关闭。
- 关闭derived_merge:
set session optimizer_switch='derived_merge=off'; //session
set global optimizer_switch='derived_merge=off'; //global
- 开启derived_merge:
set session optimizer_switch='derived_merge=on'; //session
set global optimizer_switch='derived_merge=on'; //global
可以通过在子查询中使用任何阻止合并的构造来禁用合并,尽管这些构造对实现的影响并不明确。 防止合并的构造对于派生表和视图引用是相同的:
聚合函数( SUM() , MIN() , MAX() , COUNT()等)
DISTINCT
GROUP BY
HAVING
LIMIT
UNION或UNION ALL
选择列表中的子查询
分配给用户变量
仅引用文字值(在这种情况下,没有基础表)
order by失效的场景
select * from (SELECT r.id as examinationRecordId,u.nick_name,d.dept_name,r.exam_score,r.exam_start_time,r.exam_id FROM `examination_record` r
inner JOIN user u on u.user_id = r.user_id
inner join ept d on u.dept_id = d.dept_id
where r.del_flag = 0 and r.exam_id in (select id from `plan_exam` where plan_son_exam_id = 1 )
order by r.exam_start_time desc ) a
group by a.exam_id
原理分析:
我们这里使用了临时表排序,继而对其结果进行分组,结果显示失败,加了distinct(r.id) rid,后结果正确,原因是因为临时表(派生表derived table)中使用order by且使其生效,必须满足三个条件:
外部查询禁止分组或者聚合
外部查询未指定having, order by
外部查询将派生表或者视图作为from句中唯一指定源
不满足这三个条件,order by会被忽略。