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>