尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

mysql join on where

mysql join on where
📅 发布时间:2026/6/22 13:01:24
left outer join 的含义
LEFT OUTER JOIN(通常简写为 LEFT JOIN)是 SQL/JPQL 中外连接的核心类型,也是关联多表查询时最常用的连接方式之一。其核心含义是:以左表为基准,返回左表的所有记录,同时匹配右表中满足连接条件的记录;若右表无匹配记录,则右表字段返回 NULL。

一、核心概念拆解

1. 关键术语

  • 左表:LEFT JOIN 左侧的表(驱动表),查询结果会包含左表的全部行;
  • 右表:LEFT JOIN 右侧的表(被驱动表),仅返回与左表匹配的行,无匹配则补 NULL;
  • 连接条件:通过 ON 子句指定的匹配规则(如 a.id = b.a_id),决定右表哪些行能与左表匹配。

2. 与其他连接的对比(快速区分)

连接类型核心行为结果集特点
LEFT JOIN 左表全量,右表匹配补 NULL 行数 = 左表总行数
INNER JOIN 仅返回左右表都匹配的行 行数 ≤ 左表 / 右表总行数
RIGHT JOIN 右表全量,左表匹配补 NULL(与 LEFT 相反) 行数 = 右表总行数
FULL JOIN 左右表全量,彼此无匹配则补 NULL 行数 = 左表 + 右表 - 交集行数

二、直观示例(SQL 层面)

假设存在两张表:
  • t_user(用户表,左表):存储所有用户,即使该用户无订单;
  • t_order(订单表,右表):存储用户的订单记录。

表数据示例

t_user (左表) t_order (右表)  
id name id order_no user_id
1 张三 101 O1001 1
2 李四 102 O1002 1
3 王五 103 O1003 2

执行 LEFT JOIN 查询

sql
 
 
SELECT u.id AS user_id, u.name, o.id AS order_id, o.order_no
FROM t_user u
LEFT OUTER JOIN t_order o ON u.id = o.user_id; -- 连接条件:用户ID匹配
 

查询结果

user_idnameorder_idorder_no
1 张三 101 O1001
1 张三 102 O1002
2 李四 103 O1003
3 王五 NULL NULL
核心特征:
  • 左表(t_user)的「王五」无订单(右表无匹配),但仍出现在结果中,右表字段补 NULL;
  • 左表有匹配的行(张三、李四),会返回所有匹配的右表记录(张三对应 2 条订单)。

三、JPQL/QueryDSL 中的 LEFT JOIN 用法

结合你之前关注的 JPQLQueryFactory,以下是 LEFT JOIN 的典型场景示例:

1. 基础 LEFT JOIN(QueryDSL 写法)

需求:查询所有用户,以及其关联的订单(无订单则显示 NULL)。
java
 
运行
 
 
 
 
@Service
public class UserOrderService {@Resourceprivate JPAQueryFactory queryFactory;private final QUser qUser = QUser.user;private final QOrder qOrder = QOrder.order;// LEFT JOIN 查询所有用户+订单(无订单补NULL)public List<Tuple> listUserWithOrders() {return queryFactory.select(qUser.id, qUser.name, qOrder.id, qOrder.orderNo).from(qUser)// LEFT JOIN:左表=qUser,右表=qOrder,连接条件=用户ID匹配.leftJoin(qUser.orders, qOrder) .fetch();}
}
 

2. LEFT JOIN + 过滤(仅过滤右表,不影响左表)

需求:查询所有用户,以及其「金额 > 100」的订单(无符合条件订单则补 NULL)。
注意:过滤右表条件需写在 ON 子句(而非 WHERE),否则会退化为 INNER JOIN!
java
 
运行
 
 
 
 
// 正确写法:过滤条件写在 ON 子句
public List<Tuple> listUserWithHighAmountOrders() {return queryFactory.select(qUser.id, qUser.name, qOrder.id, qOrder.amount).from(qUser)// ON 子句添加右表过滤条件.leftJoin(qUser.orders, qOrder).on(qOrder.amount.gt(new BigDecimal("100"))) .fetch();
}
 

3. LEFT JOIN + DISTINCT(去重)

需求:查询所有用户(去重),以及其订单(避免左表因右表多条数据重复)。
java
 
