多表查询
一:表的基本介绍
可以参考:https://www.cnblogs.com/cdf-opensource-007/p/6517627.html 建立一个员工表信息表和一个部门表,每个员工都对应在哪个部门。因此这两张表具有一定关系。需要将两个表格进行查询,找到一个 员工所对应的所属部门。
01:建立一个员工表:employee 和一个部门表departmentemployee表:
mysql> create table employee( -> id int primary key auto_increment, -> name varchar(20), -> sex enum("male","female") not null default "male", -> age int, -> dep_id int -> ); Query OK, 0 rows affected (0.18 sec) department表: mysql> create table department( -> id int, -> name varchar(20) -> ); Query OK, 0 rows affected (0.12 sec)
02:给两张表加入信息。
employee表:
mysql> insert into employee(name,sex,age,dep_id) values -> ("egon","male",18,200), -> ("alex","female",48,201), -> ("wupeiqi","male",38,210), -> ("yuanhao","female",28,202), -> ("liwenzhou","female",28,202), -> ("jingwen","female",18,204); Query OK, 6 rows affected (0.05 sec) Records: 6 Duplicates: 0 Warnings: 0
查看employee的结构:
mysql> desc employee; +--------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------+-----------------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | YES | | NULL | | | sex | enum('male','female') | NO | | male | | | age | int(11) | YES | | NULL | | | dep_id | int(11) | YES | | NULL | | +--------+-----------------------+------+-----+---------+----------------+ 5 rows in set (0.00 sec)
查看employee的信息:
mysql> select * from employee; +----+-----------+--------+------+--------+ | id | name | sex | age | dep_id | +----+-----------+--------+------+--------+ | 1 | egon | male | 18 | 200 | | 2 | alex | female | 48 | 201 | | 3 | wupeiqi | male | 38 | 210 | | 4 | yuanhao | female | 28 | 202 | | 5 | liwenzhou | female | 28 | 202 | | 6 | jingwen | female | 18 | 204 | +----+-----------+--------+------+--------+ 6 rows in set (0.00 sec)
department表:
mysql> insert into department values -> (200,"技术"), -> (201,"人力资源"), -> (202,"销售"), -> (203,"运营"); Query OK, 4 rows affected (0.04 sec) Records: 4 Duplicates: 0 Warnings: 0 department的结构: mysql> desc department; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec)
department的信息:
mysql> select * from department; +------+--------------+ | id | name | +------+--------------+ | 200 | 技术 | | 201 | 人力资源 | | 202 | 销售 | | 203 | 运营 | +------+--------------+ 4 rows in set (0.00 sec)
二:多表查询(以employee和department为例)
#重点:外链接语法: select 字段列表 from 表1 inner/left/right join 表2 on 表1.字段=表2.字段;
01:交叉链接:生成笛卡儿积:
mysql> select * from employee,department; +----+-----------+--------+------+--------+------+--------------+ | id | name | sex | age | dep_id | id | name | +----+-----------+--------+------+--------+------+--------------+ | 1 | egon | male | 18 | 200 | 200 | 技术 | | 1 | egon | male | 18 | 200 | 201 | 人力资源 | | 1 | egon | male | 18 | 200 | 202 | 销售 | | 1 | egon | male | 18 | 200 | 203 | 运营 | | 2 | alex | female | 48 | 201 | 200 | 技术 | | 2 | alex | female | 48 | 201 | 201 | 人力资源 | | 2 | alex | female | 48 | 201 | 202 | 销售 | | 2 | alex | female | 48 | 201 | 203 | 运营 | | 3 | wupeiqi | male | 38 | 210 | 200 | 技术 | | 3 | wupeiqi | male | 38 | 210 | 201 | 人力资源 | | 3 | wupeiqi | male | 38 | 210 | 202 | 销售 | | 3 | wupeiqi | male | 38 | 210 | 203 | 运营 | | 4 | yuanhao | female | 28 | 202 | 200 | 技术 | | 4 | yuanhao | female | 28 | 202 | 201 | 人力资源 | | 4 | yuanhao | female | 28 | 202 | 202 | 销售 | | 4 | yuanhao | female | 28 | 202 | 203 | 运营 | | 5 | liwenzhou | female | 28 | 202 | 200 | 技术 | | 5 | liwenzhou | female | 28 | 202 | 201 | 人力资源 | | 5 | liwenzhou | female | 28 | 202 | 202 | 销售 | | 5 | liwenzhou | female | 28 | 202 | 203 | 运营 | | 6 | jingwen | female | 18 | 204 | 200 | 技术 | | 6 | jingwen | female | 18 | 204 | 201 | 人力资源 | | 6 | jingwen | female | 18 | 204 | 202 | 销售 | | 6 | jingwen | female | 18 | 204 | 203 | 运营 | +----+-----------+--------+------+--------+------+--------------+ 24 rows in set (0.00 sec) 这种显示是将所有列表排序都生成了,我们要找的排序肯定会在这个笛卡儿积表格中,但是不利于分析。
02:内链接,只链接匹配的行。
mysql> select * from employee,department where department.id=employee.dep_id; #where条件分析。 +----+-----------+--------+------+--------+------+--------------+ | id | name | sex | age | dep_id | id | name | +----+-----------+--------+------+--------+------+--------------+ | 1 | egon | male | 18 | 200 | 200 | 技术 | | 2 | alex | female | 48 | 201 | 201 | 人力资源 | | 4 | yuanhao | female | 28 | 202 | 202 | 销售 | | 5 | liwenzhou | female | 28 | 202 | 202 | 销售 | +----+-----------+--------+------+--------+------+--------------+ 4 rows in set (0.00 sec)
#再看一个需求,我要查出技术部的员工的名字
mysql> select name from employee,department where employee.dep_id=department.id and department.name='技术'; ERROR 1052 (23000): Column 'name' in field list is ambiguous #上面直接就报错了,因为select后面直接写的name,在两个表合并起来的表中,是有两个name字段的,直接写name是不行的,要加上表名,再看: mysql> select employee.name from employee,department where employee.dep_id=department.id and department.name="技术"; +------+ | name | +------+ | egon | +------+ 1 row in set (0.00 sec)
03:外链接之左链接:优先显示左边表的全部记录
#以左表为准,即找出所有员工信息,当然包括没有部门的员工 #本质就是:在内链接的基础上增加左边有而右边没有的结果 mysql> select employee.id,employee.name,department.name as depart_name from employee > left join department on employee.dep_id=department.id; +----+-----------+--------------+ | id | name | depart_name | +----+-----------+--------------+ | 1 | egon | 技术 | | 2 | alex | 人力资源 | | 4 | yuanhao | 销售 | | 5 | liwenzhou | 销售 | | 3 | wupeiqi | NULL | | 6 | jingwen | NULL | +----+-----------+--------------+ 6 rows in set (0.00 sec)
04:外链接之右链接:优先显示右边表的全部记录
#以右表为准,即找出所有员工信息,当然包括没有部门的员工 #本质就是:在内链接的基础上增加右边有而左边没有的结果 mysql> select employee.id,employee.name,department.name as depart_name from -> employee right join department on -> employee.dep_id=department.id; +------+-----------+--------------+ | id | name | depart_name | +------+-----------+--------------+ | 1 | egon | 技术 | | 2 | alex | 人力资源 | | 4 | yuanhao | 销售 | | 5 | liwenzhou | 销售 | | NULL | NULL | 运营 | +------+-----------+--------------+ 5 rows in set (0.00 sec)
05:全外链接:显示左右两个表的全部内容
001:union显示的左右两边的数据,并将重复的数据去重。
mysql> select * from employee left join department on employee.dep_id=department.id -> union -> select * from employee right join department on employee.dep_id=department.id -> ; +------+-----------+--------+------+--------+------+--------------+ | id | name | sex | age | dep_id | id | name | +------+-----------+--------+------+--------+------+--------------+ | 1 | egon | male | 18 | 200 | 200 | 技术 | | 2 | alex | female | 48 | 201 | 201 | 人力资源 | | 4 | yuanhao | female | 28 | 202 | 202 | 销售 | | 5 | liwenzhou | female | 28 | 202 | 202 | 销售 | | 3 | wupeiqi | male | 38 | 210 | NULL | NULL | | 6 | jingwen | female | 18 | 204 | NULL | NULL | | NULL | NULL | NULL | NULL | NULL | 203 | 运营 | +------+-----------+--------+------+--------+------+--------------+ 7 rows in set (0.06 sec)
002:union all 显示的是左右两边表的数据,并不会去重
mysql> select * from employee left join department on employee.dep_id=department.id -> union all -> select * from employee right join department on employee.dep_id=department.id; +------+-----------+--------+------+--------+------+--------------+ | id | name | sex | age | dep_id | id | name | +------+-----------+--------+------+--------+------+--------------+ | 1 | egon | male | 18 | 200 | 200 | 技术 | | 2 | alex | female | 48 | 201 | 201 | 人力资源 | | 4 | yuanhao | female | 28 | 202 | 202 | 销售 | | 5 | liwenzhou | female | 28 | 202 | 202 | 销售 | | 3 | wupeiqi | male | 38 | 210 | NULL | NULL | | 6 | jingwen | female | 18 | 204 | NULL | NULL | | 1 | egon | male | 18 | 200 | 200 | 技术 | | 2 | alex | female | 48 | 201 | 201 | 人力资源 | | 4 | yuanhao | female | 28 | 202 | 202 | 销售 | | 5 | liwenzhou | female | 28 | 202 | 202 | 销售 | | NULL | NULL | NULL | NULL | NULL | 203 | 运营 | +------+-----------+--------+------+--------+------+--------------+ 11 rows in set (0.00 sec)
三:符合条件接连的查询
1、
#示例1:以内连接的方式查询employee和department表,并且employee表中的age字段值必须大于25,即找出年龄大于25岁的员工以及员工所在的部门 mysql> select employee.name,department.name from employee inner join department -> on employee.dep_id=department.id -> where age>25; +-----------+--------------+ | name | name | +-----------+--------------+ | alex | 人力资源 | | yuanhao | 销售 | | liwenzhou | 销售 | +-----------+--------------+ 3 rows in set (0.00 sec)
2、#实例:以内连接的方式查询employee和department表,并且以age字段的生序方式显示;
实例01:内连接的方式查询employee和department表,并且employee表中的age字段值必须大于25,即找出年龄大于25岁的员工以及员工所在的部门 mysql> select employee.name,department.name from employee inner join department -> on employee.dep_id=department.id where age>25 -> order by age; #(order by 排序是默认的升序的,升序order by asc) +-----------+--------------+ | name | name | +-----------+--------------+ | yuanhao | 销售 | | liwenzhou | 销售 | | alex | 人力资源 | +-----------+--------------+ 3 rows in set (0.00 sec)
实例02:以内连接的方式查询employee和department表,并且以age字段的升序方式显示 mysql> select employee.id,employee.name,employee.age,department.name from employee,department -> where employee.dep_id=department.id -> and age >25 -> order by age asc; +----+-----------+------+--------------+ | id | name | age | name | +----+-----------+------+--------------+ | 5 | liwenzhou | 28 | 销售 | | 4 | yuanhao | 28 | 销售 | | 2 | alex | 48 | 人力资源 | +----+-----------+------+--------------+ 3 rows in set (0.00 sec)
四:子查询
解释:子查询就是将一个查询结果用括号括起来,交给另外一个sql语句,作为它的一个查询语句来进行操作。 子查询: #1:子查询是将一个查询语句嵌套在另一个查询语句中。 #2:内层查询语句的查询结果,可以为外层查询语句提供查询条件。 #3:子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字 #4:还可以包含比较运算符:= 、 !=、> 、<等
1: 带in关键字的的字查询:
mysql> select id,name from department where id in (select dep_id from employee group by -> dep_id having avg(age)>25); +------+--------------+ | id | name | +------+--------------+ | 201 | 人力资源 | | 202 | 销售 | +------+--------------+ 2 rows in set (0.05 sec) 总结:子查询的思路和解决问题一样,先解决一个然后拿着这个的结果再去解决另外一个问题,连表的思路是先将两个表关联在一起, 然后在进行group by啊过滤啊等等操作,两者的思路是不一样的.
01:#查询员工平均年龄在25岁以上的部门名,可以用连表,也可以用子查询, mysql> select department.name from department inner join employee on department.id=employee.dep_id -> group by department.name having avg(age)>25; +--------------+ | name | +--------------+ | 人力资源 | | 销售 | +--------------+
02:#查看技术部员工姓名 mysql> select name from employee where dep_id in (select id from department where name="技术"); +------+ | name | +------+ | egon | +------+ 1 row in set (0.00 sec)
03:#查看不足1人的部门名(子查询得到的是有人的部门id) mysql> select id,name from department where id not in (select distinct dep_id from employee); +------+--------+ | id | name | +------+--------+ | 203 | 运营 | +------+--------+ 1 row in set (0.00 sec)
2:比较运算符的子查询:
#比较运算符:=、!=、>、>=、<、<=、<> #查询大于所有人平均年龄的员工名与年龄 mysql> select name,age from employee where age >(select avg(age) from employee); +---------+------+ | name | age | +---------+------+ | alex | 48 | | wupeiqi | 38 | +---------+------+ 2 rows in set (0.00 sec)
3:带exists(存在)关键字的子查询
EXISTS关字键字表示存在。在使用EXISTS关键字时,内层查询语句不返回查询的记录。而是返回一个真假值。True或False
当返回True时,外层查询语句将进行查询;当返回值为False时,外层查询语句不进行查询。还可以写not exists,和exists的效果就是反的
01:employee表中不存在id为200
mysql> select * from employee where exists (select id from employee where id=500); Empty set (0.00 sec)
02:employee存在的情况:
#只有当括号里面的条件成立了,select * from employee 才会执行 mysql> select * from employee where exists (select dep_id from employee where dep_id=200); +----+-----------+--------+------+--------+ | id | name | sex | age | dep_id | +----+-----------+--------+------+--------+ | 1 | egon | male | 18 | 200 | | 2 | alex | female | 48 | 201 | | 3 | wupeiqi | male | 38 | 210 | | 4 | yuanhao | female | 28 | 202 | | 5 | liwenzhou | female | 28 | 202 | | 6 | jingwen | female | 18 | 204 | +----+-----------+--------+------+--------+ 6 rows in set (0.00 sec)