SQL内连接与外连接

1.概述

1、内联接(典型的联接运算,使用像 = 或 <> 之类的比较运算符)。包括相等联接和自然联接。
内联接使用比较运算符根据每个表共有的列的值匹配两个表中的行。例如,检索 students和courses表中学生标识号相同的所有行。

2、外联接。
外联接可以是左向外联接、右向外联接或完整外部联接。 
 FROM子句中指定外联接时,可以由下列几组关键字中的一组指定: 
1)LEFT JOIN或LEFT OUTER JOIN 
左向外联接的结果集包括 LEFT OUTER子句中指定的左表的所有行,而不仅仅是联接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值。
2)RIGHT JOIN 或 RIGHT OUTER JOIN 
右向外联接是左向外联接的反向联接。将返回右表的所有行。如果右表的某行在左表中没有匹配行,则将为左表返回空值。
3)FULL JOIN 或 FULL OUTER JOIN
完整外部联接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值。


例子: 
-------------------------------------------------
a表 id name  b表 id job parent_id 
1 张3 1 23 1 
2 李四 2 34 2 
3 王武 3 34 4 
a.id同parent_id 存在关系 
-------------------------------------------------- 
1) 内连接 
select a.*,b.* from a inner join b on a.id=b.parent_id 
结果是 
1 张3 1 23 1 
2 李四 2 34 2 

2)左连接 
select a.*,b.* from a left join b on a.id=b.parent_id 
结果是 
1 张3 1 23 1 
2 李四 2 34 2 
3 王武 null 

3) 右连接 
select a.*,b.* from a right join b on a.id=b.parent_id 
结果是 
1 张3 1 23 1 
2 李四 2 34 2 
null 3 34 4 

4) 完全连接 (不做过多概述)
select a.*,b.* from a full join b on a.id=b.parent_id 
结果是 
1 张3 1 23 1 
2 李四 2 34 2 
null    3 34 4 
3 王武 null

