1.今日内容
-
多表联合查询
- 内连接 inner join ...on ... :只连接匹配的行
- 外连接:只连接匹配的行
- 左外连接 left join ... on ...
- 右外连接 right join ... on ...
- 全外连接 full join
select 字段列表 from 表1 inner|left|right join 表2 on 表1.字段 = 表2.字段
-
子查询
子查询是将一个查询语句嵌套在另一个查询语句中;内层查询语句的查询结果,可以为外层查询语句提供查询条件;可以包含:in 、not in、any、all、exists、和not exists等关键字。
- 带in关键字的字查询
- 带比较符关键字的子查询(=、!=、<、>等)
- 带exists关键字的子查询
2.具体内容
-
数据准备
数据准备示例
mysql> use day41; Database changed # 建表 mysql> create table department( -> id int, -> name varchar(20) -> ); Query OK, 0 rows affected (0.05 sec) 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.02 sec) # 插入数据 mysql> insert into department values -> (200,'技术'), -> (201,'人力资源'), -> (202,'销售'), -> (203,'运营'); Query OK, 4 rows affected (0.01 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> insert into employee(name,sex,age,dep_id) values -> ('egon','male',18,200), -> ('alex','female',48,201), -> ('wupeiqi','male',38,201), -> ('yuanhao','female',28,202), -> ('liwenzhou','male',18,200), -> ('jingliyang','female',18,204) -> ; Query OK, 6 rows affected (0.00 sec) Records: 6 Duplicates: 0 Warnings: 0 # 查看表结构和数据 mysql> desc department; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.01 sec) 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) mysql> select * from department; +------+--------------+ | id | name | +------+--------------+ | 200 | 技术 | | 201 | 人力资源 | | 202 | 销售 | | 203 | 运营 | +------+--------------+ 4 rows in set (0.00 sec) mysql> select * from employee; +----+------------+--------+------+--------+ | id | name | sex | age | dep_id | +----+------------+--------+------+--------+ | 1 | egon | male | 18 | 200 | | 2 | alex | female | 48 | 201 | | 3 | wupeiqi | male | 38 | 201 | | 4 | yuanhao | female | 28 | 202 | | 5 | liwenzhou | male | 18 | 200 | | 6 | jingliyang | female | 18 | 204 | +----+------------+--------+------+--------+ 6 rows in set (0.00 sec)
-
交叉连接
(不适合任何匹配条件,生成笛卡尔积)
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 | 技术 | | ..... | +----+------------+--------+------+--------+------+--------------+ 24 rows in set (0.01 sec)
-
内连接
- 只连接匹配的行
- 找两张表共有的部分,相当于利用条件从笛卡尔积结果中筛选出正确的结果
- 取出两张表中存在连接匹配关系的记录
select * from 表1 inner join 表2 on 条件 # select * from department as t1 inner join employee as t2 on t1.id = t2.dep_id; # 示例 mysql> select * from employee inner 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 | 人力资源 | | 3 | wupeiqi | male | 38 | 201 | 201 | 人力资源 | | 4 | yuanhao | female | 28 | 202 | 202 | 销售 | | 5 | liwenzhou | male | 18 | 200 | 200 | 技术 | +----+-----------+--------+------+--------+------+--------------+ 5 rows in set (0.01 sec)
-
左外连接
- 优先显示左表全部记录
- 在内连接的基础上增加左表有,右表没有的结果
select * from 表1 left join 表2 on 条件 #select * from department as t1 left join employee as t2 on t1.id = t2.dep_id; # 示例 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 | 技术 | | 5 | liwenzhou | 技术 | | 2 | alex | 人力资源 | | 3 | wupeiqi | 人力资源 | | 4 | yuanhao | 销售 | | 6 | jingliyang | NULL | +----+------------+--------------+ 6 rows in set (0.00 sec)
-
右外连接
- 优先显示右表全部记录
- 在内连接的基础上增加右边有,左边没有的结果
select * from 表1 right join 表2 on 条件 # 示例 mysql> select * from department t1 right join employee as t2 on t1.id = t2.dep_id; +------+--------------+----+------------+--------+------+--------+ | id | name | id | name | sex | age | dep_id | +------+--------------+----+------------+--------+------+--------+ | 200 | 技术 | 1 | egon | male | 18 | 200 | | 200 | 技术 | 5 | liwenzhou | male | 18 | 200 | | 201 | 人力资源 | 2 | alex | female | 48 | 201 | | 201 | 人力资源 | 3 | wupeiqi | male | 38 | 201 | | 202 | 销售 | 4 | yuanhao | female | 28 | 202 | | NULL | NULL | 6 | jingliyang | female | 18 | 204 | +------+--------------+----+------------+--------+------+--------+ 6 rows in set (0.00 sec)
-
全外连接
- 显示左右两个表的全部记录
- 在内连接的基础上增加左边有右边没有,和右边有左边没有的结果
- 不支持 full join ,但可以间接实现全外连接
mysql> select * from employee left join department on employee.dep_id = department.id -> union -> select * from department t1 right join employee as t2 on t1.id = t2.dep_id; +------+--------------+--------+------------+--------+------+--------------+ | id | name | sex | age | dep_id | id | name | +------+--------------+--------+------------+--------+------+--------------+ | 1 | egon | male | 18 | 200 | 200 | 技术 | | 5 | liwenzhou | male | 18 | 200 | 200 | 技术 | | 2 | alex | female | 48 | 201 | 201 | 人力资源 | | 3 | wupeiqi | male | 38 | 201 | 201 | 人力资源 | | 4 | yuanhao | female | 28 | 202 | 202 | 销售 | | 6 | jingliyang | female | 18 | 204 | NULL | NULL | | 200 | 技术 | 1 | egon | male | 18 | 200 | | 200 | 技术 | 5 | liwenzhou | male | 18 | 200 | | 201 | 人力资源 | 2 | alex | female | 48 | 201 | | 201 | 人力资源 | 3 | wupeiqi | male | 38 | 201 | | 202 | 销售 | 4 | yuanhao | female | 28 | 202 | | NULL | NULL | 6 | jingliyang | female | 18 | 204 | +------+--------------+--------+------------+--------+------+--------------+ 12 rows in set (0.01 sec)
- 练习
练习
# 找到技术部的所有人的名字 mysql> select * from employee e inner join department d on e.dep_id = d.id where d.name = '技术'; +-----------+ | name | +-----------+ | egon | | liwenzhou | +-----------+ 2 rows in set (0.00 sec) # 找到人力资源的年龄大于40岁的人的姓名 mysql> select * from employee e inner join department d on e.dep_id = d.id where d.name = '人力资源' and age > 40; +------+ | name | +------+ | alex | +------+ 1 row in set (0.00 sec) # 找到年龄大于25岁的员工以及员工所在部门 mysql> select e.name,d.name from employee e inner join department d on e.dep_id = d.id where age > 25; +---------+--------------+ | name | name | +---------+--------------+ | alex | 人力资源 | | wupeiqi | 人力资源 | | yuanhao | 销售 | +---------+--------------+ 3 rows in set (0.00 sec) # 以内连接的方式查询employee和department表,并且以age字段的升序方式显示 mysql> select * from employee e inner join department d on e.dep_id = d.id order by age; +----+-----------+--------+------+--------+------+--------------+ | id | name | sex | age | dep_id | id | name | +----+-----------+--------+------+--------+------+--------------+ | 1 | egon | male | 18 | 200 | 200 | 技术 | | 5 | liwenzhou | male | 18 | 200 | 200 | 技术 | | 4 | yuanhao | female | 28 | 202 | 202 | 销售 | | 3 | wupeiqi | male | 38 | 201 | 201 | 人力资源 | | 2 | alex | female | 48 | 201 | 201 | 人力资源 | +----+-----------+--------+------+--------+------+--------------+ 5 rows in set (0.01 sec) # 求每一个部门有多少人,按照人数从高到低排序 select d.name,count(e.id) from employee e inner join department d on e.dep_id = d.id group by d.name order by count(e.id) desc; +--------------+-------------+ | name | count(e.id) | +--------------+-------------+ | 技术 | 2 | | 人力资源 | 2 | | 销售 | 1 | +--------------+-------------+ 3 rows in set (0.01 sec)
-
带in 的字查询
# 查询平均年龄在25岁以上的部门名 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.01 sec) # 查看技术部员工姓名 mysql> select name from employee where dep_id in ( select id from department where name = '技术'); +-----------+ | name | +-----------+ | egon | | liwenzhou | +-----------+ 2 rows in set (0.00 sec) # 查看不足1人的部门名(子查询得到的所有人的部门id) mysql> select name from department where id not in (select distinct dep_id from employee); +--------+ | name | +--------+ | 运营 | +--------+ 1 row in set (0.00 sec)
-
带比较符的子查询
-
带exists的子查询