MySQL多表连接查询
连接(join):将一张表中的行按照某个条件(连接条件)和另一张表中的行连接起来形成一个新行的过程。
根据连接查询返回的结果,分3类:
内连接(inner join)
外连接(outer join)
交叉连接(cross join)
根据连接条件所使用的操作符,分2类:
相等连接(使用等号操作符)
不等连接(不使用等号操作符)
标准的连接语法:
注意:
在连接查询中,一个列可能出现在多张表中,为了避免引起歧义,通常在列名前面加上表名或表别名作为前缀(例:s.sid、x.sid)—使用表别名作为前缀,可以使得SQL代码较短,使用的内存更少(例:stu s,xuanke as x)。
搭建环境:模拟选课
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
<span style="font-size: 16px;">mysql> <span style="color: rgba(0, 0, 255, 1);">select</span> * <span style="color: rgba(0, 0, 255, 1);">from</span><span style="color: rgba(0, 0, 0, 1);"> stu; </span>+------+--------+---------+ | sid | sname | sphonum | +------+--------+---------+ | <span style="color: rgba(128, 0, 128, 1);">1</span> | 张三 | <span style="color: rgba(128, 0, 128, 1);">110</span> | | <span style="color: rgba(128, 0, 128, 1);">2</span> | 李四 | <span style="color: rgba(128, 0, 128, 1);">120</span> | | <span style="color: rgba(128, 0, 128, 1);">3</span> | 王五 | <span style="color: rgba(128, 0, 128, 1);">130</span> | +------+--------+---------+ <span style="color: rgba(128, 0, 128, 1);">3</span> rows <span style="color: rgba(0, 0, 255, 1);">in</span> <span style="color: rgba(0, 0, 255, 1);">set</span> (<span style="color: rgba(128, 0, 128, 1);">0.00</span><span style="color: rgba(0, 0, 0, 1);"> sec) mysql</span>> <span style="color: rgba(0, 0, 255, 1);">select</span> * <span style="color: rgba(0, 0, 255, 1);">from</span><span style="color: rgba(0, 0, 0, 1);"> tea; </span>+------+-----------+---------+ | tid | tname | tphonum | +------+-----------+---------+ | <span style="color: rgba(128, 0, 128, 1);">1113</span> | 相老师 | <span style="color: rgba(128, 0, 128, 1);">1111</span> | | <span style="color: rgba(128, 0, 128, 1);">1114</span> | 冯老师 | <span style="color: rgba(128, 0, 128, 1);">1112</span> | +------+-----------+---------+ <span style="color: rgba(128, 0, 128, 1);">2</span> rows <span style="color: rgba(0, 0, 255, 1);">in</span> <span style="color: rgba(0, 0, 255, 1);">set</span> (<span style="color: rgba(128, 0, 128, 1);">0.00</span><span style="color: rgba(0, 0, 0, 1);"> sec) mysql</span>> <span style="color: rgba(0, 0, 255, 1);">select</span> * <span style="color: rgba(0, 0, 255, 1);">from</span><span style="color: rgba(0, 0, 0, 1);"> course; </span>+------+--------+ | cid | cname | +------+--------+ | <span style="color: rgba(128, 0, 128, 1);">1</span> | linux | | <span style="color: rgba(128, 0, 128, 1);">2</span> | mysql | | <span style="color: rgba(128, 0, 128, 1);">3</span> | hadoop | +------+--------+ <span style="color: rgba(128, 0, 128, 1);">3</span> rows <span style="color: rgba(0, 0, 255, 1);">in</span> <span style="color: rgba(0, 0, 255, 1);">set</span> (<span style="color: rgba(128, 0, 128, 1);">0.00</span><span style="color: rgba(0, 0, 0, 1);"> sec) mysql</span>> <span style="color: rgba(0, 0, 255, 1);">select</span> * <span style="color: rgba(0, 0, 255, 1);">from</span><span style="color: rgba(0, 0, 0, 1);"> xuanke; </span>+------+------+------+--------+ | sid | tid | cid | xuefen | +------+------+------+--------+ | <span style="color: rgba(128, 0, 128, 1);">1</span> | <span style="color: rgba(128, 0, 128, 1);">1113</span> | <span style="color: rgba(128, 0, 128, 1);">2</span> | <span style="color: rgba(128, 0, 128, 1);">2</span> | | <span style="color: rgba(128, 0, 128, 1);">1</span> | <span style="color: rgba(128, 0, 128, 1);">1114</span> | <span style="color: rgba(128, 0, 128, 1);">1</span> | <span style="color: rgba(128, 0, 128, 1);">4</span> | | <span style="color: rgba(128, 0, 128, 1);">1</span> | <span style="color: rgba(128, 0, 128, 1);">1113</span> | <span style="color: rgba(128, 0, 128, 1);">3</span> | <span style="color: rgba(128, 0, 128, 1);">6</span> | | <span style="color: rgba(128, 0, 128, 1);">2</span> | <span style="color: rgba(128, 0, 128, 1);">1113</span> | <span style="color: rgba(128, 0, 128, 1);">2</span> | <span style="color: rgba(128, 0, 128, 1);">2</span> | | <span style="color: rgba(128, 0, 128, 1);">2</span> | <span style="color: rgba(128, 0, 128, 1);">1114</span> | <span style="color: rgba(128, 0, 128, 1);">1</span> | <span style="color: rgba(128, 0, 128, 1);">2</span> | | <span style="color: rgba(128, 0, 128, 1);">2</span> | <span style="color: rgba(128, 0, 128, 1);">1113</span> | <span style="color: rgba(128, 0, 128, 1);">3</span> | <span style="color: rgba(128, 0, 128, 1);">2</span> | +------+------+------+--------+ <span style="color: rgba(128, 0, 128, 1);">6</span> rows <span style="color: rgba(0, 0, 255, 1);">in</span> <span style="color: rgba(0, 0, 255, 1);">set</span> (<span style="color: rgba(128, 0, 128, 1);">0.00</span> sec)</span> |
1、内连接inner join
只返回两张表中所有满足连接条件的行,即使用比较运算符根据每个表中共有的列的值匹配两个表中的行。(inner关键字是可省略的)
①传统的连接写法:
在FROM子句中列出所有要连接的表的名字(进行表别名),以逗号分隔;
连接条件写在WHERE子句中;
注意:一旦给表定义了别名,那么原始的表名就不能在出现在该语句的其它子句中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<span style="font-size: 16px;">mysql> <span style="color: rgba(0, 0, 255, 1);">select</span><span style="color: rgba(0, 0, 0, 1);"> s.sname,c.cname,t.tname,x.xuefen </span>-> <span style="color: rgba(0, 0, 255, 1);">from</span><span style="color: rgba(0, 0, 0, 1);"> stu s,tea t,course c,xuanke x </span>-> <span style="color: rgba(0, 0, 255, 1);">where</span> s.sid=x.sid and t.tid=x.tid and c.cid=<span style="color: rgba(0, 0, 0, 1);">x.cid; </span>+--------+--------+-----------+--------+ | sname | cname | tname | xuefen | +--------+--------+-----------+--------+ | 张三 | linux | <span style="font-family: 宋体;">冯老师</span> | <span style="color: rgba(128, 0, 128, 1);">4</span> | | 李四 | linux | 冯老师 | <span style="color: rgba(128, 0, 128, 1);">2</span> | | 张三 | mysql | 相老师 | <span style="color: rgba(128, 0, 128, 1);">2</span> | | 李四 | mysql | 相老师 | <span style="color: rgba(128, 0, 128, 1);">2</span> | | 张三 | hadoop | 相老师 | <span style="color: rgba(128, 0, 128, 1);">6</span> | | 李四 | hadoop | 相老师 | <span style="color: rgba(128, 0, 128, 1);">2</span> | +--------+--------+-----------+--------+ <span style="color: rgba(128, 0, 128, 1);">6</span> rows <span style="color: rgba(0, 0, 255, 1);">in</span> <span style="color: rgba(0, 0, 255, 1);">set</span> (<span style="color: rgba(128, 0, 128, 1);">0.08</span> sec)</span> |
②使用on子句(常用):笔者比较喜欢的方法,因为觉得结构清晰明了。
1 2 3 4 5 6 7 8 9 10 |
<span style="font-size: 16px;">mysql> <span style="color: rgba(0, 0, 255, 1);">select</span><span style="color: rgba(0, 0, 0, 1);"> s.sname,t.tname,c.cname,x.xuefen </span>-> <span style="color: rgba(0, 0, 255, 1);">from</span><span style="color: rgba(0, 0, 0, 1);"> stu s </span>-><span style="color: rgba(0, 0, 0, 1);"> join xuanke x </span>-> on s.sid=<span style="color: rgba(0, 0, 0, 1);">x.sid </span>-><span style="color: rgba(0, 0, 0, 1);"> join tea t </span>-> on x.tid=<span style="color: rgba(0, 0, 0, 1);">t.tid </span>-><span style="color: rgba(0, 0, 0, 1);"> join course c </span> -> on c.cid=<span style="color: rgba(0, 0, 0, 1);">x.cid; <span style="font-family: 'Microsoft YaHei'; color: rgba(255, 0, 0, 1);">结果如上……</span></span></span> |
表之间的关系以JOIN指定,ON的条件与WHERE条件相同。
③使用using子句
1 2 3 4 5 6 7 8 9 10 |
<span style="font-size: 16px;">mysql> <span style="color: rgba(0, 0, 255, 1);">select</span><span style="color: rgba(0, 0, 0, 1);"> s.sname,t.tname,c.cname,x.xuefen </span>-> <span style="color: rgba(0, 0, 255, 1);">from</span><span style="color: rgba(0, 0, 0, 1);"> stu s </span>-><span style="color: rgba(0, 0, 0, 1);"> join xuanke x </span>-> <span style="color: rgba(0, 0, 255, 1);">using</span><span style="color: rgba(0, 0, 0, 1);">(sid) </span>-><span style="color: rgba(0, 0, 0, 1);"> join tea t </span>-> <span style="color: rgba(0, 0, 255, 1);">using</span><span style="color: rgba(0, 0, 0, 1);">(tid) </span>-><span style="color: rgba(0, 0, 0, 1);"> join course c </span>-> <span style="color: rgba(0, 0, 255, 1);">using</span>(cid);</span> <span style="font-size: 16px; font-family: 'Microsoft YaHei'; color: rgba(255, 0, 0, 1);"> 结果如上……</span> |
表之间的关系以join指定,using(连接列)进行连接匹配,类似于on。(相对用的会比较少)
2、外连接outer join
使用外连接不但返回符合连接和查询条件的数据行,还返回不符合条件的一些行。
在MySQL数据库中外连接分两类(不支持全外连接):
左外连接、右外连接。(outer关键字可省略)。
共同点:都返回符合连接条件和查询条件(即:内连接)的数据行
不同点:
①左外连接还返回左表中不符合连接条件,但符合查询条件的数据行。(所谓左表,就是写在left join关键字左边的表)
②右外连接还返回右表中不符合连接条件,但符合查询条件的数据行。(所谓右表,就是写在right join关键字右边的表)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<span style="font-size: 16px;">mysql> <span style="color: rgba(0, 0, 255, 1);">select</span><span style="color: rgba(0, 0, 0, 1);"> s.sname,x.xuefen </span>-> <span style="color: rgba(0, 0, 255, 1);">from</span><span style="color: rgba(0, 0, 0, 1);"> stu s </span>-><span style="color: rgba(0, 0, 0, 1);"> left join xuanke x </span>-> on s.sid=<span style="color: rgba(0, 0, 0, 1);">x.sid; </span>+--------+--------+ | sname | xuefen | +--------+--------+ | 张三 | <span style="color: rgba(128, 0, 128, 1);">2</span> | | 张三 | <span style="color: rgba(128, 0, 128, 1);">4</span> | | 张三 | <span style="color: rgba(128, 0, 128, 1);">6</span> | | 李四 | <span style="color: rgba(128, 0, 128, 1);">2</span> | | 李四 | <span style="color: rgba(128, 0, 128, 1);">2</span> | | 李四 | <span style="color: rgba(128, 0, 128, 1);">2</span> | | 王五 | NULL | +--------+--------+ <span style="color: rgba(128, 0, 128, 1);">7</span> rows <span style="color: rgba(0, 0, 255, 1);">in</span> <span style="color: rgba(0, 0, 255, 1);">set</span> (<span style="color: rgba(128, 0, 128, 1);">0.00</span> sec)</span> |
解析:stu表是左表,xuanke表是右表:left join是左连接,stu表中”王五”没有选课,在xueke表中没有数据行,不符合连接条件,返回符合查询条件的数据行,所以xuefen为null。
1 2 3 4 5 6 |
<span style="font-size: 16px;">mysql> <span style="color: rgba(0, 0, 255, 1);">select</span><span style="color: rgba(0, 0, 0, 1);"> s.sname,x.xuefen </span>-> <span style="color: rgba(0, 0, 255, 1);">from</span><span style="color: rgba(0, 0, 0, 1);"> xuanke x </span>-><span style="color: rgba(0, 0, 0, 1);"> right join stu s </span> -> on x.sid=<span style="color: rgba(0, 0, 0, 1);">s.sid; <span style="font-family: 'Microsoft YaHei';">结果如上(<span style="color: rgba(255, 0, 0, 1); font-family: 'Microsoft YaHei';">用的是右连接的方式</span>)</span></span></span> |
给连接查询附加条件:
1、写在WHERE子句中
2、使用AND和连接条件写在一起
!!!但是:
对于内连接,两种写法结果相同;
对于外连接,两种写法结果不同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<span style="font-size: 16px;">mysql> <span style="color: rgba(0, 0, 255, 1);">select</span><span style="color: rgba(0, 0, 0, 1);"> s.sname,x.xuefen </span>-> <span style="color: rgba(0, 0, 255, 1);">from</span><span style="color: rgba(0, 0, 0, 1);"> <span style="font-size: 16px;"><span style="color: rgba(0, 0, 0, 1);">stu s</span></span> </span>-><span style="color: rgba(0, 0, 0, 1);"> left join <span style="font-size: 16px;"><span style="color: rgba(0, 0, 0, 1);">xuanke x</span></span> </span>-> on x.sid=<span style="color: rgba(0, 0, 0, 1);">s.sid </span>-> <span style="color: rgba(0, 0, 255, 1);">where</span> sname=<span style="color: rgba(128, 0, 0, 1);">'</span><span style="color: rgba(128, 0, 0, 1);">张三</span><span style="color: rgba(128, 0, 0, 1);">'</span><span style="color: rgba(0, 0, 0, 1);">; </span>+--------+--------+ | sname | xuefen | +--------+--------+ | 张三 | <span style="color: rgba(128, 0, 128, 1);">2</span> | | 张三 | <span style="color: rgba(128, 0, 128, 1);">4</span> | | 张三 | <span style="color: rgba(128, 0, 128, 1);">6</span> | +--------+--------+ <span style="color: rgba(128, 0, 128, 1);">3</span> rows <span style="color: rgba(0, 0, 255, 1);">in</span> <span style="color: rgba(0, 0, 255, 1);">set</span> (<span style="color: rgba(128, 0, 128, 1);">0.01</span><span style="color: rgba(0, 0, 0, 1);"> sec) mysql</span>> <span style="color: rgba(0, 0, 255, 1);">select</span><span style="color: rgba(0, 0, 0, 1);"> s.sname,x.xuefen </span>-> <span style="color: rgba(0, 0, 255, 1);">from</span><span style="color: rgba(0, 0, 0, 1);"> (select * from <span style="font-size: 16px;"><span style="color: rgba(0, 0, 0, 1);"><span style="font-size: 16px;"><span style="color: rgba(0, 0, 0, 1);">stu</span></span></span></span> where <span style="font-size: 16px;">sname=<span style="color: rgba(128, 0, 0, 1);">'<span style="color: rgba(128, 0, 0, 1);">张三<span style="color: rgba(128, 0, 0, 1);">'</span></span></span></span>)<span style="font-size: 16px;"><span style="color: rgba(0, 0, 0, 1);"> s</span></span> </span>-><span style="color: rgba(0, 0, 0, 1);"> left join <span style="font-size: 16px;"><span style="color: rgba(0, 0, 0, 1);">xuanke x</span></span> </span>-> on x.sid=<span style="color: rgba(0, 0, 0, 1);">s.sid</span><span style="color: rgba(0, 0, 0, 1);">; </span>+--------+--------+ | sname | xuefen | +--------+--------+ | 张三 | <span style="color: rgba(128, 0, 128, 1);">2</span> | | 张三 | <span style="color: rgba(128, 0, 128, 1);">4</span> | | 张三 | <span style="color: rgba(128, 0, 128, 1);">6</span> | +--------+--------+ <span style="color: rgba(128, 0, 128, 1);">3</span> rows <span style="color: rgba(0, 0, 255, 1);">in</span> <span style="color: rgba(0, 0, 255, 1);">set</span> (<span style="color: rgba(128, 0, 128, 1);">0.00</span> sec)</span> |
①先连接后过滤
select ……from ……
left join ……
on 连接条件
where 过滤条件;
②先过滤后连接
select ……from (select ……from ……where 过滤条件)
left join ……
on 连接条件;
3、交叉连接—笛卡尔积
因为没有连接条件,所进行的表与表间的所有行的连接。
特点:
①连接查询没有写任何连接条件
②结果集中的总行数就是两张表中总行数的乘积(笛卡尔积)
注意:在实际中,应该要避免产生笛卡尔积的连接,特别是对于大表
1 2 3 4 |
<span style="font-size: 16px;">mysql> <span style="color: rgba(0, 0, 255, 1);">select</span> * <span style="color: rgba(0, 0, 255, 1);">from</span><span style="color: rgba(0, 0, 0, 1);"> stu,tea,course,xuanke; …… …… </span><span style="color: rgba(128, 0, 128, 1);">108</span> rows <span style="color: rgba(0, 0, 255, 1);">in</span> <span style="color: rgba(0, 0, 255, 1);">set</span> (<span style="color: rgba(128, 0, 128, 1);">0.00</span> sec)</span> |
若是想专门产生笛卡尔积,可以使用交叉连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<span style="font-size: 16px;">mysql> <span style="color: rgba(0, 0, 255, 1);">select</span> * -> <span style="color: rgba(0, 0, 255, 1);">from</span><span style="color: rgba(0, 0, 0, 1);"> stu </span>-><span style="color: rgba(0, 0, 0, 1);"> crosss join tea; </span>+------+--------+---------+------+-----------+---------+ | sid | sname | sphonum | tid | tname | tphonum | +------+--------+---------+------+-----------+---------+ | <span style="color: rgba(128, 0, 128, 1);">1</span> | 张三 | <span style="color: rgba(128, 0, 128, 1);">110</span> | <span style="color: rgba(128, 0, 128, 1);">1113</span> | 相老师 | <span style="color: rgba(128, 0, 128, 1);">1111</span> | | <span style="color: rgba(128, 0, 128, 1);">1</span> | 张三 | <span style="color: rgba(128, 0, 128, 1);">110</span> | <span style="color: rgba(128, 0, 128, 1);">1114</span> | 冯老师 | <span style="color: rgba(128, 0, 128, 1);">1112</span> | | <span style="color: rgba(128, 0, 128, 1);">2</span> | 李四 | <span style="color: rgba(128, 0, 128, 1);">120</span> | <span style="color: rgba(128, 0, 128, 1);">1113</span> | 相老师 | <span style="color: rgba(128, 0, 128, 1);">1111</span> | | <span style="color: rgba(128, 0, 128, 1);">2</span> | 李四 | <span style="color: rgba(128, 0, 128, 1);">120</span> | <span style="color: rgba(128, 0, 128, 1);">1114</span> | 冯老师 | <span style="color: rgba(128, 0, 128, 1);">1112</span> | | <span style="color: rgba(128, 0, 128, 1);">3</span> | 王五 | <span style="color: rgba(128, 0, 128, 1);">130</span> | <span style="color: rgba(128, 0, 128, 1);">1113</span> | 相老师 | <span style="color: rgba(128, 0, 128, 1);">1111</span> | | <span style="color: rgba(128, 0, 128, 1);">3</span> | 王五 | <span style="color: rgba(128, 0, 128, 1);">130</span> | <span style="color: rgba(128, 0, 128, 1);">1114</span> | 冯老师 | <span style="color: rgba(128, 0, 128, 1);">1112</span> | +------+--------+---------+------+-----------+---------+ <span style="color: rgba(128, 0, 128, 1);">6</span> rows <span style="color: rgba(0, 0, 255, 1);">in</span> <span style="color: rgba(0, 0, 255, 1);">set</span> (<span style="color: rgba(128, 0, 128, 1);">0.00</span> sec)<span style="font-family: 'Microsoft YaHei'; line-height: 1.5; background-color: rgba(255, 255, 255, 1);"> </span></span> |