运行
 
 
 
 
// LEFT JOIN + DISTINCT 去重左表记录
public List<User> listDistinctUsersWithOrders() {return queryFactory.select(distinct(qUser)) // 对左表用户去重.from(qUser).leftJoin(qUser.orders, qOrder).fetch();
}
 

四、常见误区与注意事项

1. 过滤条件写在 WHERE 子句会导致 LEFT JOIN 失效

错误示例:
sql
 
 
-- 错误:WHERE 过滤右表会把左表无匹配的行(王五)过滤掉,退化为 INNER JOIN
SELECT u.id, u.name, o.order_no
FROM t_user u
LEFT JOIN t_order o ON u.id = o.user_id
WHERE o.amount > 100;
 
正确示例(过滤条件写在 ON):
sql
 
 
SELECT u.id, u.name, o.order_no
FROM t_user u
LEFT JOIN t_order o ON u.id = o.user_id AND o.amount > 100;
 

2. LEFT JOIN 后统计右表数据(需处理 NULL)

需求:统计每个用户的订单数(无订单则为 0)。
sql
 
 
SELECT u.id, u.name, COUNT(o.id) AS order_count -- COUNT(NULL)=0,适合统计
FROM t_user u
LEFT JOIN t_order o ON u.id = o.user_id
GROUP BY u.id, u.name;
 

3. JPQL 中 LEFT JOIN 关联非关联字段

若实体未配置关联关系(如 @OneToMany),可通过 on 手动指定连接条件:
java
 
运行
 
 
 
 
// 无实体关联时的 LEFT JOIN(手动指定 ON 条件)
public List<Tuple> listUserWithOrdersNoRelation() {return queryFactory.select(qUser.id, qOrder.orderNo).from(qUser)// 手动指定左表、右表,以及连接条件.leftJoin(qOrder).on(qUser.id.eq(qOrder.userId)) .fetch();
}
 

五、核心使用场景

  1. 查询主表全量数据 + 关联表可选数据:如「查询所有商品,以及其评论(无评论则显示空)」;
  2. 统计主表记录的关联数据:如「统计每个用户的订单数(含无订单用户)」;
  3. 避免丢失左表数据:如「查询所有员工,以及其所属部门(含未分配部门的员工)」。

总结

LEFT OUTER JOIN 的核心是「左表全保留,右表匹配补,无匹配补 NULL」,是多表查询中保障左表数据不丢失的关键方式。使用时需注意:
  • 右表过滤条件写在 ON 子句,而非 WHERE;
  • 结合 COUNT() 统计时,用右表非空字段(如主键)避免统计错误;
  • JPQL/QueryDSL 中,关联实体用 leftJoin(关联字段),非关联实体用 leftJoin(右表).on(条件)。
 
mysql join on where
在 MySQL 中,JOIN ... ON 和 WHERE 是多表查询的核心语法,但二者的执行时机、作用范围、对结果集的影响 有本质区别,误用会导致查询结果不符合预期(比如 LEFT JOIN 被 “降级” 为 INNER JOIN)。以下从 核心区别、场景示例、执行原理、常见误区 四个维度,彻底讲清二者的用法和配合方式。

一、核心区别:ON vs WHERE

维度JOIN ... ONWHERE
执行时机 多表连接阶段(先匹配行,再生成临时表) 连接完成后(对临时表过滤行)
作用对象 仅作用于参与连接的两张表,控制 “哪些行能匹配” 作用于连接后的完整临时表,控制 “哪些行保留”
对 LEFT JOIN 影响 不过滤左表,仅过滤右表匹配行(无匹配则右表补 NULL) 过滤整个结果集(包括左表无匹配的行,可能丢失左表数据)
核心用途 指定表之间的连接条件(如 a.id = b.a_id) 过滤最终结果集(如 a.status = 1)

二、基础场景示例(先建测试表)

先创建两张测试表,方便后续演示:
sql
 
 
-- 左表:用户表
CREATE TABLE t_user (id INT PRIMARY KEY,name VARCHAR(20),status TINYINT -- 1=正常,0=禁用
);
INSERT INTO t_user VALUES (1, '张三', 1), (2, '李四', 1), (3, '王五', 0);-- 右表:订单表
CREATE TABLE t_order (id INT PRIMARY KEY,order_no VARCHAR(20),user_id INT,amount DECIMAL(10,2)
);
INSERT INTO t_order VALUES (101, 'O1001', 1, 99.00), (102, 'O1002', 1, 200.00), (103, 'O1003', 2, 150.00);
 

