集合操作(UNION / INTERSECT / EXCEPT)
约 664 字大约 2 分钟
布欧-Lewyon
2026-05-15
首页 › MySQL › 高级查询(在新窗口打开) › 集合操作(UNION / INTERSECT / EXCEPT)
集合操作将多个 SELECT 的结果集按行合并或比较。MySQL 很早就支持 UNION,从 8.0.31 起增加了 INTERSECT 和 EXCEPT。
CREATE TABLE employee_2025 (
id INT PRIMARY KEY,
name VARCHAR(50),
dept VARCHAR(20)
);
CREATE TABLE employee_2026 (
id INT PRIMARY KEY,
name VARCHAR(50),
dept VARCHAR(20)
);
INSERT INTO employee_2025 VALUES
(1, '张三', '技术部'), (2, '李四', '市场部'), (3, '王五', '技术部');
INSERT INTO employee_2026 VALUES
(2, '李四', '市场部'), (3, '王五', '技术部'), (4, '赵六', '人事部');UNION 与 UNION ALL
将两个或多个查询的结果上下拼接:
-- UNION:去重合并(开销更大)
SELECT name FROM employee_2025
UNION
SELECT name FROM employee_2026;
-- 李四、王五、张三、赵六(4 行,去重)
-- UNION ALL:直接合并(更快,保留重复)
SELECT name FROM employee_2025
UNION ALL
SELECT name FROM employee_2026;
-- 张三、李四、王五、李四、王五、赵六(6 行)规则:
- 各
SELECT的列数必须相同,对应列的类型需兼容。 - 最终结果集的列名取自第一个
SELECT。 - 默认
UNION结果按第一列升序排序(需注意性能)。
-- 排序放在最后一个 SELECT 之后
SELECT id, name FROM employee_2025
UNION
SELECT id, name FROM employee_2026
ORDER BY name DESC;INTERSECT(交集,8.0.31+)
返回两个查询中都存在的行:
SELECT name FROM employee_2025
INTERSECT
SELECT name FROM employee_2026;
-- 李四、王五等效于用 INNER JOIN 做同样的事:
SELECT DISTINCT a.name
FROM employee_2025 a
INNER JOIN employee_2026 b ON a.name = b.name;EXCEPT(差集,8.0.31+)
返回第一个查询中有但第二个查询中没有的行:
SELECT name FROM employee_2025
EXCEPT
SELECT name FROM employee_2026;
-- 张三等效于用 LEFT JOIN / NOT EXISTS:
SELECT a.name
FROM employee_2025 a
LEFT JOIN employee_2026 b ON a.name = b.name
WHERE b.name IS NULL;MySQL 中
EXCEPT与MINUS是同义词(Oracle 习惯用MINUS)。
集合操作与 NULL
集合操作使用行比较语义,NULL 被视为彼此相等:
-- 场景:两表中都有 name 为 NULL 的行
SELECT name FROM t1 WHERE name IS NULL -- 返回一行 NULL
UNION
SELECT name FROM t2 WHERE name IS NULL; -- 返回一行 NULL
-- UNION 结果中 NULL 只出现一次(去重时视 NULL == NULL)执行顺序与括号
多个集合操作可以用括号控制优先级,MySQL 8.0.31+ 默认从左到右执行:
-- 先 INTERSECT 再 UNION
(SELECT name FROM employee_2025
INTERSECT
SELECT name FROM employee_2026)
UNION
SELECT name FROM employee_2025;小结
UNION ALL直接拼接行(无去重开销),UNION去重合并。INTERSECT取交集,EXCEPT取差集(MySQL 8.0.31+)。- 集合操作要求各 SELECT 列数一致、类型兼容;排序写在末尾的
ORDER BY中。 - 低版本 MySQL 可通过
JOIN或NOT EXISTS模拟INTERSECT/EXCEPT。
