MySQL UNION合并独立SQL查询报1064错误及成绩报表实现问题
报错根因
- 和NULL值无关,语法错误的直接原因是
UNION拼接的单个子查询中,不能独立使用ORDER BY子句(除非子查询包裹括号且搭配LIMIT做结果限制),你在第一个SELECT块末尾写的order by B.grade desc,A.name直接接在union关键字前,触发了语法解析错误。 - 另外你的排序逻辑本身也不符合UNION的执行规则:UNION最终返回的是一个完整结果集,只能有一套全局排序规则,无法让两段结果分别按不同规则排序后再拼接。
- 额外说明:你原SQL漏查了业务要求的
Mark列,即使语法修正后输出字段也不符合需求。
修正后的UNION实现
如果要保留UNION写法,需要把两个查询块作为子查询包裹,在外层统一做排序。因为两段查询的分数区间完全不重叠,用UNION ALL代替UNION可以省去去重开销,执行效率更高:
SELECT id, Name, Grade, Marks FROM ( SELECT A.id, A.Name, B.Grade, A.Marks FROM Students A, Grades B WHERE A.Marks >= B.min_mark AND A.Marks <= B.max_mark AND B.Grade >= 8 UNION ALL SELECT A.id, NULL AS Name, B.Grade, A.Marks FROM Students A, Grades B WHERE A.Marks >= B.min_mark AND A.Marks <= B.max_mark AND B.Grade < 8 ) t ORDER BY Grade DESC, -- 8分及以上按姓名升序 CASE WHEN Grade >= 8 THEN Name END ASC, -- 7分及以下按分数升序 CASE WHEN Grade < 8 THEN Marks END ASC
无UNION的替代方案
不需要拆分两段查询,直接通过CASE表达式单次关联查询即可实现所有需求,逻辑更简洁,执行效率也更高:
SELECT A.id, -- 低于8分姓名显示为NULL CASE WHEN B.Grade >= 8 THEN A.Name ELSE NULL END AS Name, B.Grade, A.Marks FROM Students A INNER JOIN Grades B ON A.Marks BETWEEN B.min_mark AND B.max_mark ORDER BY -- 全局按成绩降序 B.Grade DESC, -- 8分及以上同分段按姓名升序 CASE WHEN B.Grade >= 8 THEN A.Name END ASC, -- 7分及以下同分段按分数升序 CASE WHEN B.Grade < 8 THEN A.Marks END ASC
该写法用显式JOIN替代了隐式逗号关联,可读性更好;所有业务规则都通过SELECT和ORDER BY中的CASE表达式直接实现,不需要额外合并结果集。
内容的提问来源于stack exchange,提问作者Leos Literak
相关产品推荐
相关产品推荐

