404 Not Found

404 Not Found


nginx

集合运算

集合运算

🌍 生活类比

想象你有两堆名片:

集合运算就是对两个查询结果集进行"合并、取交、取差"的操作。


🎯 核心概念

UNION — 去重合并

将两个结果集合并,自动去除重复行。

SQL
SELECT city FROM employees
UNION
SELECT city FROM departments;

UNION ALL — 不去重合并

将两个结果集合并,保留所有重复行。性能更好,因为不需要去重。

SQL
SELECT city FROM employees
UNION ALL
SELECT city FROM departments;

INTERSECT — 交集

返回两个结果集中都存在的行。

SQL
SELECT city FROM employees
INTERSECT
SELECT city FROM departments;

EXCEPT / MINUS — 差集

返回在第一个结果集中存在、但第二个结果集中不存在的行。

SQL
-- EXCEPT(SQL Server、PostgreSQL)
SELECT city FROM employees
EXCEPT
SELECT city FROM departments;

-- MINUS(Oracle)
SELECT city FROM employees
MINUS
SELECT city FROM departments;

列匹配规则

使用集合运算时,两个 SELECT 必须满足:

规则 说明
列数相同 两个 SELECT 的列数必须一致
类型兼容 对应列的数据类型必须兼容
ORDER BY 放最后 只能在整个语句末尾使用一次
SQL
-- 正确:两列,类型匹配
SELECT first_name, salary FROM employees
UNION
SELECT department_name, budget FROM departments;

-- 错误:列数不同
SELECT first_name, salary FROM employees
UNION
SELECT department_name;  -- ❌ 列数不匹配

💡 何时使用哪种运算

运算 场景 是否去重 性能
UNION 需要合并且去重 ✅ 是 较慢
UNION ALL 合并不需要去重 ❌ 否 较快
INTERSECT 找共同部分 ✅ 是 中等
EXCEPT 找差异部分 ✅ 是 中等
💡 经验法则:如果确定没有重复数据,优先用 UNION ALL,性能更好。


📝 基本语法

SQL
-- UNION 语法
SELECT column1, column2 FROM table1
UNION
SELECT column1, column2 FROM table2
[ORDER BY column1];

-- UNION ALL 语法
SELECT column1, column2 FROM table1
UNION ALL
SELECT column1, column2 FROM table2;

-- INTERSECT 语法
SELECT column1, column2 FROM table1
INTERSECT
SELECT column1, column2 FROM table2;

-- EXCEPT 语法
SELECT column1, column2 FROM table1
EXCEPT
SELECT column1, column2 FROM table2;
💡 提示

  • 集合运算中,列名以第一个 SELECT 的列名为准
  • ORDER BY 只能出现在最后,且通常按列序号排序
  • 每个 SELECT 内可以有自己的 WHERE、GROUP BY

📌 示例

示例:查询所有人员的姓名来源

合并员工姓名和部门名称到一个结果集中。

SQL
-- 查看所有"人名"来源:员工 + 部门经理
SELECT first_name AS name, '员工' AS 来源
FROM employees
UNION ALL
SELECT department_name, '部门'
FROM departments
ORDER BY 来源;
▶ 试一试

说明:添加一个常量列标记数据来源,便于区分。

示例:找出有员工但没有部门的城市

SQL
-- 有员工的城市 减去 有部门的城市
SELECT city FROM employees
EXCEPT
SELECT city FROM departments;
▶ 试一试

思路:用 EXCEPT 做差集,快速找出"只在 employees 中出现的城市"。


🎬 场景演练

场景一:合并多渠道客户名单

公司有线上和线下两个客户表,需要合并去重后生成完整客户名录。

SQL
-- 线上客户
SELECT customer_name, email, '线上' AS channel
FROM online_customers
UNION
-- 线下客户
SELECT customer_name, email, '线下'
FROM offline_customers
ORDER BY customer_name;

要点:用 UNION 而非 UNION ALL,自动去除重复客户。

场景二:对比两个月的销售差异

找出本月有销售但上月没有销售的产品。

SQL
-- 本月销售的产品
SELECT product_id FROM orders
WHERE order_date >= '2026-06-01'
EXCEPT
-- 上月销售的产品
SELECT product_id FROM orders
WHERE order_date >= '2026-05-01'
  AND order_date < '2026-06-01';

要点EXCEPT 天然适合"找差异"的场景。


❓ 常见问题

Q:UNION 和 UNION ALL 什么时候该用哪个? A: 如果不需要去重,优先用 UNION ALL,因为它不需要额外的去重步骤,性能更好。只有确定需要去重时才用 UNION

Q:集合运算中列名不一致会报错吗? A: 不会,结果集的列名以第一个 SELECT 的列名为准。但列数和对应列的数据类型必须一致。

Q:INTERSECT 和 JOIN 有什么区别? A: INTERSECT 是按整行去匹配交集,而 JOIN 是按指定条件关联。如果需要"找完全相同的行"用 INTERSECT,需要"按某个字段关联不同表的列"用 JOIN

Q:MySQL 支持 INTERSECT 和 EXCEPT 吗? A: MySQL 8.0 起支持 INTERSECTEXCEPT。如果使用更早版本,需要用 INNER JOINNOT EXISTS / LEFT JOIN ... IS NULL 来模拟。


📖 小节

运算 作用 是否去重
UNION 合并两个结果集
UNION ALL 合并两个结果集(保留重复)
INTERSECT 取两个结果集的交集
EXCEPT 取两个结果集的差集

📝 作业

  1. 使用 UNION 合并 employees 表中工资高于 8000 的员工和 departments 表中预算高于 100000 的部门名称。
  2. 使用 INTERSECT 找出 employeesdepartments 表中都存在的城市。
  3. 使用 EXCEPT 找出有部门但没有员工被分配的城市。
  4. 思考:如果两个查询结果的列类型不完全一致(如 INT 和 VARCHAR),集合运算会发生什么?

下一课

下一节我们将学习 约束与键 — 了解如何用 PRIMARY KEY、FOREIGN KEY 等约束保证数据完整性。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