2.内连接(INNER JOIN


内连接(INNER JOIN):有两种,显式的和隐式的,返回连接表中符合连接条件和查询条件的数据行。(所谓的链接表就是数据库在做查询形成的中间表)。
例如:下面的语句3和语句4的结果是相同的。

语句1:隐式的内连接,没有INNER JOIN,形成的中间表为两个表的笛卡尔积。
SELECT O.ID,O.ORDER_NUMBER,C.ID,C.NAME
FROM CUSTOMERS C,ORDERS O
WHERE C.ID=O.CUSTOMER_ID;

语句2:显示的内连接,一般称为内连接,有INNER JOIN,形成的中间表为两个表经过ON条件过滤后的笛卡尔积。
SELECT O.ID,O.ORDER_NUMBER,C.ID,C.NAME
FROM CUSTOMERS C INNER JOIN ORDERS O ON C.ID=O.CUSTOMER_ID;

3.外连接(OUTER JOIN):

外连不但返回符合连接和查询条件的数据行,还返回不符合条件的一些行。外连接分三类:左外连接(LEFT OUTER JOIN)、右外连接(RIGHT OUTER JOIN)和全外连接(FULL OUTER JOIN)。
三者的共同点是都返回符合连接条件和查询条件(即:内连接)的数据行。不同点如下:
左外连接还返回左表中不符合连接条件单符合查询条件的数据行。
右外连接还返回右表中不符合连接条件单符合查询条件的数据行。
全外连接还返回左表中不符合连接条件单符合查询条件的数据行,并且还返回右表中不符合连接条件单符合查询条件的数据行。全外连接实际是上左外连接和右外连接的数学合集(去掉重复),即“全外=左外 UNION 右外”。
说明:左表就是在“(LEFT OUTER JOIN)”关键字左边的表。右表当然就是右边的了。在三种类型的外连接中,OUTER 关键字是可省略的。

下面举例说明:
语句3:左外连接(LEFT OUTER JOIN)
SELECT O.ID,O.ORDER_NUMBER,O.CUSTOMER_ID,C.ID,C.NAME
FROM ORDERS O LEFT OUTER JOIN CUSTOMERS C ON C.ID=O.CUSTOMER_ID;

语句4:右外连接(RIGHT OUTER JOIN)
SELECT O.ID,O.ORDER_NUMBER,O.CUSTOMER_ID,C.ID,C.NAME
FROM ORDERS O RIGHT OUTER JOIN CUSTOMERS C ON C.ID=O.CUSTOMER_ID;
注意:WHERE条件放在ON后面查询的结果是不一样的。例如:

语句5:WHERE条件独立。
SELECT O.ID,O.ORDER_NUMBER,O.CUSTOMER_ID,C.ID,C.NAME
FROM ORDERS O LEFT OUTER JOIN CUSTOMERS C ON C.ID=O.CUSTOMER_ID
WHERE O.ORDER_NUMBER<>'MIKE_ORDER001';

语句6:将语句5中的WHERE条件放到ON后面。
SELECT O.ID,O.ORDER_NUMBER,O.CUSTOMER_ID,C.ID,C.NAME
FROM ORDERS O LEFT OUTER JOIN CUSTOMERS C ON C.ID=O.CUSTOMER_ID AND O.ORDER_NUMBER<>'MIKE_ORDER001';

从语句5和语句6查询的结果来看,显然是不相同的,语句6显示的结果是难以理解的。因此,推荐在写连接查询的时候,ON后面只跟连接条件,而对中间表限制的条件都写到WHERE子句中。

语句7:全外连接(FULL OUTER JOIN)。
SELECT O.ID,O.ORDER_NUMBER,O.CUSTOMER_ID,C.ID,C.NAME
FROM ORDERS O FULL OUTER JOIN CUSTOMERS C ON C.ID=O.CUSTOMER_ID;
注意:MySQL是不支持全外的连接的,这里给出的写法适合Oracle和DB2。但是可以通过左外和右外求合集来获取全外连接的查询结果。
语句8:左外和右外的合集,实际上查询结果和语句7是相同的。
SELECT O.ID,O.ORDER_NUMBER,O.CUSTOMER_ID,C.ID,C.NAME
FROM ORDERS O LEFT OUTER JOIN CUSTOMERS C ON C.ID=O.CUSTOMER_ID
UNION
SELECT O.ID,O.ORDER_NUMBER,O.CUSTOMER_ID,C.ID,C.NAME
FROM ORDERS O RIGHT OUTER JOIN CUSTOMERS C ON C.ID=O.CUSTOMER_ID;

4.SQL查询的基本原理:两种情况介绍。


第一、
单表查询:根据WHERE条件过滤表中的记录,形成中间表(这个中间表对用户是不可见的);然后根据SELECT的选择列选择相应的列进行返回最终结果。

第二、两表连接查询:对两表求积(笛卡尔积)并用ON条件和连接连接类型进行过滤形成中间表;然后根据WHERE条件过滤中间表的记录,并根据SELECT指定的列返回查询结果。

第三、
多表连接查询:先对第一个和第二个表按照两表连接做查询,然后用查询结果和第三个表做连接查询,以此类推,直到所有的表都连接上为止,最终形成一个中间的结果表,然后根据WHERE条件过滤中间表的记录,并根据SELECT指定的列返回查询结果。
理解SQL查询的过程是进行SQL优化的理论依据。

ON后面的条件(ON条件)和WHERE条件的区别:
ON条件:是过滤两个链接表笛卡尔积形成中间表的约束条件。
WHERE条件:在有ON条件的SELECT语句中是过滤中间表的约束条件。在没有ON的单表查询中,是限制物理表或者中间查询结果返回记录的约束。在两表或多表连接中是限制连接形成最终中间表的返回结果的约束。
从这里可以看出,将WHERE条件移入ON后面是不恰当的。推荐的做法是:
ON只进行连接操作,WHERE只过滤中间表的记录。

总结
连接查询是SQL查询的核心,连接查询的连接类型选择依据实际需求。如果选择不当,非但不能提高查询效率,反而会带来一些逻辑错误或者性能低下。下面总结一下两表连接查询选择方式的依据:
1、 查两表关联列相等的数据用内连接。
2、 Col_L是Col_R的子集时用右外连接。
3、 Col_R是Col_L的子集时用左外连接。
4、 Col_R和Col_L彼此有交集但彼此互不为子集时候用全外。

多个表查询的时候,这些不同的连接类型可以写到一块。例如:
SELECT T1.C1,T2.CX,T3.CY
FROM TAB1 T1
INNER JOIN TAB2 T2 ON (T1.C1=T2.C2)
INNER JOIN TAB3 T3 ON (T1.C1=T2.C3)
LEFT OUTER JOIN TAB4 ON(T2.C2=T3.C3);
WHERE T1.X >T3.Y;
上面这个SQL查询是多表连接的一个示范。

5.操作符下的左右连接

对于外连接, 也可以使用“(+) ”来表示。 关于使用(+)的一些注意事项:
       1.+)操作符只能出现在where子句中,并且不能与outer join语法同时使用。
       2. 当使用(+)操作符执行外连接时,如果在where子句中包含有多个条件,则必须在所有条件中都包含(+)操作符
       3.+)操作符只适用于列,而不能用在表达式上。
       4.+)操作符不能与orin操作符一起使用。
       5.+)操作符只能用于实现左外连接和右外连接

