关于Left join,你可能不知道这些

Posted 泡^泡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于Left join,你可能不知道这些相关的知识,希望对你有一定的参考价值。

一对一

这种情况最好理解。t_name表,有id,name(用户名称),sex(性别),dt(注册日期)等字段。t_age表。有id,age(年龄),province(省份),dt(更新日期)等字段。表中包含的信息如下:

现在我们进行t_name(左表,别名a)和t_age(右表,别名b)的left join 操作,关联键为id。a表有6条记录,b表有3条记录,且关键的键是唯一的,因此最终结果以a表为准有6条记录,b表有3条关联不上,相应的记录中,b表所有的字段都为空。

一对多

这回我们用t_age作为左表,关联条件为dt。重点看dt为20190905的记录。由于右表有3条20190905,这三条在关联的时候都满足关联条件,因此最终的结果会有3条记录是20190905。

这回为准的表是t_age表,但显然结果并不是原本的3条记录,而是7条:20190905 3条,20190906 4条。如果你不太理解,可以继续往下看。

多对多

上面例子中,20190906的记录最终有4条,同样是因为满足了关联条件,是一种2对2的情况。这里我们还是回到t_name表做主表的情况,用dt来关联。可以预见,与2中相比,这次结果中会多一行20190907的,而b表相应的字段依然为空。

left join 的执行原理

mysql采用嵌套循环的方式处理left join。
SELECT * FROM LT LEFT JOIN RT ON P1(LT,RT)) WHERE P2(LT,RT)

其中P1是on过滤条件,缺失则认为是TRUE,P2是where过滤条件,缺失也认为是TRUE,该语句的执行逻辑可以描述为:
FOR each row lt in LT // 遍历左表的每一行
BOOL b = FALSE;
FOR each row rt in RT such that P1(lt, rt) // 遍历右表每一行,找到满足join条件的行
IF P2(lt, rt) //满足 where 过滤条件
t:=lt||rt;//合并行,输出该行

b=TRUE;// lt在RT中有对应的行

IF (!b)  // 遍历完RT,发现lt在RT中没有有对应的行,则尝试用null补一行
IF P2(lt,NULL) // 补上null后满足 where 过滤条件
t:=lt||NULL; // 输出lt和null补上的行



  1. 如果想对右表进行限制,则一定要在on条件中进行,若在where中进行则可能导致数据缺失,导致左表在右表中无匹配行的行在最终结果中不出现,违背了我们对left join的理解。因为对左表无右表匹配行的行而言,遍历右表后b=FALSE,所以会尝试用NULL补齐右表,但是此时我们的P2对右表行进行了限制,NULL若不满足P2(NULL一般都不会满足限制条件,除非IS NULL这种),则不会加入最终的结果中,导致结果缺失。
  2. 如果没有where条件,无论on条件对左表进行怎样的限制,左表的每一行都至少会有一行的合成结果,对左表行而言,若右表若没有对应的行,则右表遍历结束后b=FALSE,会用一行NULL来生成数据,而这个数据是多余的。所以对左表进行过滤必须用where。

我们再来看看实例,返回来研究这段话可能更好理解一些。

  1. 只有1个on条件
    这里可以直接看第一部分中的例子。最终会输出以左表为准,右表匹配不上补null的结果,但可能会有多对多的情况。
  2. 有2个on条件

    上图是在关联条件中增加了b.age=24之后的输出结果。由于对b表进行了限制,满足条件的只有一个,但是由于没有where条件,因此依然要以左表为准,又因为是一对一,所以输出还是左表的记录数。更极端的,我们可以“清空”b表。

    以上两种情况,在b表中都没有符合条件的结果,因此在以左表为准的基础上,右边的所有字段都为空。

3.有where的情况

将b.age=24写到where里,发现结果中只有这一行,打破了“left join”以左表为主的限制。同样再来看下后两种情况写到where里会发生什么:

没错,结果全部是为空的。因为where 在 on 后面执行,而on生成的结果里没有满足条件的记录!
这里给出两个结论:

1、 on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录。
2、where条件是在临时表生成好后,再对临时表进行过滤的条件。这时已经没有left
join的含义(必须返回左边表的记录)了,条件不为真的就全部过滤掉。

以上是关于关于Left join,你可能不知道这些的主要内容,如果未能解决你的问题,请参考以下文章

Oracle left join 或right join

mysql left join的深入探讨

Etl之HiveSql调优(left join where的位置)

如何取得left join的第二表中符合条件的第一条记录?

MySQL LEFT JOIN 你可能需要了解的三点

关于Left join