前言
到本篇为止,我们已经完整学完了企业 SQL 80% 核心重难点:INNER/LEFT/RIGHT/FULL JOIN 多表联查、标量 / 列 / 行子查询、EXISTS/IN/ANY/ALL、UNION/UNION ALL 联合查询。这些内容是面试必考、工作高频、拉开差距的关键。
这一篇不讲新知识点,专门做高强度复盘 + 真题集训,把前面所有重难点串成体系、用企业真实面试题带你彻底吃透,做到学完就会、会了能用、用了不踩坑。
一、本章知识点汇总
二、重难点速记复盘(背会直接面试)
1. 四大连接速记
- INNER JOIN:取交集,只保留两边匹配数据
- LEFT JOIN:左表全保留,右表不匹配补 NULL(工作最常用)
- RIGHT JOIN:右表全保留,可转为 LEFT JOIN 写
- FULL JOIN:两边全保留,MySQL 用 UNION 实现
黄金原则:90% 场景用 LEFT JOIN,主表永远放左边。
2. 子查询速记
- 标量子查询:返回 1 个值,用 = > <
- 列子查询:返回一列,用 IN/ANY/ALL
- 行子查询:返回一行多列,(a,b)=(子查询)
- EXISTS:只判断存在,大表性能最强
- IN:小表好用,大表慎用
- NOT IN:有 NULL 陷阱,生产禁用
- NOT EXISTS:查询不存在数据的唯一安全写法
黄金原则:大表关联用 EXISTS,非存在用 NOT EXISTS。
3. 联合查询速记
- UNION:合并 + 去重 + 排序,慢
- UNION ALL:直接合并,极快
- 语法铁律:列数相同、类型兼容、顺序一致
- 排序:只在最后写一次 ORDER BY
黄金原则:生产默认 UNION ALL。
4. 三大致命坑复盘
三、企业高频面试真题(10 道)
真题 1:LEFT JOIN 与 INNER JOIN 区别?
答案: INNER JOIN 只返回两张表交集; LEFT JOIN 保留左表全部数据,右表不匹配补 NULL,是企业最常用连接。
真题 2:为什么不推荐使用 RIGHT JOIN?
答案: RIGHT JOIN 逻辑可读性差,所有 RIGHT JOIN 都可以换成 LEFT JOIN,企业统一规范只用 LEFT JOIN,便于维护。
真题 3:UNION 与 UNION ALL 区别?哪个快?
答案: UNION 会去重并排序,速度慢; UNION ALL 直接拼接,速度远快于 UNION,生产优先使用。
真题 4:EXISTS 与 IN 怎么选?
答案: 小表用 IN,大表关联必用 EXISTS; EXISTS 只判断存在,匹配到即停止,性能更高。
真题 5:NOT IN 有什么坑?怎么解决?
答案: 子查询返回 NULL 时,NOT IN 结果永远为空。 必须用 NOT EXISTS 替代。
真题 6:什么是笛卡尔积?怎么避免?
答案: 多表连接无关联条件导致全表匹配,数据量爆炸。 避免:每层 JOIN 必须写 ON,用主键 = 外键关联,先过滤再连接。
真题 7:左连接中,右表条件放 ON 还是 WHERE?
答案: 右表条件放 ON,不影响左表保留; 放 WHERE 会过滤左表,等价于内连接。
真题 8:子查询有哪几种类型?
答案: 按结果分:标量、列、行子查询。 按关键字分:IN/ANY/ALL/EXISTS。
真题 9:如何查询 “没有下单的用户”?
答案:
sql
SELECT * FROM users u
WHERE NOT EXISTS (
SELECT 1 FROM orders o
WHERE o.user_id=u.user_id
);
真题 10:多表连接统计时,为什么要用 COUNT (DISTINCT)?
答案: 一对多连接会导致行数膨胀,直接 COUNT 会重复计算,必须用 DISTINCT 去重。
四、综合实战环境(直接复制运行)
sql
— 用户表
CREATE TABLE users (
user_id INT PRIMARY KEY,
user_name VARCHAR(20) NOT NULL
);
— 订单表
CREATE TABLE orders (
order_id INT PRIMARY KEY,
user_id INT,
amount DECIMAL(10,2),
order_time DATE
);
— 商品表
CREATE TABLE goods (
goods_id INT PRIMARY KEY,
goods_name VARCHAR(30),
price DECIMAL(10,2)
);
— 订单明细表
CREATE TABLE order_item (
id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT,
goods_id INT,
num INT
);
INSERT INTO users VALUES (1,'张三'),(2,'李四'),(3,'王五'),(4,'赵六');
INSERT INTO orders VALUES
(1001,1,299,'2024-06-01'),
(1002,2,420,'2024-06-02'),
(1003,3,88,'2024-06-03');
INSERT INTO goods VALUES (1,'笔记本',299),(2,'键盘',159),(3,'T恤',99);
INSERT INTO order_item VALUES (1,1001,1,1),(2,1002,3,1),(3,1003,2,1);
五、综合实战大题(企业标准难度)
综合题 1:四表联查 + 统计
查询所有用户的: 用户名、订单数、商品总数、总消费金额,无消费显示 0。
sql
SELECT
u.user_id,
u.user_name,
COUNT(DISTINCT o.order_id) AS order_cnt,
COALESCE(SUM(oi.num),0) AS total_goods,
COALESCE(SUM(oi.num * g.price),0) AS total_amount
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
LEFT JOIN order_item oi ON o.order_id = oi.order_id
LEFT JOIN goods g ON oi.goods_id = g.goods_id
GROUP BY u.user_id, u.user_name
ORDER BY total_amount DESC;
综合题 2:子查询 + EXISTS 优化
查询买过 “笔记本” 的用户(用 EXISTS,性能最优)。
sql
SELECT * FROM users u
WHERE EXISTS (
SELECT 1 FROM orders o
JOIN order_item oi ON o.order_id=oi.order_id
JOIN goods g ON oi.goods_id=g.goods_id
WHERE o.user_id=u.user_id
AND g.goods_name='笔记本'
);
综合题 3:联合查询 + 报表汇总
合并订单表,统计: 线上总金额、线下总金额、总金额(模拟两表合并)。
sql
SELECT '订单总金额' AS type, SUM(amount) FROM orders
UNION ALL
SELECT '商品总销售额' AS type, SUM(num*price)
FROM order_item oi
JOIN goods g ON oi.goods_id=g.goods_id;
六、注意事项(职场终极规范)
七、核心总结(全文最精华)
一句话通关口诀: 左连接为主表全留,子查询 EXISTS 最优;联合用 ALL 速度够,NULL 与笛卡尔积要躲;多表逐级不跳走,职场 SQL 不用愁
八、下一步学习预告
从下一篇开始,我们进入企业进阶刚需模块:
- 事务 ACID
- 事务隔离级别
- 窗口函数(面试必考)
- CTE 公用表表达式
- 存储过程、触发器
- 索引优化、EXPLAIN





