Skip to content

INNER JOIN 和 OUTER JOIN 之间有什么区别? 38549  #4

@bitfishxyz

Description

@bitfishxyz

'INNER JOIN' 和 'OUTER JOIN' 之间有什么区别?

首先假设我们有下面两张表:

drop table if exists t_a;
create table t_a(id int);
insert into t_a(id) values (1);
insert into t_a(id) values (2);
insert into t_a(id) values (3);
insert into t_a(id) values (4);

drop table if exists t_b;
create table t_b(id int, str char(10));
insert into t_b(id) values (3);
insert into t_b(id, str) values (4, 'qq');
insert into t_b(id, str) values (4, 'mm');
insert into t_b(id) values (5);
insert into t_b(id) values (6);

Screen Shot 2019-04-03 at 3.37.16 PM

Screen Shot 2019-04-03 at 4.08.13 PM

Join

回答这个问题之前,首先要明白join这个关键字

那么下面这个语句的返回值是什么?

select * from t_a join t_b;

读者可以思考下再来看结果。

d

上面的就是 join的结果。

我们来分析下上面的结果。刚好是 4 * 5 = 20 行。

这其实是把两个表给 【相乘】 了,类似于笛卡尔积。

上面的语句还有一种写法,就是 cross join

select * from t_a cross join t_b;

结果是一样的。

inner join

select *
  from t_a inner join t_b
       on t_a.id = t_b.id;

Screen Shot 2019-04-03 at 3.51.15 PM

inner join 就是对join的结果进行过滤,它只保留符合on后面条件的结果。

这里我们只筛选出两个表中id相同的结果。

上面的SQL语句等价于下面的

select * from t_a, t_b
 where t_a.id = t_b.id;

这个语句其实隐式的产生了inner join操作。

不过前者更有语义化,推荐是使用前者,不要使用后者。

outer join

在之前的inner join过程中,我们发现这样的记录也被过滤了

比如说在t_b表中有的id5的记录,它在t_a表中就没有对应的id5的记录,导致这样的数据直接被过滤了。

如果你想保留这些数据,你可以使用 outer join

select *
  from t_a right outer join t_b
       on t_a.id = t_b.id;

Screen Shot 2019-04-03 at 3.59.45 PM

我们可以看到outer join相比于inner join就是会保留一些没有匹配上的数据。然后outer join 分为 left outer joinright inner join。它们的区别在于一个是以左边的为基准,一个是以右边的为基准,看下操作结果就明白了。

select *
  from t_a left outer join t_b
       on t_a.id = t_b.id;

Screen Shot 2019-04-03 at 4.00.12 PM

其实用语言不好描述,大家多看几次结果就懂了。

full outer join

当然,除了有左联结,有联结,含有全联结

参考这样的语句

select *
  from t_a full outer join t_b
       on t_a.id = t_b.id;

不过我用的是MySQL,目前不支持这种写法,但是上面的语句可以通过下面的写法来模拟

select *
  from t_a right outer join t_b
       on t_a.id = t_b.id
union 
select *
  from t_a left outer join t_b
       on t_a.id = t_b.id;

总结

  • inner join 就是取两个表的交集

    Screen Shot 2019-04-03 at 4.17.33 PM

  • left outer join

    Screen Shot 2019-04-03 at 4.17.51 PM

  • full outer join的结果如下

    Screen Shot 2019-04-03 at 4.17.44 PM

发散思维

如果我想要下面的结果, 如何写SQL语句?

Screen Shot 2019-04-03 at 4.17.57 PM

下拉可以看到答案

select *
  from t_a left outer join t_b
       on t_a.id = t_b.id
where t_b.id is null;

Screen Shot 2019-04-03 at 4.24.41 PM

上述SQL语句删除了在集合a但是不在集合b的记录。

Metadata

Metadata

Assignees

No one assigned

    Labels

    SOExtra attention is neededSQL

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions