2021年必看!Mysql的left join无效问题剖析及使用详解

解决Mysql的left join无效及使用的注意事项说明

2021 年 7 月 1 日 10 时 05 分进行了更新,作者是栗子木。

这篇文章主要介绍了关于解决 Mysql 的 left join 无效的相关内容以及使用时的注意事项,这些内容具有很好的参考价值,希望能对大家有所帮助。倘若存在错误或者未考虑周全的地方,希望大家不吝赐教。

Mysql的left join无效及使用

今天写 sql 时发现,使用 left join 并没有将左边表的所有数据都查询出来,这让我郁闷了一段时间。之后我仔细研究了一会儿,才意识到自己犯了一个常识性的错误(我是新手)。

这是原sql

这样的查询无法将 tb_line 这张表的所有数据都查询出来,真的很尴尬……

之后我才知晓,当我们进行多表查询时,在执行到 where 之前,会首先形成一个临时表。

on 是临时表中的条件筛选。使用 left join 时,无论条件是否为真,都会查询出左边表的数据。如果条件为假,就会显示为 null。

where则是在临时表生成之后的过滤条件

在第一张图里,我把 tb_vehicle 这张表的过滤条件置于 where 之中。这样一来,left join 所产生的条件为假的数据,会在 where 的 v.del_flag='0'中被过滤掉,原因是条件为假的数据,其 del_flag 都为空。

所以我看上去使用了 left join 。实际上,这样的写法所得到的结果和使用 inner join 是相同的。

正确sql如下:

在临时表中就做好条件筛选,这样就能够得到左边表的数据

总结:

在使用 left join 并且需要进行条件查询时,需要谨慎考虑该条件筛选究竟放在 on 后面还是 where 后面。

Mysql left join 避坑指南现象

在我们使用 mysql 查询时,left join 非常常见。例如,博客里一篇文章的评论数量、商城里一个货物的评论数量、一条评论的点赞数量等情况。然而,由于对 join、on、where 等关键字不熟悉,有时会致使查询结果与预期不同。所以,今天我来进行总结,一起避免踩坑。

这里先给出一个场景,接着抛出两个问题。倘若你都能答对,那么这篇文章就无需再看了。

假设有一个班级管理应用,存在一个名为 classes 的表,其中存了所有的班级;还有一个名为 students 的表,里面存了所有的学生,其具体数据情况如下:

SELECT * FROM classes;

SELECT * FROM students;

那么现在有两个需求:

找出每个班级的名称及其对应的女同学数量

找出一班的同学总数

对于需求 1,大多数人在未经思考的情况下就能想出以下两种 sql 写法。请问,这两种写法中哪一种是正确的?

选择 c 的 name,将 s 的 name 进行计数并命名为 num 。
使用左连接(left join)将 classes 表 c 和 students 表 s 进行连接操作。
    on s.class_id = c.id 
    and s.gender = 'F'
    group by c.name

或者

SELECT c.name, count(s.name) as num 
    FROM classes c left join students s 
    on s.class_id = c.id 
    where s.gender = 'F'
    group by c.name

对于需求 2,大多数人能够不假思索地想出以下两种 SQL 写法。请问,这两种写法哪一种是正确的?

SELECT c.name, count(s.name) as num 
    FROM classes c left join students s 
    on s.class_id = c.id 
    where c.name = '一班' 
    group by c.name

或者

SELECT c.name, count(s.name) as num 
    FROM classes c left join students s 
    on s.class_id = c.id 
    and c.name = '一班' 
    group by c.name

不要继续往下翻啦!先给出你自己的答案,因为正确答案就在下面呢。

答案有两个需求,其中第一条语句是正确的。要弄清楚这个问题,就必须明白 mysql 对于 left join 的执行原理,下节将对此展开。

根源

mysql 在处理 left join 时采用类似嵌套循环的方式。以下面的语句为例:

从 LT 表中选择所有数据,然后将其与 RT 表进行左连接,连接条件是 P1(LT,RT),最后筛选出满足 P2(LT,RT)条件的数据。

其中一个过滤条件是 P1 且为 on 条件,若缺失则视为 TRUE;另一个过滤条件是 P2 且为 where 条件,若缺失也视为 TRUE。该语句的执行逻辑可描述为:先判断 P1 条件(若有则为 on 条件,若无视为 TRUE),再判断 P2 条件(若有则为 where 条件,若无视为 TRUE)。

