SELECT goods_id,goods_name,brand.name brand,goods_type.name type FROM (goods LEFT JOIN brand ON goods.brand_id=brand.id) LEFT JOIN goods_type ON goods.goods_type=goods_type.id;
非常好的问题!这是一个两次左外连接的典型写法,在实际开发中很常见。我们一步步拆解。
一、涉及的三张表结构
假设有以下三张表:
goods(商品表)
goods_id | goods_name | brand_id | goods_type |
101 | 华为Mate60 | 1 | 1 |
102 | 小米14 | 2 | 1 |
103 | 联想小新 | 3 | 2 |
104 | 杂牌耳机 | NULL | 99 |
brand(品牌表)
| id | name |
|---|---|
| 1 | 华为 |
| 2 | 小米 |
| 3 | 联想 |
goods_type(商品类型表)
| id | name |
|---|---|
| 1 | 手机 |
| 2 | 电脑 |
二、代码执行顺序
你的 SQL:
sql
SELECT goods_id, goods_name, brand.name brand, -- 给 brand.name 起了别名 brand goods_type.name type -- 给 goods_type.name 起了别名 typeFROM (goods LEFT JOIN brand ON goods.brand_id = brand.id)LEFT JOIN goods_type ON goods.goods_type = goods_type.id;
执行步骤:
第1步:先执行括号里的左连接
sql
goods LEFT JOIN brand ON goods.brand_id = brand.id
结果(临时表A):
goods_id | goods_name | brand_id | goods_type | brand.id | |
101 | 华为Mate60 | 1 | 1 | 1 | 华为 |
102 | 小米14 | 2 | 1 | 2 | 小米 |
103 | 联想小新 | 3 | 2 | 3 | 联想 |
104 | 杂牌耳机 | NULL | 99 | NULL | NULL |
第2步:再跟 goods_type 表左连接
sql
临时表A LEFT JOIN goods_type ON goods.goods_type = goods_type.id
注意:ON 条件里用的是 goods.goods_type(原始goods表),不是临时表里的字段。
最终结果:
goods_id | goods_name | brand | type |
101 | 华为Mate60 | 华为 | 手机 |
102 | 小米14 | 小米 | 手机 |
103 | 联想小新 | 联想 | 电脑 |
104 | 杂牌耳机 | NULL | NULL |
三、为什么两次都要用 LEFT JOIN?
因为要保留主表(goods)的所有商品,两次连接都是"可选的补充信息":
| 连接对象 | 目的 | 如果匹配不上 |
|---|---|---|
| 第一次 LEFT JOIN brand | 补充品牌名称 | 品牌显示为 NULL(商品没有品牌或品牌ID无效) |
| 第二次 LEFT JOIN goods_type | 补充类型名称 | 类型显示为 NULL(商品类型ID无效) |
四、如果用 INNER JOIN 会怎样?
sql
-- 假设改成 INNER JOINFROM goods INNER JOIN brand ON goods.brand_id = brand.idINNER JOIN goods_type ON goods.goods_type = goods_type.id
结果:只显示 101、102、103
104(杂牌耳机)因为 brand_id 为 NULL,第一次连接就被过滤掉了
五、常见应用场景
这种两次左外连接常用于主表需要关联多个字典表:
订单表 → 用户表 → 用户等级表
文章表 → 作者表 → 作者部门表
商品表 → 品牌表 → 分类表
核心原则:主表的每一条记录都要保留,关联的信息有则显示,没有则为 NULL。
六、写法说明
你的代码中括号可以省略(LEFT JOIN 从左到右执行),但加括号更清晰:
sql
-- 这两种写法等价FROM goods LEFT JOIN brand ON ... LEFT JOIN goods_type ON ...FROM (goods LEFT JOIN brand ON ...) LEFT JOIN goods_type ON ...
七、记忆口诀
多层左连接,主表永保留,
右表能配就配,配不到就 NULL