场景 1:仅用 ON 指定连接条件(LEFT JOIN 保留左表全量)

需求:查询所有用户,以及其订单(无订单则补 NULL)。
sql
 
 
SELECT u.id, u.name, o.order_no, o.amount
FROM t_user u
LEFT JOIN t_order o ON u.id = o.user_id; -- 仅指定连接条件,不过滤
 
结果:左表(t_user)的 3 条记录全部保留,右表无匹配则补 NULL:
idnameorder_noamount
1 张三 O1001 99.00
1 张三 O1002 200.00
2 李四 O1003 150.00
3 王五 NULL NULL

场景 2:ON + WHERE 过滤左表全局条件

需求:查询正常状态的所有用户,以及其订单(先过滤左表,再连接)。
sql
 
 
SELECT u.id, u.name, o.order_no, o.amount
FROM t_user u
LEFT JOIN t_order o ON u.id = o.user_id
WHERE u.status = 1; -- 过滤左表全局条件(禁用用户王五被排除)
 
结果:左表仅保留 status=1 的用户,右表匹配规则不变:
idnameorder_noamount
1 张三 O1001 99.00
1 张三 O1002 200.00
2 李四 O1003 150.00

场景 3:ON 中过滤右表(保留左表,仅过滤右表匹配行)

需求:查询所有用户,以及其金额 > 100 的订单(无符合条件订单则补 NULL)。
sql
 
 
SELECT u.id, u.name, o.order_no, o.amount
FROM t_user u
LEFT JOIN t_order o ON u.id = o.user_id AND o.amount > 100; -- ON 中过滤右表
 
结果:左表全保留,右表仅匹配金额 > 100 的订单(张三的 O1001 被过滤,王五仍为 NULL):
idnameorder_noamount
1 张三 O1002 200.00
2 李四 O1003 150.00
3 王五 NULL NULL

场景 4:WHERE 中过滤右表(LEFT JOIN 降级为 INNER JOIN)

需求:错误示例 —— 想查询所有用户 + 金额 > 100 的订单,但误用 WHERE 过滤右表:
sql
 
 
SELECT u.id, u.name, o.order_no, o.amount
FROM t_user u
LEFT JOIN t_order o ON u.id = o.user_id
WHERE o.amount > 100; -- WHERE 过滤右表,导致左表无匹配行被删除
 
结果:左表王五因 o.amount 为 NULL,不满足 o.amount > 100 被过滤,LEFT JOIN 变为 INNER JOIN:
idnameorder_noamount
1 张三 O1002 200.00
2 李四 O1003 150.00

三、执行原理(为什么会有这种区别?)

MySQL 执行多表 JOIN 查询的核心步骤:
  1. 笛卡尔积:先将左表和右表生成笛卡尔积(所有行的组合);
  2. ON 过滤:根据 ON 条件过滤笛卡尔积,保留匹配的行(LEFT JOIN 会保留左表未匹配的行,右表补 NULL);
  3. WHERE 过滤:对步骤 2 生成的临时表,按 WHERE 条件过滤,不满足的行直接删除;
  4. 分组 / 排序 / 限制:最后执行 GROUP BY、ORDER BY、LIMIT 等操作。
关键结论:ON 是 “筛选匹配的行”,WHERE 是 “筛选最终的行”;对 LEFT JOIN 来说,ON 不会删除左表行,而 WHERE 会。

四、常见误区与解决方案

误区 1:LEFT JOIN 中用 WHERE 过滤右表,导致左表数据丢失

问题:如场景 4,WHERE 过滤右表字段会删除左表无匹配的行(NULL 不满足任何比较条件)。解决方案:将右表过滤条件移到 ON 子句,或在 WHERE 中兼容 NULL:
sql
 
 
-- 方案 1:移到 ON 子句(推荐)
SELECT u.id, u.name, o.order_no, o.amount
FROM t_user u
LEFT JOIN t_order o ON u.id = o.user_id AND o.amount > 100;-- 方案 2:WHERE 中兼容 NULL(适合需同时过滤其他条件)
SELECT u.id, u.name, o.order_no, o.amount
FROM t_user u
LEFT JOIN t_order o ON u.id = o.user_id
WHERE (o.amount > 100 OR o.amount IS NULL) AND u.status = 1;
 

