1.多表连接查询
1.1准备表
#建表
create table department(
id int,
name varchar(20)
);
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
);
#插入数据
insert into department values
(200,'技术'),
(201,'人力资源'),
(202,'销售'),
(203,'运营');
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)
;
mysql> select * from department;
+------+--------------+
| id | name |
+------+--------------+
| 200 | 技术 |
| 201 | 人力资源 |
| 202 | 销售 |
| 203 | 运营 |
+------+--------------+
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 |
+----+------------+--------+------+--------+
1.2多表连接
1.2.1语法
SELECT 字段列表
FROM 表1 INNER|LEFT|RIGHT JOIN 表2
ON 表1.字段 = 表2.字段;
1.2.2笛卡尔积
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 | 201 | 200 | 技术 |
| 3 | wupeiqi | male | 38 | 201 | 201 | 人力资源 |
| 3 | wupeiqi | male | 38 | 201 | 202 | 销售 |
| 3 | wupeiqi | male | 38 | 201 | 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 | male | 18 | 200 | 200 | 技术 |
| 5 | liwenzhou | male | 18 | 200 | 201 | 人力资源 |
| 5 | liwenzhou | male | 18 | 200 | 202 | 销售 |
| 5 | liwenzhou | male | 18 | 200 | 203 | 运营 |
| 6 | jingliyang | female | 18 | 204 | 200 | 技术 |
| 6 | jingliyang | female | 18 | 204 | 201 | 人力资源 |
| 6 | jingliyang | female | 18 | 204 | 202 | 销售 |
| 6 | jingliyang | female | 18 | 204 | 203 | 运营 |
+----+------------+--------+------+--------+------+--------------+
24 rows in set (0.00 sec)
mysql>
1.2.3inner join
"取出两张表中共有的部分
employee表中有dep_id=204
department表中有id=203
这两条是非共有数据"
mysql> select * from employee e inner join department d on e.dep_id=d.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.00 sec)
mysql>
或
mysql> select * from employee e,department d where e.dep_id=d.id;
1.2.4left join
"以左表为准,左表的数据会全部显示
employee表中dep_id为204的那条,也会存在了"
mysql> select * from employee e left join department d on e.dep_id=d.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 |
+----+------------+--------+------+--------+------+--------------+
6 rows in set (0.00 sec)
mysql>
1.2.5right join
"以右表为准,右表中的数据全部显示
department表中id=203那条也会存在"
mysql> select * from employee e right join department d on e.dep_id=d.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 | 技术 |
| NULL | NULL | NULL | NULL | NULL | 203 | 运营 |
+------+-----------+--------+------+--------+------+--------------+
6 rows in set (0.00 sec)
mysql>
1.2.6全外连接
"显示左右两个表中的全部记录
mysql中不支持全外连接 full join
mysql可以使用下面的方式实现全外连接"
mysql> select * from employee e right join department d on e.dep_id=d.id
-> union
-> select * from employee e left join department d on e.dep_id=d.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 | 技术 |
| NULL | NULL | NULL | NULL | NULL | 203 | 运营 |
| 6 | jingliyang | female | 18 | 204 | NULL | NULL |
+------+------------+--------+------+--------+------+--------------+
7 rows in set (0.00 sec)
mysql>
"union与union all的区别:union会去掉相同的记录"
mysql> select * from employee e right join department d on e.dep_id=d.id union all select * from employee e left joinn department d on e.dep_id=d.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 | 技术 |
| NULL | NULL | NULL | NULL | NULL | 203 | 运营 |
| 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 |
+------+------------+--------+------+--------+------+--------------+
12 rows in set (0.00 sec)
mysql>
1.2.7符合条件的连接查询
"#示例1:以内连接的方式查询employee和department表,并且employee表中的age字段值必须大于25,即找出年龄大于25岁的员工以及员工所在的部门"
mysql> select * from employee e right join department d on e.dep_id=d.id where age>25;
+------+---------+--------+------+--------+------+--------------+
| id | name | sex | age | dep_id | id | name |
+------+---------+--------+------+--------+------+--------------+
| 2 | alex | female | 48 | 201 | 201 | 人力资源 |
| 3 | wupeiqi | male | 38 | 201 | 201 | 人力资源 |
| 4 | yuanhao | female | 28 | 202 | 202 | 销售 |
+------+---------+--------+------+--------+------+--------------+
3 rows in set (0.00 sec)
mysql>
"示例2:以内连接的方式查询employee和department表,并且以age字段的升序方式显示"
mysql> select * from employee e right join department d on e.dep_id=d.id where age>25 order by age desc;
+------+---------+--------+------+--------+------+--------------+
| id | name | sex | age | dep_id | id | name |
+------+---------+--------+------+--------+------+--------------+
| 2 | alex | female | 48 | 201 | 201 | 人力资源 |
| 3 | wupeiqi | male | 38 | 201 | 201 | 人力资源 |
| 4 | yuanhao | female | 28 | 202 | 202 | 销售 |
+------+---------+--------+------+--------+------+--------------+
3 rows in set (0.00 sec)
mysql>
2.子查询
#1:子查询是将一个查询语句嵌套在另一个查询语句中。
#2:内层查询语句的查询结果,可以为外层查询语句提供查询条件。
#3:子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字
#4:还可以包含比较运算符:= 、 !=、> 、<等
"带in关键字的子查询"
#查询平均年龄在25岁以上的部门名
mysql> select * 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>
#查看技术部员工姓名
mysql> select * from employee where dep_id =(select id from department where name='技术')
-> ;
+----+-----------+------+------+--------+
| id | name | sex | age | dep_id |
+----+-----------+------+------+--------+
| 1 | egon | male | 18 | 200 |
| 5 | liwenzhou | male | 18 | 200 |
+----+-----------+------+------+--------+
2 rows in set (0.00 sec)
#查看不足1人的部门名
mysql> select name from department where id in( select dep_id from employee group by dep_id having sum(id)<1);
Empty set (0.00 sec)
#查看人数多于1人的部门
mysql> select name from department where id in(
-> select dep_id from employee group by dep_id having sum(id)>1);
+--------------+
| name |
+--------------+
| 技术 |
| 人力资源 |
| 销售 |
+--------------+
3 rows in set (0.00 sec)
mysql>
"带比较运算符的子查询"
#比较运算符:=、!=、>、>=、<、<=、<>
#查询大于所有人平均年龄的员工名与年龄
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)
mysql>
#查询大于部门内平均年龄的员工名、年龄
mysql> select * from employee as e inner join(
-> select avg(age) as avg_age,dep_id from employee group by dep_id) as b
-> on e.dep_id=b.dep_id
-> where e.age>b.avg_age;
+----+------+--------+------+--------+---------+--------+
| id | name | sex | age | dep_id | avg_age | dep_id |
+----+------+--------+------+--------+---------+--------+
| 2 | alex | female | 48 | 201 | 43.0000 | 201 |
+----+------+--------+------+--------+---------+--------+
1 row in set (0.00 sec)
mysql>
"带exist的关键字"
EXISTS关字键字表示存在。在使用EXISTS关键字时,内层查询语句不返回查询的记录。
而是返回一个真假值。True或False
当返回True时,外层查询语句将进行查询;当返回值为False时,外层查询语句不进行查询
#department表中存在dept_id=203,Ture
mysql> select * from employee
-> where exists
-> (select id from department where id=200);
+----+------------+--------+------+--------+
| 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 |
+----+------------+--------+------+--------+
#department表中存在dept_id=205,False
mysql> select * from employee
-> where exists
-> (select id from department where id=204);
Empty set (0.00 sec)
"练习:查询每个部门最新入职的那位员工"
company.employee
员工id id int
姓名 emp_name varchar
性别 sex enum
年龄 age int
入职日期 hire_date date
岗位 post varchar
职位描述 post_comment varchar
薪水 salary double
办公室 office int
部门编号 depart_id int
#创建表
create table employee(
id int not null unique auto_increment,
name varchar(20) not null,
sex enum('male','female') not null default 'male', #大部分是男的
age int(3) unsigned not null default 28,
hire_date date not null,
post varchar(50),
post_comment varchar(100),
salary double(15,2),
office int, #一个部门一个屋子
depart_id int
);
#插入记录
#三个部门:教学,销售,运营
insert into employee(name,sex,age,hire_date,post,salary,office,depart_id) values
('egon','male',18,'20170301','大使post',7300.33,401,1), #以下是教学部
('alex','male',78,'20150302','teacher',1000000.31,401,1),
('wupeiqi','male',81,'20130305','teacher',8300,401,1),
('yuanhao','male',73,'20140701','teacher',3500,401,1),
('liwenzhou','male',28,'20121101','teacher',2100,401,1),
('jingliyang','female',18,'20110211','teacher',9000,401,1),
('jinxin','male',18,'19000301','teacher',30000,401,1),
('成龙','male',48,'20101111','teacher',10000,401,1),
('歪歪','female',48,'20150311','sale',3000.13,402,2),#以下是销售部门
('丫丫','female',38,'20101101','sale',2000.35,402,2),
('丁丁','female',18,'20110312','sale',1000.37,402,2),
('星星','female',18,'20160513','sale',3000.29,402,2),
('格格','female',28,'20170127','sale',4000.33,402,2),
('张野','male',28,'20160311','operation',10000.13,403,3), #以下是运营部门
('程咬金','male',18,'19970312','operation',20000,403,3),
('程咬银','female',18,'20130311','operation',19000,403,3),
('程咬铜','male',18,'20150411','operation',18000,403,3),
('程咬铁','female',18,'20140512','operation',17000,403,3)
;
mysql> select depart_id,max(hire_date) from employee group by depart_id ;
+-----------+----------------+
| depart_id | max(hire_date) |
+-----------+----------------+
| 1 | 2017-03-01 |
| 2 | 2017-01-27 |
| 3 | 2016-03-11 |
+-----------+----------------+
3 rows in set (0.00 sec)
#最终答案
mysql> select * from employee as e inner join (select depart_id,max(hire_date) as max_hidate from employee group by depart_id) as b on e.depart_id=b.depart_id where e.hire_date=b.max_hidate;
+----+--------+--------+-----+------------+------------+--------------+----------+--------+-----------+-----------+------------+
| id | name | sex | age | hire_date | post | post_comment | salary | office | depart_id | depart_id | max_hidate |
+----+--------+--------+-----+------------+------------+--------------+----------+--------+-----------+-----------+------------+
| 1 | egon | male | 18 | 2017-03-01 | 大使post | NULL | 7300.33 | 401 | 1 | 1 | 2017-03-01 |
| 13 | 格格 | female | 28 | 2017-01-27 | sale | NULL | 4000.33 | 402 | 2 | 2 | 2017-01-27 |
| 14 | 张野 | male | 28 | 2016-03-11 | operation | NULL | 10000.13 | 403 | 3 | 3 | 2016-03-11 |
+----+--------+--------+-----+------------+------------+--------------+----------+--------+-----------+-----------+------------+
3 rows in set (0.00 sec)
mysql>