左连接

用(+)来实现, 这个+号可以这样来理解:表示补充,即哪个表有加号,这个表就是匹配表。所以加号写在右表,左表就是全部显示,故是左连接。

SQL> Select * from dave a,bl b where a.id=b.id(+);    -- 注意: 用(+) 就要用关键字where

右连接

用(+)来实现, 这个+号可以这样来理解:表示补充,即哪个表有加号,这个表就是匹配表。所以加号写在左表,右表就是全部显示,故是右连接。

SQL> Select * from dave a,bl b where a.id(+)=b.id;

6.Onwhere的区别

数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户。 
     在使用left jion时,onwhere条件的区别如下:

1on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录。

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

      假设有两张表:

1tab2 id size 
1 10 
2 20 
3 30 
2tab2 size name 
10 AAA 
20 BBB 
20 CCC

两条SQL:
1select * form tab1 left join tab2 on (tab1.size = tab2.size) where tab2.name=’AAA’
2select * form tab1 left join tab2 on (tab1.size = tab2.sizeand tab2.name=’AAA’)

第一条SQL的过程:

1、中间表
on条件
tab1.size = tab2.size  tab1.id tab1.size tab2.size tab2.name 
1 10 10 AAA 
2 20 20 BBB 
2 20 20 CCC 
3 30 (null) (null) 
 
| |  
2、再对中间表过滤
where 条件:
tab2.name=’AAA’ 
 tab1.id tab1.size tab2.size tab2.name 
1 10 10 AAA 
 

第二条SQL的过程:

1、中间表
on条件
tab1.size = tab2.size and tab2.name=’AAA’
(条件不为真也会返回左表中的记录) tab1.id tab1.size tab2.size tab2.name 
1 10 10 AAA 
2 20 (null) (null) 
3 30 (null) (null) 
 

     其实以上结果的关键原因就是left join,right join,full join的特殊性,不管on上的条件是否为真都会返回leftright表中的记录,full则具有leftright的特性的并集。inner jion没这个特殊性,则条件放在on中和where中,返回的结果集是相同的。

外链接匹配,内连接过滤,外链接即匹配又过滤用onwhere搭配

7.图解SQL的内连接与外连接

内外连接就相当于多个业务表的一次合体,连接的条件必须是关键性的!连接成功就可看成一张表!

 

