10.1显示多个表的记录

10.1.1合并表多个表中的数据

  1. 我们可以使用union从多个表中提取记录,并将它们合并起来,但要注意合并后的列数要相同<br /> ** 语法:**

select 列名 from 表名 union select 列名 from 表名

   **  示列**:合并表t1(今年客户表)和tb2(往年客户表)
mysql> select* from tb2
    -> union
    -> select* from tb;
+-------+------+------+
| empid | name | age  |
+-------+------+------+
| A106  | 中村 |   26 |
| A107  | 田中 |   24 |
| A108  | 铃木 |   23 |
| A109  | 村井 |   25 |
| A110  | 吉田 |   27 |
| A103  | 101  |    4 |
| A104  | 181  |    5 |
| A101  | 184  |    4 |
| A103  | 17   |    5 |
| A101  | 300  |    5 |
| A102  | 205  |    6 |
| A104  | 93   |    5 |
| A103  | 12   |    6 |
| A107  | 87   |    6 |
+-------+------+------+
14 rows in set (0.00 sec)
  既是数据类型不同,mysql也会对其合并。但要保证合并玩的列数相同<br />**示列:**
mysql> desc tb3;
+--------+--------------+------+-----+---------+-------+
| Field  | Type         | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| empid  | varchar(10)  | YES  |     | NULL    |       |
| region | varchar(100) | YES  |     | NULL    |       |
+--------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> desc tb1;
+-------+-------------+------+-----+------------+-------+
| Field | Type        | Null | Key | Default    | Extra |
+-------+-------------+------+-----+------------+-------+
| empid | varchar(10) | YES  |     | NULL       |       |
| name  | varchar(10) | YES  |     | 未输入名字 |       |
| age   | int(11)     | YES  |     | NULL       |       |
+-------+-------------+------+-----+------------+-------+
3 rows in set (0.00 sec)

mysql> select region from tb3
    -> union
    -> select  name from tb1;
+------------+
| region     |
+------------+
| 东京都     |
| 琦玉县     |
| 神奈川县   |
| 北海县     |
| 静岗县     |
| 佐藤       |
| 高桥       |
| 中川       |
| 渡边       |
| 西泽       |
| 未输入名字 |
+------------+
11 rows in set (0.00 sec)

示列二:使用union合并三个表以上的数据

mysql> select *from tb1
    -> union
    -> select * from tb
    -> union
    -> select * from tb2;
+-------+------------+------+
| empid | name       | age  |
+-------+------------+------+
| A101  | 佐藤       |   40 |
| A102  | 高桥       |   28 |
| A103  | 中川       |   20 |
| A104  | 渡边       |   23 |
| A105  | 西泽       |   35 |
| N110  | 未输入名字 |   25 |
| A103  | 101        |    4 |
| A104  | 181        |    5 |
| A101  | 184        |    4 |
| A103  | 17         |    5 |
| A101  | 300        |    5 |
| A102  | 205        |    6 |
| A104  | 93         |    5 |
| A103  | 12         |    6 |
| A107  | 87         |    6 |
| A106  | 中村       |   26 |
| A107  | 田中       |   24 |
| A108  | 铃木       |   23 |
| A109  | 村井       |   25 |
| A110  | 吉田       |   27 |
+-------+------------+------+
20 rows in set (0.00 sec)

10.1.2按条件合并多条结果并显示

 当使用union合并提取的多条记录时,如果需要添加条件可以在各个命令最后加上where条件<br />   示列:<br />        ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12862216/1622520601327-5d23b60c-ad99-45ed-8c4c-9ba7509816b2.png#clientId=u4fd030f0-f10d-4&from=paste&height=69&id=ua98a5ea5&margin=%5Bobject%20Object%5D&name=image.png&originHeight=137&originWidth=1114&originalType=binary&size=151551&status=done&style=none&taskId=ub1347a31-8b4a-4ada-96be-cfba90945bc&width=557)
