为什么要学关联查询
真实业务里数据几乎不会放在一张表里:用户信息存 users 表,订单存 orders 表,商品存 products 表。你想查每个用户的订单金额,就必须把两张表按用户ID关联起来。这就是 JOIN 的用武之地。
本教程用两张简化的表:users(id、姓名、城市)和 orders(id、user_id、金额、日期),全程围绕真实查询需求展开。
第一步:INNER JOIN 取交集
INNER JOIN 只返回两边都能匹配上的行。查询有订单的用户及其订单:SELECT users.姓名, orders.金额 FROM users INNER JOIN orders ON users.id = orders.user_id。结果里没有订单的用户不会出现,没有对应用户的孤儿订单也不会出现。
判断是否用 INNER JOIN 的标准:只要匹配不上的数据对我没用,就用它。比如统计有效订单、核对已付款用户,都是典型场景。
第二步:LEFT JOIN 保左表
LEFT JOIN 返回左表全部行,右表匹配不上的位置填 NULL。查询所有用户及其订单:SELECT users.姓名, orders.金额 FROM users LEFT JOIN orders ON users.id = orders.user_id。没下过单的用户也会出现,只是金额是 NULL。
它最经典的应用是找无订单用户:在 LEFT JOIN 基础上加 WHERE orders.id IS NULL,就能筛出所有注册但从未下单的用户,运营做激活活动时天天用这条。
第三步:RIGHT JOIN 与 FULL JOIN
RIGHT JOIN 与 LEFT JOIN 对称,保右表全部行,实际开发中用得少,因为把表换个位置用 LEFT JOIN 就能达到同样效果。FULL JOIN 保两边全部行,MySQL 不直接支持,一般用 LEFT JOIN 加 UNION 模拟。
实战建议:90% 的场景只记 INNER 和 LEFT 两种就够了,遇到 RIGHT 需求就调换表的位置改写。
第四步:三张表及以上的关联
需求升级:查每个用户的订单里商品名称。需要 users 关联 orders,再关联 order_items 或 products。写法是连续 JOIN:SELECT 用户, 商品名 FROM users JOIN orders ON users.id=orders.user_id JOIN order_items ON orders.id=order_items.order_id JOIN products ON order_items.product_id=products.id。
多表关联时先理清表之间的连接键,把关联关系画出来再写 SQL,别凭感觉堆 JOIN,很容易查出笛卡尔积(行数爆炸)。
第五步:NULL陷阱与性能优化
NULL 陷阱:LEFT JOIN 后金额为 NULL 不是0,做 SUM 时 NULL 会被忽略,做 WHERE 金额>0 过滤时 NULL 行也会被滤掉。需要时用 COALESCE(金额,0) 把 NULL 转成 0。
性能优化三条:第一,JOIN 的关联字段必须建索引,orders.user_id 建索引后查询速度能提升几个数量级;第二,只 SELECT 需要的字段,别用 SELECT *;第三,大数据量时先用 WHERE 缩小范围再 JOIN,减少中间结果集。记住这三条,多表查询基本不会卡。