对于左表的每一行 lt,进行如下操作:
  BOOL b = FALSE;
对于 RT 中的每一行 rt 而言,如果 P1(lt, rt)成立,那么就进行以下操作:// 遍历右表每一行,找到满足 join 条件的行
如果 P2 小于 rt 且 P2 大于 lt ,那么就满足 where 过滤条件 。
      t:=lt||rt;//合并行,输出该行
    }
    b=TRUE;// lt在RT中有对应的行
  }
如果 b 不成立,即遍历完 RT 后,发现 lt 在 RT 中没有对应的行,那么就尝试用 null 补一行。
如果 P2 小于某个值且该值为 NULL 时满足 where 过滤条件;
      t:=lt||NULL; // 输出lt和null补上的行
    }         
  }
}

在实际情况里,MySQL 会通过使用 buffer 的方式来进行优化,以此减少行比较的次数。然而,这并不会对关键的执行流程产生影响,并且也不在本文的讨论范围之内。

从这个伪代码中,我们可以看出两点:

如果要对右表进行限制,那就必须在 on 条件中进行。要是在 where 中进行,就可能会使数据缺失,从而让左表中在右表中没有匹配行的那些行在最终结果中不出现,这违背了我们对于 left join 的理解。对于左表无右表匹配行的那些行来说,在遍历右表之后,b 为 FALSE。于是会尝试用 NULL 来补齐右表。然而,此时我们的 P2 对右表行进行了限制,由于 NULL 通常都不会满足限制条件(除非是 IS NULL 这种情况),所以如果 NULL 不满足 P2,就不会被加入到最终的结果中,从而导致结果缺失。

如果不存在 where 条件,不管 on 条件怎样对左表进行限制,左表的每一行都至少会有一行合成结果。对于左表的行来说,倘若右表没有对应的行,那么在右表遍历结束后,b 为 FALSE,此时会用一行 NULL 来生成数据,而这部分数据是多余的。因此,必须使用 where 对左表进行过滤。

下面展开两个需求的错误语句的执行结果和错误原因:

需求1

需求2

需求 1 因为在 where 条件里对右表进行了限制,所以导致了数据缺失,具体来说,四班本应该有一个结果为 0 的情况。

需求 2 由于在 on 条件中对左表进行了限制,所以导致数据出现多余的情况,即其他班的结果也被显示出来了,而且这些结果还是错误的。

总结

通过上面的问题现象及分析,得出结论:在 left join 语句里,左表的过滤需放在 where 条件中,右表的过滤需放在 on 条件中,如此一来,结果才能不多不少且刚刚好。

SQL 看起来较为简单,然而实际上其中蕴含着诸多细节原理。哪怕只是一个小小的混淆,都可能致使结果与预期不一致。因此,在平时应当留意这些细节原理,以防在关键时候出现错误。

这是个人的经验,希望能给大家提供参考,同时也希望大家多多支持脚本之家。

本文来自作者[qulangwang]投稿,不代表趣浪号立场,如若转载,请注明出处:https://qulangwang.cn/life/202504-15544.html

(21)