mysql> select * from tb;
+-------+-------+-------+
| empid | sales | month |
+-------+-------+-------+
| A103  |   101 |     4 |
| A103  |   101 |     4 |
| A104  |   181 |     5 |
| A101  |   184 |     4 |
| A103  |    17 |     5 |
| A101  |   300 |     5 |
| A102  |   205 |     6 |
| A104  |    93 |     5 |
| A103  |    12 |     6 |
| A107  |    87 |     6 |
+-------+-------+-------+
10 rows in set (0.00 sec)
mysql> select * from tb1;
+-------+------------+------+
| empid | name       | age  |
+-------+------------+------+
| A101  | 佐藤       |   40 |
| A102  | 高桥       |   28 |
| A103  | 中川       |   20 |
| A104  | 渡边       |   23 |
| A105  | 西泽       |   35 |
| N110  | 未输入名字 |   25 |
+-------+------------+------+
6 rows in set (0.00 sec)
mysql> select empid from tb where sales>=200
    -> union
    -> select empid from tb1 where age>=35;
+-------+
| empid |
+-------+
| A101  |
| A102  |
| A105  |
+-------+
3 rows in set (0.00 sec)

10.1.3合并显示多态提取结果(运行重复)
在使用union合并结果时,会执行消除重复记录的操作,但是我们可以通过给union加上all来省去消除重复的操作
示列:
在上述示列中符合①条件的tb表中有两个A101,但是在合并的时候消除了,通过All让其展示出来

mysql> select empid from tb where sales>=200
    -> union all
    -> select empid from tb1 where age>=35;
+-------+
| empid |
+-------+
| A101  |
| A102  |
| A101  |
| A105  |
+-------+
4 rows in set (0.00 sec)
mysql>

10.2连接多个表并显示(内连接)

10.2.1使用其他表的记录进行处理

     将多个表通过某个连接键连接在一起的处理称为“连接”,通常我们使用join来连接两个表。**而这种方法只会提取连接键想匹配的记录。**<br />  ** 语法:**

select 列名 from 表1 join 要连接的表2 on 表1的列=表2的列

语法详解:image.png
示列一:通过tb表和tb1的empid 列将两个表连接起来

/*表tb的内容*/
+-------+-------+-------+   
| empid | sales | month |
+-------+-------+-------+
| A103  |   101 |     4 |          
| A103  |   101 |     4 |
| A104  |   181 |     5 |
| A101  |   184 |     4 |
| A103  |    17 |     5 |
| A101  |   300 |     5 |
| A102  |   205 |     6 |
| A104  |    93 |     5 |
| A103  |    12 |     6 |
| A107  |    87 |     6 |
+-------+-------+-------+
/*表tb1的内容*/
+-------+------+------+
| empid | name | age  |
+-------+------+------+
| A101  | 佐藤 |   40 |
| A102  | 高桥 |   28 |
| A103  | 中川 |   20 |
| A104  | 渡边 |   23 |
| A105  | 西泽 |   35 |
+-------+------+------+
mysql> select * from tb join tb1 on tb.empid=tb1.empid;
+-------+-------+-------+-------+------+------+
| empid | sales | month | empid | name | age  |
+-------+-------+-------+-------+------+------+
| A103  |   101 |     4 | A103  | 中川 |   20 |
| A103  |   101 |     4 | A103  | 中川 |   20 |
| A104  |   181 |     5 | A104  | 渡边 |   23 |
| A101  |   184 |     4 | A101  | 佐藤 |   40 |
| A103  |    17 |     5 | A103  | 中川 |   20 |
| A101  |   300 |     5 | A101  | 佐藤 |   40 |
| A102  |   205 |     6 | A102  | 高桥 |   28 |
| A104  |    93 |     5 | A104  | 渡边 |   23 |
| A103  |    12 |     6 | A103  | 中川 |   20 |
+-------+-------+-------+-------+------+------+
9 rows in set (0.00 sec)
/*因为tb表中的A107在tb1表中没有对应的记录所以没有A107*/

