第三章|连接、子查询与集合
本章目标
学习如何组合多个表的数据,掌握 JOIN、子查询、EXISTS、UNION 等操作,理解关系数据库的核心能力。
从 INNER JOIN 开始,理解笛卡尔积和连接条件,学会用 LEFT JOIN 处理可选关系,用子查询嵌套查询逻辑,用 EXISTS 检查存在性,用 UNION 合并结果集。
学习路径
按顺序阅读以下文章,每篇包含讲解、示例和练习:
INNER JOIN:内连接与笛卡尔积
理解表连接的基础,掌握 INNER JOIN 和 ON 条件。LEFT JOIN 与 RIGHT JOIN:外连接
处理可选关系,理解 NULL 在外连接中的作用。子查询:WHERE、FROM 与 SELECT 中的子查询
在查询中嵌套查询,理解标量、行、表子查询。EXISTS 与 IN:存在性检查
高效检查关联数据是否存在,理解 EXISTS 与 IN 的差异。UNION 与集合操作:合并结果
合并多个查询结果,理解 UNION、INTERSECT、EXCEPT。
关键概念
表连接组合多表数据
关系数据库将数据分散在多个表中(范式化),通过 JOIN 重新组合:
-- 用户表
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50)
);
-- 订单表
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
amount DECIMAL(10, 2)
);
-- 连接两表
SELECT users.name, orders.amount
FROM users
JOIN orders ON users.id = orders.user_id;INNER JOIN vs LEFT JOIN
- INNER JOIN:只返回两表都匹配的行
- LEFT JOIN:返回左表所有行,右表不匹配时为 NULL
-- INNER:只返回有订单的用户
SELECT users.name, COUNT(orders.id) AS order_count
FROM users
INNER JOIN orders ON users.id = orders.user_id
GROUP BY users.name;
-- LEFT:返回所有用户,没有订单的显示 0
SELECT users.name, COUNT(orders.id) AS order_count
FROM users
LEFT JOIN orders ON users.id = orders.user_id
GROUP BY users.name;子查询提供动态条件
子查询是嵌套在主查询中的查询:
-- 查询高于平均金额的订单
SELECT * FROM orders
WHERE amount > (SELECT AVG(amount) FROM orders);EXISTS 检查存在性
EXISTS 比 IN 更高效(短路求值):
-- 查询有订单的用户
SELECT * FROM users
WHERE EXISTS (SELECT 1 FROM orders WHERE orders.user_id = users.id);UNION 合并结果集
UNION 垂直合并多个查询结果:
SELECT name FROM customers
UNION
SELECT name FROM suppliers;前置知识
- 掌握 SELECT、WHERE、GROUP BY(第一、二章)
- 理解主键和外键的概念
- 能够创建关联表
后续章节
完成本章后,继续学习:
第四章:窗口函数与高级查询
学习窗口函数、CTE、递归查询。第五章:事务与隔离
理解事务、ACID、隔离级别。
练习答案
本章所有练习的答案和详细解释:第三章练习答案
深入阅读
为什么需要表连接?
关系数据库遵循范式化原则,避免数据冗余。用户信息存在 users 表,订单信息存在 orders 表,通过外键关联。JOIN 在查询时重新组合数据,兼顾存储效率和查询灵活性。
笛卡尔积是什么?
没有连接条件的 JOIN 会产生笛卡尔积:每个左表行与每个右表行组合。如果 users 有 100 行,orders 有 1000 行,笛卡尔积会产生 100,000 行!ON 条件限制了组合规则。