MySQL使用UNION合并带GROUP BY、ORDER BY查询报错解决方案
错误原因
MySQL中直接对带ORDER BY的子查询使用UNION会触发1221语法错误,核心规则是:UNION拼接的子查询默认不允许单独使用ORDER BY,除非子查询用括号包裹且搭配LIMIT,否则优化器会判定子查询内的排序无意义直接报错。
你之前用OR合并WHERE条件的方案无法满足排序要求,是因为这种写法会把两类条件的callback数据混合聚合,无法区分记录来源,自然没法实现查询1结果优先展示的规则。
实现代码
通过加来源标记、外层聚合去重、自定义排序的方式实现需求,代码如下:
SELECT id, stage, property_id, due_soon_callbacks_sum FROM ( -- 查询1结果,标记优先级为0(排序时靠前) (SELECT deals.id, deals.stage, deals.property_id, SUM(callbacks.created_at < '2022-07-06 16:59:21') AS due_soon_callbacks_sum, 0 AS source_priority FROM `deals` INNER JOIN `requests` ON `requests`.`deal_id` = `deals`.`id` INNER JOIN `callbacks` ON `callbacks`.`request_id` = `requests`.`id` WHERE callbacks.overdue_at > '2022-07-07 16:59:21' GROUP BY `deals`.`id`) UNION ALL -- 查询2结果,标记优先级为1(排序时靠后) (SELECT deals.id, deals.stage, deals.property_id, SUM(callbacks.created_at < '2022-07-06 16:59:21') AS due_soon_callbacks_sum, 1 AS source_priority FROM `deals` INNER JOIN `requests` ON `requests`.`deal_id` = `deals`.`id` INNER JOIN `callbacks` ON `callbacks`.`request_id` = `requests`.`id` WHERE callbacks.overdue_at < '2022-07-07 16:59:21' GROUP BY `deals`.`id`) ) AS combined_result -- 按deal id分组,优先保留优先级更高(数值更小)的来源记录 GROUP BY id -- 排序规则:先保证查询1的所有记录在前,同来源内按回调数倒序 ORDER BY MIN(source_priority) ASC, due_soon_callbacks_sum DESC;
逻辑说明
- 用
UNION ALL代替默认去重的UNION,避免提前全局去重打乱优先级,同时查询性能更高 - 给两个子查询增加
source_priority标记,查询1的标记值更小,排序时会排在前面 - 外层按
deals.id分组时,MIN(source_priority)会自动选中同id下优先级最高的记录:只要id在查询1结果中存在,就会保留查询1的对应记录,自动丢弃查询2中的重复项 - 最终排序先保证查询1的全部记录排在最前,查询2独有的记录排在后面,两类记录内部都保持
due_soon_callbacks_sum倒序的规则,完全匹配需求。
内容的提问来源于stack exchange,提问作者skamsie
相关产品推荐
相关产品推荐