内连接:
想上述示列中,把不同的相匹配的记录提取出来的连接方式称为内连接。如果要明确的指出某一处理是内连接,可将join部分写成inner
列如:select from tb inner join tb1 on tb.empid=tb1.empid;结果不会发生任何变化
同时,*使用join 或者 inner join 的内连接只会提取与连接键相匹配的记录(内连接的特征)

10.2.2选择列进行显示

在上述的示列中我们把两个表全部的列提取出来。同样,我们也可以选择自己想要的列来提取,我们的列别名在这种情况下也适用。而我们只需要把 列名—>表名.列名 就可以了。列会按照指定的顺序显示。同一个列显示多少次都没关系
示列二重写示列一,只提取想要的列并加上别名

mysql> select tb.empid as 员工号 ,tb1.name as 姓名,tb.sales as 销售额 from tb join tb1 on tb.empid=tb1.empid;
+--------+------+--------+
| 员工号 | 姓名 | 销售额 |
+--------+------+--------+
| A103   | 中川 |    101 |
| A103   | 中川 |    101 |
| A104   | 渡边 |    181 |
| A101   | 佐藤 |    184 |
| A103   | 中川 |     17 |
| A101   | 佐藤 |    300 |
| A102   | 高桥 |    205 |
| A104   | 渡边 |     93 |
| A103   | 中川 |     12 |
+--------+------+--------+
9 rows in set (0.00 sec)

mysql>

10.2.3给表加别名

 我们也可以给表加别名,方法与给列加别名一样。给表加别名后我们在连接表的话就必须要安装别名.列名来操作。<br />** 示列三:通过表别名的方法,提前出tb 表和tb1表中匹配的记录**<br /> 
mysql> select x.empid,y.name,x.sales from tb as x join tb1 as y on x.empid=y.empid;
+-------+------+-------+
| empid | name | sales |
+-------+------+-------+
| A103  | 中川 |   101 |
| A103  | 中川 |   101 |
| A104  | 渡边 |   181 |
| A101  | 佐藤 |   184 |
| A103  | 中川 |    17 |
| A101  | 佐藤 |   300 |
| A102  | 高桥 |   205 |
| A104  | 渡边 |    93 |
| A103  | 中川 |    12 |
+-------+------+-------+
9 rows in set (0.00 sec)

mysql>

10.2.4using使on更容易阅读

在前面的示列中作为连接键的列都是empid,但是列名也可以不相同,值需要在on 后面把对应的列写出了即将可。而如果列相同,我们可以使用using(作为连接键的列名)来代替on 的写法。<br />**示列四:使用using重写示列三**
mysql> select tb.empid,tb1.name,tb.sales from tb join tb1 using(empid);
+-------+------+-------+
| empid | name | sales |
+-------+------+-------+
| A103  | 中川 |   101 |
| A103  | 中川 |   101 |
| A104  | 渡边 |   181 |
| A101  | 佐藤 |   184 |
| A103  | 中川 |    17 |
| A101  | 佐藤 |   300 |
| A102  | 高桥 |   205 |
| A104  | 渡边 |    93 |
| A103  | 中川 |    12 |
+-------+------+-------+
9 rows in set (0.00 sec)

mysql>

10.2.5通多where设置条件从连接表中提前记录

 我们可以将where的条件运用到连接表中提前记录去,只要把where后面的列名写成表名.列名或别名.列名即可<br />** 示列五**:显示销售额大于等于100的员工信息
mysql> select tb.empid,tb1.name,tb.sales from tb join tb1 using(empid) where tb.sales>=100;
+-------+------+-------+
| empid | name | sales |
+-------+------+-------+
| A101  | 佐藤 |   184 |
| A101  | 佐藤 |   300 |
| A102  | 高桥 |   205 |
| A103  | 中川 |   101 |
| A103  | 中川 |   101 |
| A104  | 渡边 |   181 |
+-------+------+-------+
6 rows in set (0.00 sec)

mysql>