oracleSQL语句常用的连接有内连接(inner join),外连接(outer join)等,内连接又包括等值连接,非等值连接,自连接;而外连接又分为左连接和右连接。其中默认的是内连接的等值连接。

为了方便我们创建两张最简易的表AB,具体的表结构参看下面,来分析内连接与外连接的区别

一对多关系,A(主表),B(子表),表的一条记录对应子表的多条记录

                             

            图1                                                                                                               2

两个表要做连接,必须要有连接字段,而在表A和表B中连接字段是AidBnamid,下图说明了连接之间关系图3

 

                           图3

(1) 内连接:利用内连接(等值)就可获取蓝色的公共部分C,即图3中的数据集C,结果集为如下:

只显示主表与子表有关联的记录,一个主表记录可能有多个子表记录(即在生成的中间表中,主表数据一般重复出现,所以查询出来的记录数根据每个主表记录有多少个子表记录而定,下同)

 

                       图4

其实select * from A join B on A.Aid=B.Bnamid;等价于select * from A,B where A.Aid=B.Bnamid;
注:非等值连接主要的话是针对一个范围来查询数据,自连接主要就是把1张表堪称两张表来用


(2)外连接:分为左外连接(left join)与右外连接(right join

左外连接即公共显示的蓝色部分C1+显示黄色的记录集A1,显示语句等价于select * from A,B where A.Aid=B.Bnamid+);

 不但显示主表与子表有关联的记录,还显示主表与子表没有关联的主表记录


                            图 5

右外连接即公共显示的蓝色部分C1+显示绿色的B1,显示语句等价于select * from A,B where A.Aid(+)=B.Bnamid

显示子表在主表有关联的记录,还显示子表与主表没有关联的子表记录


                           图6

A和表B情况是相对的,以上实验都是A在左边的情况,其实A left join BB right join A的情况的结果集是一样的。

两表之间,只要有关联,不管以什么关系存在,都可能有对方关联或被关联不到的数据,这就是区分内外连接的关键,数据的展示以关联的一方为准,被关联的可能重复被关联

以哪个表为准,就显示这个表的全部信息,抛去另一个表独有的部分

这是仅仅的技术层面,至于要以哪个表为准,要看业务逻辑的需要,哪个表的独有部分是我们更想要的,这时候,表之间的对应关系才更重要点,这是业务问题

利用关键性的数据库字段连接,才能更好地关联

8.SQL何时使用内外连接

所谓内外连接,就是表与表有条件的拼接,内连接是连接条件所列字段,(比如a.recorder = b.userid中的recorderuserid)有值且满足表达式的记录才拼接成功并显示,外链接的左外链接,连接条件是给右表说的,连接表达式成立的记录与左表拼接,不成立的行不显示,不管拼接表达式是否成立,左表照常显示,

连接条件不受限制,并不是必须有主表,也可以是和主表连接的其他表组成连接条件

需要查找两张表同时存在的数据,使用内连接,需要查找两张表中一张表存在,另一张表不存在的时候使用外连接。

SELECT T1.C1,T2.CX,T3.* --如果没有要求特别显示哪个字段,则所有表的字段都显示
FROM TAB1 T1
INNER JOIN TAB2 T2 ON (T1.C1=T2.C2)
LEFT  JOIN TAB3 T3 ON (T1.C1=T2.C3)--不管和哪个表组成连接条件,只要表达式成立的记录,才能和主表拼接并显示。

LEFT  JOIN TAB4 T4 ON(T3.C2=T4.C3);

比如有tableA tableBtableAtableB是一对多

需求:根据tableB的某写字段,查询出tableA

分析:如果此时使用内链接 则相应的语句是:

select a.* from tableA a ,tableB b  where a.id =tableB.aid and b.code='4401'

此时返回的结果是tableAtableB有子数据的部分数据,而如果表tableA中的某条数据,在表tableB中不存在子数据,此时是查询不出来!

 如果使用的是外连接,则相应的语句如下:

select a.* from tableA a  left join tableB b on a.id=b.aid and b.code='4401';

                 此时返回的结果是tableA中的全部数据,而且有重复数出现,则应该用distinct过滤,语句如下:

select distinct a.* from tableA a  left join tableB b on a.id=b.aid and b.code='4401';

内联接查询可以连接两个或两个以上的表,参与内联接的表的地位是平等的,

而外联接中参与联接的表有主从之分.以主表的每行数据去匹配从表的数据列,符合条件的数据将直接返回到结果集中,不符合的用NULL(空值)填充后再返回到结果集中.  

介绍2 

内连接的查询结果都是满足连接条件的元组。但有时我们也希望输出那些不满足连接条件的元组信息。比如, 

有学生表与选课表

我们想知道每个学生的选课情况(每个学生有唯一的学号),包括已经选课的学生(这部分学生的学号在学生表中有,在选课表中也有,是满足连接条件的),也包括没有选课的学生(这部分学生的学号在学生表中有,但在选课表中没有,不满足连接条件),这时就需要使用外连接。外连接是只限制一张表中的数据必须满足连接条件,而另一张表中的数据可以不满足连接条件的连接方式。3种外连接:

1)左外连接(LEFTOUTER JOIN

如果在连接查询中,连接管子左端的表中所有的元组都列出来,并且能在右端的表中找到匹配的元组,那么连接成功。如果在右端的表中,没能找到匹配的元组,那么对应的元组是空值(NULL)。这时,查询语句使用关键字LEFT OUTERJOIN,也就是说,左外连接的含义是限制连接关键字右端的表中的数据必须满足连接条件,而不关左端的表中的数据是否满足连接条件,均输出左端表中的内容。

例如:要查询所有学生的选课情况,包括已经选课的和还没有选课的学生,查询语句为

SELECT学生表.学号,姓名,班级,课程号,成绩

FROM学生表LEFT OUTER JOIN选课表ON学生表.学号=选课表.学号

左外连接查询中左端表中的所有元组的信息都得到了保留。

2)右外连接(RIGHTOUTERJOIN

右外连接与左外连接类似,只是右端表中的所有元组都列出,限制左端表的数据必须满足连接条件,而不管右端表中的数据是否满足连接条件,均输出表中的内容。

例如:同上例内容,查询语句为

SELECT学生表.学号,姓名,班级,课程号,成绩

FROM学生表RIGHTOUTERJOIN选课表ON学生表.学号=选课表.学号

右外连接查询中右端表中的所有元组的信息都得到了保留。 

3)全外连接(FULL OUTER JOIN

全外连接查询的特点是左、右两端表中的元组都输出,如果没能找到匹配的元组,就使用NULL来代替。

例如:同左外连接例子内容,查询语句为

SELECT学生表.学号,姓名,班级,课程号,成绩

FROM学生表FULL OUTER JOIN选课表ON学生表.学号=选课表.学号

全外连接查询中所有表中的元组信息都得到了保留。

答案

你首先是要搞清楚外连接和内连接的概念之后就很容易进行判断了,你要将两个表匹配的记录都选取出来那么就是内连接, 你要将除了两表匹配之外还需要其中某一个表不匹配的记录,那么就用外连接,是左还是右取决于那个表是放在左边还是右边。

简单说就是以谁为准就用谁!以左数据为准去找满足条件的右数据,就用左外连;以右数据为准去找满足条件的左数据,就用右外连;

内连接:取的两个表的(有能连接的字段),的交集,即字段相同的。利用内连接可获取两表的公共部分的记录

左外连接 就是以A表学生数据为准,去找B表内容或合并出另一个内容。

 

 转载地址 https://blog.csdn.net/qq877507054/article/details/52328017

 

猜你喜欢

转载自blog.csdn.net/qq_21508727/article/details/79824455