文章推荐

  • 内幕揭秘“边锋老友二打一开挂辅助软件”原来确实有挂

    无需打开直接搜索微信:本司针对手游进行,选择我们的四大理由:1、软件助手是一款功能更加强大的软件!无需打开直接搜索微信:2、自动连接,用户只要开启软件,就会全程后台自动连接程序,无需用户时时盯着软件。3、安全保障,使用这款软件的用户可以非常安心,绝对没有被封的危险存在。

    2025年02月15日
    82
  • 必备教程“微扑克透视 !详细教程(确实真的有挂)

    亲,根据资深记者爆料分享实测“是可以开挂的,确实有挂(咨询软件无需打开直接加微vk3724)您好,天天川麻,确实是有挂的,很多玩家在这款游戏中打牌都会发现很多用户的牌特别好,总是好牌,而且好像能看到其他人的牌一样。所以很多小伙伴就怀疑这款游戏是不是有挂,实际上这款

    2025年02月15日
    76
  • 终于知晓“熊猫麻将究竟有没有挂(确实真的有挂)

    亲,这款游戏可以开挂的,确实是有挂的,很多玩家在这款游戏中打牌都会发现很多用户的牌特别好,总是好牌,而且好像能看到-人的牌一样。所以很多小伙伴就怀疑这款游戏是不是有挂,实际上这款游戏确实是有挂的,添加客服微信vk3724安装软件.万能游戏透视

    2025年02月16日
    115
  • 传递经验“欢聚斗地主水鱼是不是有人用挂”(曝光透视必备猫腻)

    亲,欢聚斗地主水鱼开挂神器下载软件这款游戏原来确实可以开挂,详细开挂教程请添加微信(9229591),免费测试1、起手看牌2、随意选牌3、控制牌型4、注明,就是全场,公司软件防封号、防检测、 正版软件、非诚勿扰。2025首推。全网独家,诚信可靠,无效果全额退款,本司推出

    2025年02月17日
    74
  • 2025国考行测试题及答案解析:副省级、行政执法、地市级真题回顾

    2025年国家考试书面考试已经结束!战斗已经结束了一天。当记忆仍然很深时,让我们首先回答测试!以下是2025年全国考试市政测试的相关内容,并提供参考答案!2025年国家公务员考试“实用测试”测试问题和参考答案(副总级别+行政执法+市政级别)注意:此测试问题来自候选人的记忆和在线编译,仅供学习

    2025年02月18日
    729
  • 科普分享“wepoker德州辅助器透视挂(透视)详细辅助透视教程

     大家好,今天小编来为大家解答wepoker德州有没有挂这个问题,加我们微(68079902)免费测试 wepoker德州的挂在哪里买很多人还不知道,现在让我们一起来看看吧!一、wepoker德州怎么全显示你需要获得记牌器才能全部显示,

    2025年02月19日
    78
  • 手机麻将游戏“微乐麻将有挂吗”(确实能开挂)

    微乐麻将开挂神器是一款可以让一直输的玩家,快速成为一个“必胜”的ai辅助神器,有需要的用户可以加我微下载使用。手机打牌可以一键让你轻松成为“必赢”。其操作方式十分简单,打开这个...我来教教大家“微乐麻将”真实开挂技巧分享微信84788670微乐麻将开挂神器是一款可以让一

    2025年02月22日
    87
  • 给大家通报一下“微乐甘肃麻将万能挂下载安装”(确实是有挂)-知乎!

    微乐甘肃麻将开挂神器是一款可以让一直输的玩家,快速成为一个“必胜”的ai辅助神器,有需要的用户可以加我微下载使用。手机打牌可以一键让你轻松成为“必赢”。其操作方式十分简单,打开这个...我来教教大家“微乐甘肃麻将”真实开挂技巧分享微信84788670微乐甘肃麻将开挂神器是

    2025年02月24日
    54
  • 防洪防汛常识:防汛基本知识、降雨特性及洪水自救指南

    防洪防汛常识一、防汛基本知识1、什么是防汛防汛是为了防止和减轻洪水灾害而开展的工作,包括洪水预报、防洪调度以及防洪工程运用等方面。汛的意思是江河、湖泊等水域会出现季节性或周期性的涨水现象。2、降雨的特性降雨可依据空气上升的原因进行分类。一类是峰面雨,一类是地形雨,一类是对流雨,还有一类是台

    2025年04月06日
    40
  • 古代地方官职文化常识:判官与通判的官职设置与发展

    古代地方官职文化常识(二)判官是一个官名。隋朝开始设置判官。按照唐朝的制度,被特别派遣担任临时职务的大臣可以自行挑选中级官员,奏请让他们担任判官,以此来帮助自己处理事务。五代时期的州府也设置了判官,其权力和地位逐渐变得重要。宋代在各州府沿袭设置判官,选派京官担任并称为签书判官厅公事,简称“签判”。

    2025年04月06日
    17

发表回复

本站作者后才能评论

评论列表(4条)

  • qulangwang
    qulangwang 2025年04月13日

    我是趣浪号的签约作者“qulangwang”!

  • qulangwang
    qulangwang 2025年04月13日

    希望本篇文章《2021年必看!Mysql的left join无效问题剖析及使用详解》能对你有所帮助!

  • qulangwang
    qulangwang 2025年04月13日

    本站[趣浪号]内容主要涵盖:生活百科,小常识,生活小窍门,知识分享

  • qulangwang
    qulangwang 2025年04月13日

    本文概览:这篇文章主要介绍了解决Mysql的left join无效及使用的注意事项说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...

    联系我们

    邮件:趣浪号@sina.com

    工作时间:周一至周五,9:30-18:30,节假日休息

    关注我们