10.2.6提取多个表中的记录

我们可以使用join对多个表进行连接,只要在select ..join on..的基础上在加上select ..join on..即可<br /> ** 语法:**<br />  ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12862216/1622532616759-e9b20881-0a88-43c4-a3b8-ee4bd9957365.png#clientId=ubb33a1bd-000b-4&from=paste&height=158&id=u7976ffe0&margin=%5Bobject%20Object%5D&name=image.png&originHeight=316&originWidth=443&originalType=binary&size=125122&status=done&style=none&taskId=ub64293a5-be71-48d7-8ea6-204e7f952d7&width=221.5)<br />示列六:提取每个员工的销售额和姓名和出生地
/*员工初始地表tb3*/
mysql> select * from tb3;
+-------+----------+
| empid | region   |
+-------+----------+
| A101  | 东京都   |
| A102  | 琦玉县   |
| A103  | 神奈川县 |
| A104  | 北海县   |
| A105  | 静岗县   |
+-------+----------+
5 rows in set (0.00 sec)

mysql> select tb.empid,tb1.name,tb3.region from tb join tb1 using(empid)join tb3 using(empid);
+-------+------+----------+
| empid | name | region   |
+-------+------+----------+
| A103  | 中川 | 神奈川县 |
| A103  | 中川 | 神奈川县 |
| A104  | 渡边 | 北海县   |
| A101  | 佐藤 | 东京都   |
| A103  | 中川 | 神奈川县 |
| A101  | 佐藤 | 东京都   |
| A102  | 高桥 | 琦玉县   |
| A104  | 渡边 | 北海县   |
| A103  | 中川 | 神奈川县 |
+-------+------+----------+
9 rows in set (0.00 sec)

mysql>

10.3连接多个表并显示(外连接)

外连接:是其中一个表的记录与其他表的记录不匹配的情况下也会提取出来的连接方法。也就是说既使与连接键不匹配,外连接也会提取另一个表中的所有记录
外连接可以种类:

 **  左表右表:**以join 两边的表分为左边和右表,即在join做边的表为左边又边的为右表

1.左外连接(left join )

               显示左表与右表相匹配(通过左边中的键去匹配左边中对应的键的值)的记录和左表的全部记录<br />**示列一**:使用左外连接显示tb表和tb1表中相匹配的记录,但是只会显示左表中的全部记录<br /> 

mysql> select * from tb;
+-------+-------+-------+
| empid | sales | month |
+-------+-------+-------+
| A103  |   101 |     4 |
| A103  |   101 |     4 |
| A104  |   181 |     5 |
| A101  |   184 |     4 |
| A103  |    17 |     5 |
| A101  |   300 |     5 |
| A102  |   205 |     6 |
| A104  |    93 |     5 |
| A103  |    12 |     6 |
| A107  |    87 |     6 |
+-------+-------+-------+
mysql> select * from tb1;
+-------+------+------+
| empid | name | age  |
+-------+------+------+
| A101  | 佐藤 |   40 |
| A102  | 高桥 |   28 |
| A103  | 中川 |   20 |
| A104  | 渡边 |   23 |
| A105  | 西泽 |   35 |
+-------+------+------+
5 rows in set (0.00 sec)

mysql> select tb.empid,tb1.name from tb left join tb1 using(empid);
+-------+------+
| empid | name |
+-------+------+
| A101  | 佐藤 |
| A101  | 佐藤 |
| A102  | 高桥 |
| A103  | 中川 |
| A103  | 中川 |
| A103  | 中川 |
| A103  | 中川 |
| A104  | 渡边 |
| A104  | 渡边 |
| A107  | NULL |
+-------+------+
10 rows in set (0.00 sec)
/*因为tb1表中没有A107对应的name所以显示为null*/

2.右外连接(right join)

              显示右边与左表相匹配(通过右边中的键去匹配左边中对应的键的值)的记录和右表的全部记录<br />  **示列二**:使用右外连接显示tb表和tb1表想匹配的记录,但是只会显示右边的全部记录
