MySQL 多表联查
多表联查核心就是 JOIN(连接),分为:INNER JOIN、LEFT JOIN、RIGHT JOIN、FULL JOIN(MySQL 不支持,用 union 模拟),还有隐式连接(逗号写法)。
准备两张示例表
-- 用户表 user
CREATE TABLE user(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20),
age INT
);
-- 订单表 order
CREATE TABLE `order`(
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT, -- 外键,关联user.id
order_name VARCHAR(50)
);
1、内连接 INNER JOIN(最常用)
只返回两张表匹配上的数据,两边都有才出结果
语法:
SELECT 字段
FROM 表A
INNER JOIN 表B
ON 表A.关联字段 = 表B.关联字段;
示例:查询用户以及对应的订单
SELECT u.name, o.order_name
FROM user u
INNER JOIN `order` o
ON u.id = o.user_id;
别名:
u代表 user,o代表 order
隐式内连接(逗号写法,等价 inner join)
SELECT u.name, o.order_name
FROM user u,`order` o
WHERE u.id = o.user_id;
⚠️不要忘记 where 条件,否则会产生笛卡尔积(数据爆炸)
2、左连接 LEFT JOIN(LEFT OUTER JOIN)
以左边表为主,左表全部数据都展示;右表匹配不到,字段为 NULL
SELECT u.name, o.order_name
FROM user u
LEFT JOIN `order` o
ON u.id = o.user_id;
场景:查询所有用户,包含没有下单的用户。
如果只想查左表有、右表没有的数据(没有订单的用户):
SELECT u.name
FROM user u
LEFT JOIN `order` o
ON u.id = o.user_id
WHERE o.id IS NULL;
3、右连接 RIGHT JOIN
以右边表为主,右表全部数据,左表匹配不到则 NULL
SELECT u.name, o.order_name
FROM user u
RIGHT JOIN `order` o
ON u.id = o.user_id;
4、全连接 FULL JOIN
MySQL 没有 FULL JOIN 关键字,想要左右全部数据,用
LEFT JOIN UNION RIGHT JOIN
SELECT u.name, o.order_name FROM user u LEFT JOIN `order` o ON u.id=o.user_id
UNION
SELECT u.name, o.order_name FROM user u RIGHT JOIN `order` o ON u.id=o.user_id;
5、三张及以上表联查
多张表就继续 JOIN ... ON 往后拼接
SELECT u.name,o.order_name,g.goods_name
FROM user u
LEFT JOIN `order` o ON u.id = o.user_id
LEFT JOIN goods g ON o.goods_id = g.id;
6、子查询实现多表(不是 JOIN,另一种方案)
-- where中子查询
SELECT * FROM user WHERE id IN (SELECT user_id FROM `order`);
-- from子查询(派生表)
SELECT * FROM (SELECT * FROM user WHERE age>18) t1
LEFT JOIN `order` o ON t1.id = o.user_id;
7、关键注意事项
- ON 和 WHERE 的区别
ON:join 连接时做匹配条件WHERE:连接完成之后,对结果集过滤
left join 中,条件写 on 和 where 结果完全不一样!
示例坑点:
-- ❌错误:left join后where过滤order表,会把null数据过滤掉,退化成内连接
SELECT u.name,o.order_name FROM user u
LEFT JOIN `order` o ON u.id=o.user_id
WHERE o.order_name='手机';
-- ✅正确,把条件放on
SELECT u.name,o.order_name FROM user u
LEFT JOIN `order` o ON u.id=o.user_id AND o.order_name='手机';
- 避免笛卡尔积:join 必须写 on 关联条件
- 字段重名,必须指定表别名:
u.id,不能只写id - 性能:关联字段建议建立索引(外键字段加索引,联查速度提升巨大)
快速选型记忆
表格
| 连接类型 | 作用 |
|---|---|
| INNER JOIN | 两边匹配的数据 |
| LEFT JOIN | 左边全部,右边匹配 |
| RIGHT JOIN | 右边全部,左边匹配 |
| UNION | 合并结果集 |