误区 2:INNER JOIN 中混淆 ON 和 WHERE(结果正确但性能差)

问题:INNER JOIN 中 ON 和 WHERE 过滤结果一致,但 ON 先过滤再连接,性能更高。示例:
sql
 
 
-- 低效:先连接所有行,再过滤
SELECT u.id, o.order_no
FROM t_user u
INNER JOIN t_order o ON u.id = o.user_id
WHERE u.status = 1;-- 高效:先过滤左表,再连接(减少笛卡尔积行数)
SELECT u.id, o.order_no
FROM t_user u
INNER JOIN t_order o ON u.id = o.user_id AND u.status = 1;
 

误区 3:多表 JOIN 时,ON 条件遗漏关联字段

问题:多表 JOIN 时,仅写部分关联条件,导致笛卡尔积膨胀。示例(错误 vs 正确):
sql
 
 
-- 错误:t_order 和 t_user 的关联条件写在 WHERE,导致先笛卡尔积再过滤
SELECT u.id, o.order_no, p.product_name
FROM t_user u
LEFT JOIN t_order o ON u.id = o.user_id
LEFT JOIN t_order_product p ON o.id = p.order_id
WHERE u.id = o.user_id; -- 冗余且低效-- 正确:所有关联条件写在 ON 子句
SELECT u.id, o.order_no, p.product_name
FROM t_user u
LEFT JOIN t_order o ON u.id = o.user_id
LEFT JOIN t_order_product p ON o.id = p.order_id;
 

五、最佳实践

  1. 关联条件必写在 ON:表之间的连接关系(如 u.id = o.user_id)必须写在 ON 子句;
  2. 左表全局过滤写在 WHERE:如 u.status = 1(过滤所有左表行);
  3. 右表选择性过滤写在 ON:如 o.amount > 100(保留左表,仅过滤右表匹配行);
  4. INNER JOIN 优先在 ON 过滤:减少笛卡尔积行数,提升性能;
  5. LEFT JOIN 过滤右表兼容 NULL:若必须用 WHERE 过滤右表,需加 OR 字段 IS NULL。

六、总结

需求场景正确写法
指定表之间的关联关系 JOIN ... ON 关联条件
过滤左表所有行(全局条件) WHERE 左表字段 = 值
仅过滤右表匹配行(保留左表) JOIN ... ON 关联条件 AND 右表过滤条件
过滤右表且保留左表无匹配行 WHERE (右表字段 = 值 OR 右表字段 IS NULL)
INNER JOIN 过滤(性能优先) JOIN ... ON 关联条件 AND 过滤条件
记住核心原则:ON 管 “连接匹配”,WHERE 管 “最终过滤”;LEFT JOIN 中,ON 不丢左表行,WHERE 会丢。

相关新闻

  • 高级程序语言设计第八次
  • 实验四 综合数据流处理-Storm案例构建
  • 不只是“外包”,而是共创:兰亭妙微解读UI设计合作的升维之道

最新新闻

  • 嵌入式调试利器MMDS0508:实时总线分析与非侵入式仿真实战
  • 保定卖多拉拉货车的官方授权店,货拉拉在河北省的省级总代理,核心业务与特色服务 - 企业品牌
  • 2026年漯河合同纠纷律师选对=省心 张骁隆律师值得推荐(附联系方式) - 本地品牌推荐
  • 保定哪里有卖多拉3米8,卖货拉拉货车官方授权店,货拉拉新能源汽车河北省省级总代理 - 企业品牌
  • Seedance 2.0:结构化视频生成引擎与分层可控架构解析
  • R3nzSkin英雄联盟换肤工具:免费体验全皮肤的终极指南

日新闻

  • 2026速览惠州叛逆青少年学校前十大排名名单出炉 - 武汉中职最新信息发布
  • 2026上饶白蚁消杀哪家好?15年本土2大权威白蚁防治公司推荐(金盾虫控/青蚁卫士) - 我叫一
  • 天龙八部单机版终极数据管理工具:5个技巧快速掌握游戏数据编辑

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号