SQL中left join的一些易忽略点


=Start=

缘由:

整理记录一下最近在使用left join时碰到的坑,方便以后参考,避免以后再出现实际和预期不一致的情况。

正文:

参考解答:

在学习SQL的左连接(left join)时看到的一句话,让我快速的了解了它的功能:

以LEFT [OUTER] JOIN关键字前面的表作为主表,和其他表进行关联,返回记录和主表的记录数一致,关联不上的字段置为NULL。

但是它的结论不总是正确的!

在使用left join的时候,一定要注意被关联表(除了第一张表之外的表)的数据里面有没有重复的内容,如果有的话,结果记录和主表的记录就不一定一致(即便使用distinct关键字去重)。

下面以2张测试表做left join来说明一下。

tableA的内容如下:


col1col2col3
1a1xy
2a2xz
3a3yy

tableB的内容如下:


col1col2
1a1m
2a1n
3a2m
4a2m

此时进行left [outer] join的测试SQL:

select
x1.*, x2.*
from
(select
*
from
tableA
)x1
left outer join
(select
*
from
tableB
)x2
on x1.col1 = x2.col1
;

当tableB中没有第4行(a2,m)时,两表join的结果(有4行)如下:

a1 a1 
a1 a1 
a2 a2 
4a3 NULL NULL 

可以看到,其结果为4行,比tableA的3行要多出1行,因为在tableB中在col1列里面的a1字段有重复项(虽然整行的内容并不重复)。

当在tableB中加入第4行后,结果就再增加了1行(有5行),如果用distinct关键字去重的话会滤掉对应重复的内容(有4行,但依然比tableA的3行要多1行):

select distinct
x1.col1,
x1.col2,
x1.col3,
x2.col1 as x2_col1,
x2.col2 as x2_col2
from
(select
*
from
tableA
)x1
left outer join
(select
*
from
tableB
)x2
on x1.col1 = x2.col1
;

所以,在使用left join的时候,一定要注意被关联表的数据里面有没有重复的内容,如果有的话,结果记录和主表的记录就不一定一致(即便使用distinct关键字去重)。

参考链接:

https://stackoverflow.com/questions/39271323/hive-left-join-vs-join-gives-different-results-with-filter-in-on-clause

https://cwiki.apache.org/confluence/display/Hive/OuterJoinBehavior

=END=

,

《 “SQL中left join的一些易忽略点” 》 有 4 条评论

  1. `
    mark一下:
    Hive SQL中的left outer join还是要注意一下,假设是两张表A和B进行关联,其中B是数据量较小的表,如果希望避免数据偏移以及提速的话(在只需要取出两者中都存在的特征时),【最好把表B(数据量较小的表)放在前面】,【然后在on条件后面加上where的过滤】,否则直接按顺序进行A和B的关联时,会发现产出的结果太大,且不符合自己的需求。
    `

  2. Hive Join 的原理与机制
    https://www.hadoopdoc.com/hive/hive-join

    你会“Join”吗?Hive中的join操作大总结!
    https://juejin.cn/post/7033548041319940127
    `
    Hive 中 join 有 4 种类型。分别是:
    1. 内关联(inner join 或者简写成 join)
    2. 左关联(left outer join 或者简写成 left join)
    3. 右关联(right outer join 或者简写成 right join)
    4. 全关联(full outer join 或者简写成 full join)

    1.inner join(内连接,只有进行连接的两个表中都存在与连接条件相匹配的数据才会被留下来)
    内连接是最常见的一种连接,它也被称为普通连接,而E.FCodd最早称之为自然连接。其中inner可以省略。

    2.left join 是左外连接(Left Outer Jion),其中outer可以省略,left outer join是早期的写法。
    A left join B 是以A表的记录为基础的,A可以看成左表,B可以看成右表,left join是以左表为准的。
    意思说,左表(A)的记录将会全部表示出来(不管右边的表中是否存在与它们匹配的行),而右表(B)只会显示符合搜索条件的记录,比如符合on,where中的条件。B表记录不足的地方均为NULL。
    A left join B =等价= B right join A

    3.right join ,同理和left join相反,A right join B ,则显示B表中所有的记录,A表不足的用null填充
    同样 right outer join = right join , outer可以省略。

    4. full outer join 等价 full join ,全关联
    全关联的原理是先左关联再右关联,然后把结果用 union all 合并在一起,关联不到的字段被自动置为 NULL。是否指定 outer 关键字,对查询结果无影响。
    `

    Hive中Join的类型和用法
    https://www.cnblogs.com/liupengpengg/p/7908274.html
    `
    Hive中除了支持和传统数据库中一样的内关联、左关联、右关联、全关联,还支持LEFT SEMI JOIN和CROSS JOIN,但这两种JOIN类型也可以用前面的代替。

    注意:Hive中join的关联键必须在on()中指定,不能在where中指定,否则就会先做笛卡尔积,再过滤。
    `

  3. hive 各种 join (left outer join、join、full outer join)
    https://blog.csdn.net/smile0198/article/details/38665321
    `
    1、左连接 left outer join
    以左边表为准,逐条去右边表找相同字段,如果有多条会依次列出。

    2、连接join
    找出左右相同同的记录。

    3、全连接 full outer join
    包括两个表的join结果,左边在右边中没找到的结果(NULL),右边在左边没找到的结果。
    会对结果去重,返回并集。
    `

  4. [一起学Hive]之十一-Hive中Join的类型和用法
    http://lxw1234.com/archives/2015/06/315.htm
    `
    之前写 left outer join 的时候,总喜欢把每一个要参与的表都用 select 先查出来,然后再用括号给括起来,添加一个临时的表名,再不断的:
    left outer join
    (select
    *
    from
    tbl_name
    )t2
    on t1.xid = t2.xid

    但是,如果 tbl_name 表本身的字段结构很简单的话,其实不需要这么麻烦,直接把表名写在那里就可以了:
    left outer join
    tbl_name t2
    on t1.xid = t2.xid

    这样SQL显得更简洁(尤其是最上方已经通过with语句创建的临时表),也算是去除了我之前的一块心病吧,哈哈。
    `

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注