mysql> select tb.empid,tb1.name from tb right join tb1 using(empid);
+-------+------+
| empid | name |
+-------+------+
| A103  | 中川 |
| A103  | 中川 |
| A104  | 渡边 |
| A101  | 佐藤 |
| A103  | 中川 |
| A101  | 佐藤 |
| A102  | 高桥 |
| A104  | 渡边 |
| A103  | 中川 |
| NULL  | 西泽 |
+-------+------+
10 rows in set (0.00 sec)
/*由于tb1表中的A105在tb表中没有记录,所以显示为空*/
mysql>

10.4自连接

 将表与其自神相连接,这种连接方式称为自连接 <br />   语法:

select 列名 from 表名 as 别名1 join 表名 as 别名2

示列:表自连接tb1

mysql> select * from tb1 join tb1 as b;
+-------+------+------+-------+------+------+
| empid | name | age  | empid | name | age  |
+-------+------+------+-------+------+------+
| A101  | 佐藤 |   40 | A101  | 佐藤 |   40 |
| A102  | 高桥 |   28 | A101  | 佐藤 |   40 |
| A103  | 中川 |   20 | A101  | 佐藤 |   40 |
| A104  | 渡边 |   23 | A101  | 佐藤 |   40 |
| A105  | 西泽 |   35 | A101  | 佐藤 |   40 |
| A101  | 佐藤 |   40 | A102  | 高桥 |   28 |
| A102  | 高桥 |   28 | A102  | 高桥 |   28 |
| A103  | 中川 |   20 | A102  | 高桥 |   28 |
| A104  | 渡边 |   23 | A102  | 高桥 |   28 |
| A105  | 西泽 |   35 | A102  | 高桥 |   28 |
| A101  | 佐藤 |   40 | A103  | 中川 |   20 |
| A102  | 高桥 |   28 | A103  | 中川 |   20 |
| A103  | 中川 |   20 | A103  | 中川 |   20 |
| A104  | 渡边 |   23 | A103  | 中川 |   20 |
| A105  | 西泽 |   35 | A103  | 中川 |   20 |
| A101  | 佐藤 |   40 | A104  | 渡边 |   23 |
| A102  | 高桥 |   28 | A104  | 渡边 |   23 |
| A103  | 中川 |   20 | A104  | 渡边 |   23 |
| A104  | 渡边 |   23 | A104  | 渡边 |   23 |
| A105  | 西泽 |   35 | A104  | 渡边 |   23 |
| A101  | 佐藤 |   40 | A105  | 西泽 |   35 |
| A102  | 高桥 |   28 | A105  | 西泽 |   35 |
| A103  | 中川 |   20 | A105  | 西泽 |   35 |
| A104  | 渡边 |   23 | A105  | 西泽 |   35 |
| A105  | 西泽 |   35 | A105  | 西泽 |   35 |
+-------+------+------+-------+------+------+
25 rows in set (0.01 sec)

mysql>

将一个表自连接后,将以这个表自身拥有的所有记录将与自身的所有记录进行连接,所有自连接后一个表的记录数为 记录数的平方。当我们将一个表自连接后可是看到这个表中所有情况的分组。

10.5从select的记录中select(子查询)

10.5.1什么是子查询(第二个select语句)image.png

同时,子查询可以返回值、列和记录等。
示列一:查询tb表中销量最高的员工

mysql> select * from tb where sales in (select max(sales) from tb);
+-------+-------+-------+
| empid | sales | month |
+-------+-------+-------+
| A101  |   300 |     5 |
+-------+-------+-------+
1 row in set (0.01 sec)

示列详解:
1.in后的查询语句就称为子查询,因为要查出销量的最大值,直接使用max(sales)是不行的(只能单独查询出一个最大的sales值)。所以需要先在子查询查出最高的sales的值,通过第二阶段的选择查询出sales最大的员工信息、
2.in的意思是列中包含其中子查询的结果
示列二:查询tb1表中年龄大于平局值的员工信息

