select *
from
(select
exam_id as tid,
count(distinct uid) as uv,
count(*) as pv
from exam_record
group by exam_id
order by uv desc, pv desc)as t1
union all
select *
from
(select
question_id as tid,
count(distinct uid) as uv,
count(*) as pv
from practice_record
group by question_id
order by uv desc, pv desc)as t2
关键在于 SQL 标准对 UNION ALL 的限制:
在
UNION或UNION ALL的各个分支(SELECT 子句)中,ORDER BY是不允许的,除非它在一个子查询或派生表(derived table)中。
也就是说:
- 在 UNION ALL 语句的每个分支中,ORDER BY 不能直接生效。
- 只有整个 UNION ALL 的结果集(整个联合后的结果)才能有一个总的 ORDER BY。
- 如果你想在每个部分单独排序,你必须把它放进一个 子查询(subquery)或派生表(derived table),让排序在该作用域内完成。
在这段语句中:
(select
exam_id as tid,
count(distinct uid) as uv,
count(*) as pv
from exam_record
group by exam_id
order by uv desc, pv desc)
union all
(select
question_id as tid,
count(distinct uid) as uv,
count(*) as pv
from practice_record
group by question_id
order by uv desc, pv desc)
SQL 解析器会在解析 UNION ALL 时抛弃两个分支的 ORDER BY,因为它不知道如何在未确定最终联合结果之前就对各自排序。
因此:
- 两个分支各自的 ORDER BY 被忽略;
- 系统会直接把两个结果集合并(无顺序保证);
- 最终输出的顺序是 未定义的(随机的)。
为什么加上 SELECT * FROM (...) AS t1 就能工作
当你写成:
SELECT * FROM ( SELECT ... ORDER BY ... ) AS t1
你实际上是在告诉 SQL:
“我先在内部生成一个排序好的临时表(派生表 t1),然后再拿这个排序好的结果去做下一步操作。”
此时 ORDER BY 的作用域被限制在 子查询内部,SQL 会:
- 执行内部的 SELECT ... ORDER BY ...;
- 把排序后的结果放进临时表;
- 再执行 UNION ALL。
因此,每个子查询(t1 和 t2)内部都各自是 有序结果集。

京公网安备 11010502036488号