一文搞懂SQL中的各种联结——内联结、自然联结、自联结、交叉联结

一、概述

所谓“ 联结 ”指的是数据表和本身,以及不同数据表之间的“ 联结关系 ”。常见的联结有自连接、自然连接、内连接、外联结、完全连接等等。本文以SQLite数据库作为实例讲解,创建了一个名为product的数据库用来存储产品信息。数据库中有两个表,一个productinfo,用来存储每一种产品的详细信息,另一个是vendors,用来存储提供产品的供应商信息,他们的结构分别如下:

productinfo表的信息如下,productname设置为主键(primary key)

vendors表的信息如下,vendname设置为主键(primary key):

二、自连接(self-join)

      所谓自连接,指的是一个表自己和自己连接,用来解决什么例子呢?比如我要查询所有的和productname=‘hc_002’来自于同一个生产厂商的的产品信息(假设我不知道hc_002是华测生产的,因为如果我知道,直接筛选就可以了,没必要联结);那就要分为两步走,第一我要先查询‘hc_001'到底是那一家公司生产,第二步才是查询公司是华测生产的所有产品的信息。再比如,我想给于’jim‘在同一个公司的所有员工发送一封邮件(假设我不知道Jim在哪个公司)同样要两步走,第一先查询Jim在哪一家公司,然后我再用查到的公司进行筛选。

        针对上面的问题,我当然可以分步去查询了,但是为了更快速查询,“ 自联结 “可以一步到位。一本文的productinfo表格而言。

SELECT C1.vendname,C1.productname,C1.productprice,C1.weight,C1.guide

FROM productinfo AS C1,productinfo AS C2    /*注意给同一个表区别名,为了区分*/

WHERE C1.vendname=C2.vendname AND C2.productname='hc_002'

当然同样的问题也可以用“ 子查询 ”去完成。

SELECT vendname,productname,productprice,weight,guide

FROM productinfo

WHERE vendname=(SELECT vendname FROM productinfo WHERE productname='hc_002')

上面两种查询的效果都是一样的,如下所示:

总结:子查询和自联结都可以完成上面所说的那种情况,但是有两个注意点

(1)自联结需要使用别名 (AS关键字);    (2)推荐使用自联结,不使用子查询,查询效率相对较高。

三、内联结(inner join)——也称之为“ 等值联结 ” (equijoin)

适用情况:适用于两个表或者是多个表有关系的情况,比如上面,如果将vendors表格也合并到productinfo表格里面去,因为每个厂商的公司地址、公司电话都是一样的,所以会出现很多重复的数据,这不仅浪费存储资源,而且降低了查询效率,为了解决问题,是用两个表,一个表专门用来存储公司地址和电话信息,及vendors,另一个专门存储各个公司所生产的产品详细信息。

现在我要查询每一公司所生产的所有产品的详细信息,怎么办?

(1)方法一——笨办法

select vendname,productname,productprice,weight

from productinfo

where vendname=’上海华测‘ORvendname=’南方数码’ORvendname=’北京吉威‘。。。。。。这样逐个删选

如果只有一个表,这么做自然没问题,既然有另一个表,这么做都没用到另一个表,自然不可取。

(2)方法二——内联结

select vendname,productname,productprice,weight

from productinfo,vendors

where productinfo.vendname=vendors.vendname

除此之外,有专门的内联结语句

select vendname,productname,productprice,weight

from productinfo INNER JOIN vendors

ON productinfo.vendname=vendors.vendname

结果如下:

两个表格中具有对应关系的 5 家公司都选出来了,至于什么 阿里巴巴、四维图新、拓普康是没有对应关系的。如果我不需要这么多,只需要选出两家指定公司的的,南方数码 武汉吉奥这两家呢,添加一点即可,如下:

select vendname,productname,productprice,weight

from productinfo,vendors

where productinfo.vendname=vendors.vendname and (vendors.vendname='南方数码' or vendors.vendname='武汉吉奥')

或者是使用专门的内联结语句

select vendname,productname,productprice,weight

