零基础学SQL 11:_SQL 多表关联查询入门:INNER JOIN、LEFT JOIN、RIGHT JOIN 用法详解(附实战示例)

📅 2026/8/25 16:37:49
零基础学SQL 11:_SQL 多表关联查询入门:INNER JOIN、LEFT JOIN、RIGHT JOIN 用法详解(附实战示例)
一、为什么必须学会多表关联查询实际工作中数据很少全部放在一张表里。以一个公司的订单系统为例员工表存员工姓名、部门、工资订单表存哪个员工接了哪笔订单、金额多少、状态如果你想查询张三名下的各笔订单金额就必须把两张表关联起来。这就是多表查询的价值。本系列所有文章都用下面这 4 张统一的练习表建一次就能跟着全系列练。-- SQL 系列统一练习表复制即可运行可重复执行不会报表已存在 -- 说明每张表先 DROP 再 CREATE所以每读一篇文重新跑一次这个块都安全 DROP TABLE IF EXISTS 员工表; CREATE TABLE 员工表 ( 员工id INT PRIMARY KEY, 姓名 VARCHAR(20), 部门 VARCHAR(20), 工资 DECIMAL(10,2), 邮箱 VARCHAR(50), 手机 VARCHAR(20), 入职日期 DATE ); INSERT INTO 员工表 (员工id, 姓名, 部门, 工资, 邮箱, 手机, 入职日期) VALUES (1, 张三, 技术部, 9000.00, zhangsandemo.com, 13800000001, 2019-03-01), (2, 李四, 技术部, 9000.00, lisidemo.com, 13800000002, 2020-07-15), (3, 王五, 销售部, 9200.00, wangwudemo.com, 13800000003, 2018-01-10), (4, 赵六, 销售部, 9200.00, zhaoliudemo.com, 13800000004, 2021-05-20); DROP TABLE IF EXISTS 订单表; CREATE TABLE 订单表 ( 订单id INT PRIMARY KEY, 员工id INT, 订单金额 DECIMAL(10,2), 下单时间 DATETIME, 付款时间 DATETIME, 状态 VARCHAR(20) ); INSERT INTO 订单表 (订单id, 员工id, 订单金额, 下单时间, 付款时间, 状态) VALUES (101, 1, 3000.00, 2026-01-10 10:00:00, 2026-01-10 10:05:00, 已付款), (102, 1, 2500.00, 2026-02-15 14:00:00, 2026-02-15 14:10:00, 已付款), (103, 3, 4000.00, 2026-03-20 09:30:00, 2026-03-20 09:40:00, 已付款), (104, 2, 1500.00, 2026-04-05 16:00:00, NULL, 待付款); DROP TABLE IF EXISTS 用户表; CREATE TABLE 用户表 ( 用户id INT PRIMARY KEY, 姓名 VARCHAR(20), 手机 VARCHAR(20), 邮箱 VARCHAR(50), 地址 VARCHAR(100) ); INSERT INTO 用户表 (用户id, 姓名, 手机, 邮箱, 地址) VALUES (1, 张三, 13900000001, zhangsandemo.com, 北京市朝阳区), (2, 李四, 13900000002, lisidemo.com, 上海市浦东新区), (3, 王五, 13900000003, wangwudemo.com, 广州市天河区); DROP TABLE IF EXISTS 任务表; CREATE TABLE 任务表 ( 任务id INT PRIMARY KEY, 员工id INT, 备注 VARCHAR(100), 状态 VARCHAR(20) ); INSERT INTO 任务表 (任务id, 员工id, 备注, 状态) VALUES (1, 1, 完成需求评审, 已完成), (2, 2, NULL, 进行中), (3, 3, 修复线上bug, 已完成), (4, 4, NULL, 待分配);注意赵六没有订单记录。后面我们会用这个例子说明 LEFT JOIN 和 INNER JOIN 的区别。二、INNER JOIN只返回两表都匹配的数据语法SELECT 列名 FROM 表A INNER JOIN 表B ON 表A.关联列 表B.关联列;实战查询所有有订单的员工姓名和订单金额SELECT e.姓名, o.订单金额, o.状态 FROM 员工表 e INNER JOIN 订单表 o ON e.员工id o.员工id;结果姓名订单金额状态张三5000已完成张三3000已付款李四2000已付款王五8000已完成关键点INNER JOIN 只返回能匹配上的数据。赵六在订单表里没有记录所以不会出现在结果里。工作中统计已完成的订单已接单的员工有关联的数据时优先用 INNER JOIN。三、LEFT JOIN以左表为主右表没有匹配也显示语法SELECT 列名 FROM 表A LEFT JOIN 表B ON 表A.关联列 表B.关联列;实战查询所有员工以及他们的订单没订单也显示SELECT e.姓名, o.订单金额, o.状态 FROM 员工表 e LEFT JOIN 订单表 o ON e.员工id o.员工id;结果姓名订单金额状态张三5000已完成张三3000已付款李四2000已付款王五8000已完成赵六NULLNULL关键点LEFT JOIN 以左表员工表为准左表里的数据全部显示。右表订单表没有匹配上的地方用 NULL 填充。赵六没有订单所以订单金额和状态都是 NULL。工作中查询全部员工及其业绩全部商品及其销量时常用 LEFT JOIN。小技巧如何筛选出没有订单的员工SELECT e.姓名 FROM 员工表 e LEFT JOIN 订单表 o ON e.员工id o.员工id WHERE o.订单id IS NULL;结果赵六。四、RIGHT JOIN以右表为主左表没有匹配也显示语法SELECT 列名 FROM 表A RIGHT JOIN 表B ON 表A.关联列 表B.关联列;实战查询所有订单以及接单员工姓名没员工的订单也显示SELECT o.订单id, e.姓名, o.订单金额 FROM 员工表 e RIGHT JOIN 订单表 o ON e.员工id o.员工id;结果订单id姓名订单金额101张三5000102张三3000103李四2000104王五8000关键点RIGHT JOIN 以右表为准。实际工作中RIGHT JOIN 用得比 LEFT JOIN 少。因为大多数需求可以用 LEFT JOIN 改写把右表换到左边即可。比如上面的查询等价于SELECT o.订单id, e.姓名, o.订单金额 FROM 订单表 o LEFT JOIN 员工表 e ON o.员工id e.员工id;这样写更容易理解建议新手优先掌握 LEFT JOIN。五、一张图记住三种 JOIN 的区别假设表 A 有 1、2、3表 B 有 2、3、4INNER JOIN只返回 2、3两边都有LEFT JOIN返回 1、2、3以 A 为准B 没有匹配的地方补 NULLRIGHT JOIN返回 2、3、4以 B 为准A 没有匹配的地方补 NULL六、多表 JOIN 实战查询每个部门的订单总额SELECT e.部门, SUM(o.订单金额) AS 部门订单总额 FROM 员工表 e INNER JOIN 订单表 o ON e.员工id o.员工id GROUP BY e.部门;这个查询把两张表串起来然后按部门分组求和。多表 JOIN 的核心就是先确定你要的数据在哪几张表里然后顺着关联字段一步步串起来。七、新手最容易犯的 3 个错误1. 忘记写 ON 条件变成笛卡尔积-- 错误写法 SELECT * FROM 员工表, 订单表;结果会把员工表的 4 条 × 订单表的 4 条 16 条全部组合出来数据爆炸。正确写法SELECT * FROM 员工表 e INNER JOIN 订单表 o ON e.员工id o.员工id;2. 关联字段类型不一致比如员工表.员工id是 INT但订单表.员工id存成了 VARCHAR。JOIN 时可能走不了索引结果也会慢很多。建表时尽量保证关联字段类型一致。3. 分不清 LEFT JOIN 和 INNER JOIN 的场景要全部数据用 LEFT JOIN要只查有匹配的数据用 INNER JOIN用错的话结果会漏数据或多出 NULL后面统计就会出错八、总结速查表JOIN 类型返回哪些数据典型场景INNER JOIN两表匹配上的数据查有效订单、已接单员工、有关联记录LEFT JOIN左表全部 右表匹配部分查全部员工及业绩、全部商品及销量RIGHT JOIN右表全部 左表匹配部分用得少多数可改写为 LEFT JOIN九、课后练习查询每个员工的订单总笔数需要用到 GROUP BY 和 COUNT。查询没有接单的员工名单需要用到 LEFT JOIN IS NULL。查询每个部门的订单平均金额没人接单的部门也要显示需要用到 LEFT JOIN 聚合函数。如果你也在学 SQL欢迎在评论区交流。我会持续更新 SQL 实战系列下一篇计划写《SQL 子查询与 JOIN 到底用哪个更好》。版权声明本文为博主原创文章遵循 CC 4.0 BY-SA 版权协议转载请附上原文出处链接和本声明。