EXCEPT能直接比较两个GROUP BY结果,但要求列数、顺序、数据类型严格一致且语义对等;否则报错或返回空结果,不执行而非不准。

直接用 EXCEPT 最快,但只适用于结构完全一致、且你接受自动去重和单向差(左减右)的场景;真要定位“哪边多、哪边少、差多少”,必须用 LEFT JOIN 或 FULL OUTER JOIN 配合 IS NULL 和条件判断。
EXCEPT 能不能直接比两个 GROUP BY 结果?
能,但有硬性前提:两边 SELECT 的列数、顺序、数据类型必须严格一致,且每列语义对等。比如都返回 city 和 COUNT(*),别一边是 city 一边是 UPPER(city)。
- 写错会直接报错或返回空结果,不是“不准”,而是“不执行”
-
EXCEPT比较的是整行,所以('Beijing', 100)和('Beijing', 101)算不同行,会被保留 - 自动去重:如果 2023 年某城市出现 3 次、2024 年出现 2 次,
EXCEPT只管“是否存在”,不管频次 - MySQL 不原生支持
EXCEPT,得用NOT EXISTS或LEFT JOIN ... IS NULL替代
LEFT JOIN 查差异时 ON 条件漏字段会怎样?
会错配——比如按 category 和 region 分组,但 ON 只写了 a.category = b.category,漏掉 region,结果就是所有 region 归到同一 category 下乱匹配,差异数值完全失真。
- 必须把所有分组键都写进
ON:如ON a.category = b.category AND a.region = b.region - 字段含
NULL时,NULL = NULL在标准 SQL 中不成立,会导致匹配失败;要用COALESCE(a.region, 'N/A') = COALESCE(b.region, 'N/A')归一化 - 别在子查询里加
HAVING过滤,否则“从有变无”的分组会被提前筛掉,再也查不到
想同时查“2023 有但 2024 无”和“2024 有但 2023 无”,怎么写?
用 FULL OUTER JOIN 最直白,但 MySQL 不支持;替代方案是 UNION ALL 拼两个 LEFT JOIN,或改用 UNION + NOT EXISTS。
- PostgreSQL / SQL Server 示例:
SELECT ..., 'only_2023' AS flag FROM a LEFT JOIN b ON ... WHERE b.cnt IS NULL UNION ALL SELECT ..., 'only_2024' AS flag FROM b LEFT JOIN a ON ... WHERE a.cnt IS NULL - 避免用
RIGHT JOIN——可读性差,容易写反方向 - 如果只关心“数量变化”,用
WHERE a.cnt != b.cnt OR a.cnt IS NULL OR b.cnt IS NULL一行覆盖全部情况
为什么用 INTERSECT/EXCEPT 比 JOIN 慢?
因为它们强制全程去重 + 排序,而 JOIN 可利用索引跳过扫描;尤其当某侧分组结果超十万行时,EXCEPT 往往触发大体积 Sort 操作,执行计划里一眼就能看到性能瓶颈。
- 先跑
EXPLAIN看执行计划:出现Hash Match (Aggregate)或Sort节点,说明开销已升高 - 大表对比优先建复合索引:如
(category, region),再走JOIN+CASE WHEN标记状态 -
INTERSECT无法利用单边索引加速,JOIN可以
真正麻烦的不是语法,而是 NULL 处理和分组键一致性——这两点出错,结果看着像对,实际全错。

