from productinfo INNER JOIN vendors

ON productinfo.vendname=vendors.vendname and (vendors.vendname='南方数码' or vendors.vendname='武汉吉奥')


结果为

从上面可以看出,专门的内联结语句就是将 逗号,替换成 inner join,然后将where 替换成 on 即可。

注意,如果不使用 where 或者是 on子句会怎么样呢?如下:

select vendname,productname,productprice,weight

from productinfo inner join vendors   /*没有限制字段,直接内联结两个数据表*/

这样做的结果是产生了168条记录,因为productinfo表格有24行,vendors表有7行,,故而总共有24*7=168条记录。这称之为

“ 笛卡尔积 ”,笛卡尔积检索出的行目是两个数据表中行数的乘积。返回笛卡尔积的联结称之为“ 叉联结 ”(cross join)。

孤儿为了获取需要的数据,一定不能忘记了where子句或者是on子句。

总结:(1)内联结是很有必要的  (2)内联结因为有两个表,注意“ 完全限定名 ”的使用。

          (3)不要过多对三个及三个以上表使用内联结,会降低性能,而且连接表有最大数目限制,不同数据库不一样,可参考文档。

           (4)内联结一定不能忘了 where 子句或者是 on 子句,否则会产生出乎意料的结果(笛卡尔积)

四、叉联结(cross join)——参见上面的笛卡尔积。

五、自然联结(Natural join)

1、内连接与等值连接是一回事情。
等值连接是条件连接在连接运算符为“=”号时的特例。它是从关系R与S的广义笛卡尔积中选取A,B属性值相等的那些元组
自然连接是一种特殊的等值连接,它要求两个关系中进行比较的分量必须是相同的属性组,并且在结果中把重复的属性列去掉  
等值连接表示为RA=BS,自然连接表示为RS;自然连接是除去重复属性的等值连接。两者之间的区别和联系如下: 

比如:本文以SQLite为例加以说明,不同数据库会稍有区别。

内联结代码如下:

select p.*,v.*

from productinfo as p inner join vendors as v

on p.vendname=v.vendname

运行结果如下:

自然联结代码如下:

select p.*,v.*

from productinfo as p natural join vendors as v

结果如下:

可以发现,上面二者的结果是一样的,但是“ 自然联结 ”不需要使用where 或者是 on 限定条件,它会自动根据字段的只加以匹配,这就是“自然”两个字的含义,即自发的匹配。

但是,自然结合 这种自发的匹配并不是随意的 它必须有一个严格的限制条件,那就是两个表中必须要具有公共字段,而且这两个公共字段的名称必须一样,值得类型也必须一样,才能让其“ 自发 ”的匹配。即productinfo和vendors都有一个相同的字段vendname,且他们的返回值一样。

2、比如现在有一个新的表vendors01,他的结构如下:

该表于vendors表格的区别在于,他不再是vendname,而是vendname01,这时候就没办法进行自然匹配了,那会产生怎样的结果呢?

select p.*,v.*

from productinfo as p natural join vendors01 as v

这时候进行自然匹配会产生一个 行数为72的结果,因为虽然vendname01里面依然有 南方数码 和 上海华测,但是因为字段的名称不一样,会默认为他们不是一样的列。故而会产生笛卡尔积。此时对这种列名称不一样的情况,只有进行内联结了,内联结的代码如下:

select p.*,v.*

from productinfo as p inner join vendors01 as v

on p.vendname=v.vendname01    /*对于1内联结来说,列名不一样没关系*/

结果为:

由此可见,及时列名不一样,只要该列的值有一样的,内联结依然适用,这就是为什么称之为“ 等值联结”的原因了。

总结
1、自然连接是特殊的内联结(等值联结),自然联结不能有where和on去限制筛选
2、等值连接要求相等的分量,不一定是公共属性(即相同的列名);而自然连接要求相等的公共属性(列名)。
  
 

关于“ 外联结 ”,请参见下文。

猜你喜欢

转载自blog.csdn.net/qq_27825451/article/details/81326165