mysql> select * from tb1 where age>=(select avg(age) from tb1);
+-------+------+------+
| empid | name | age  |
+-------+------+------+
| A101  | 佐藤 |   40 |
| A105  | 西泽 |   35 |
+-------+------+------+
2 rows in set (0.00 sec)
mysql>

扩展:子查询与内连接提取结果的差异
示列:提前表tb中empid员工号与tb1中相应的员工号empid和姓名name

/*使用子查询*/
mysql> select empid,name from tb1 where empid in(select empid from tb);
+-------+------+
| empid | name |
+-------+------+
| A101  | 佐藤 |
| A102  | 高桥 |
| A103  | 中川 |
| A104  | 渡边 |
+-------+------+
4 rows in set (0.00 sec)
/*使用内连接*/
mysql> select tb.empid,tb1.name from tb1 join tb using(empid) ;
+-------+------+
| empid | name |
+-------+------+
| A103  | 中川 |
| A103  | 中川 |
| A104  | 渡边 |
| A101  | 佐藤 |
| A103  | 中川 |
| A101  | 佐藤 |
| A102  | 高桥 |
| A104  | 渡边 |
| A103  | 中川 |
+-------+------+
9 rows in set (0.00 sec)

我们通过示列发现,两者的结果是不同的,使用子查询时会先查询tb表中的empid,然后仅显示tb1表与查询出来tb表中empid匹配的记录,而内连接会将所有tb中的empid都提取出来

10.5.2使用“=”代替in

   示列:
mysql> select * from tb1 where empid=(select empid from tb where sales>=200);
ERROR 1242 (21000): Subquery returns more than 1 row
mysql>
我们执行上面的语句后发现会报错,这是因为在第一阶段查询出来的是多条的记录,无法用=号去判别,**所有说如果只有一条相对应的记录,可以用=,如果是有多条记录对应,那么就要用in。**

10.5.3使用exists,仅以存在的记录为对象

我们前使用where..in(…)这种子查询。他返回符合第一阶段子查询的结果的列的记录,同样我们也可以使用exists:不返回指定的列而返回子查询中存在的目标记录。
示列一:

mysql> select * from tb1 where exists (select empid from tb1);
+-------+------+------+
| empid | name | age  |
+-------+------+------+
| A101  | 佐藤 |   40 |
| A102  | 高桥 |   28 |
| A103  | 中川 |   20 |
| A104  | 渡边 |   23 |
| A105  | 西泽 |   35 |
+-------+------+------+
5 rows in set (0.00 sec)

mysql> select * from tb;
+-------+-------+-------+
| empid | sales | month |
+-------+-------+-------+
| A103  |   101 |     4 |
| A103  |   101 |     4 |
| A104  |   181 |     5 |
| A101  |   184 |     4 |
| A103  |    17 |     5 |
| A101  |   300 |     5 |
| A102  |   205 |     6 |
| A104  |    93 |     5 |
| A103  |    12 |     6 |
| A107  |    87 |     6 |
+-------+-------+-------+
10 rows in set (0.00 sec)

mysql> select * from tb1 where exists (select * from tb where tb.empid=tb1.empid);
+-------+------+------+
| empid | name | age  |
+-------+------+------+
| A101  | 佐藤 |   40 |
| A102  | 高桥 |   28 |
| A103  | 中川 |   20 |
| A104  | 渡边 |   23 |
+-------+------+------+
4 rows in set (0.00 sec)

由于tb表中没有A105所以没有显示出来

10.5.4NOT exists

  not exists以子查询没有提取的记录为对象进行处理<br />示列:
mysql> select * from tb1 where not exists (select * from tb where tb.empid=tb1.empid);
+-------+------+------+
| empid | name | age  |
+-------+------+------+
| A105  | 西泽 |   35 |
+-------+------+------+
1 row in set (0.00 sec)

因为tb表中没有A105,所以将A105作为对象来提前tb1表中的数据