多表查询 子查询

day41

一丶多表查询

多表连接查询的应用场景:

连接是关系数据库模型的主要特点,也是区别于其他类型数据管理系的一个标志.

通常来说表与表之间的关系不必确定,也就时实体与实体之间的关系不紧密,检索数据时,使用连表操作增强灵活性.可以再连表查询时增加新的字段,为不同实体创建新的表.

多表联查的基本语句:

# 多表连接查询语法
select 字段
from 表1
INNER|LEFT|RIGHT  join   表2
on 表1.字段=表2.字段;
# 条件过滤
where 条件

# 1.形成新的表
# 2.灵活的操控两个表的所有字段
# 3.提高效率

 

交叉连接:

即笛卡尔积,将两个表所有的记录进行配对,数据大量冗余,没有实际意义

### 查询 employee 员工表 和 department 部门表的笛卡尔积
# 数据大量冗余 ,没有实际意义
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 | 运营         |
+----+------------+--------+------+--------+------+--------------+

 

内连接:

内连接是一种最常用的连接类型,两个表的字段满足的连接条件,只显示两张表中互相匹配的项,其他不匹配项的不显示.

### 将员工表(employee)与部门表(department)进行连接,  员工表通过字段dep_id(部门id) 与 部门表字段id(部门id)进行连接

   # 方式一 自连接 (特殊的内连接) 通过where 方式进行连接
       select * from employee e ,department d  where 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 | 技术         |
      +----+-----------+--------+------+--------+------+--------------+
       
   # 方式二 通过内连接 ... inner join ... on方式连接
  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 | 技术         |
      +----+-----------+--------+------+--------+------+--------------+

 

外连接:

左外连接:

语法:A LEFT join B on A.XX=B.XX;

左表存显示所有,右表没有与左表匹配的则为 null.

右外连接:

语法:A RIGHT join B on A.XX=B.XX;

右表存显示所有,左表没有与右表匹配的则为 null.

###  员工表和部门表
# 左外连接 : 与左表没有匹配的则显示空,左表完全显示
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         |  #### 重点~~~
  +----+------------+--------+------+--------+------+--------------+
   
# 右外连接 : 与右表没有匹配的则显示空,右表完全显示
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 | 运营         | #### 重点~~
  +------+-----------+--------+------+--------+------+--------------+

 

全连接:

union 关键字

mysql 不支持全外连接 full JOIN

mysql 使用 union 连接左连接和右连接,得到全连接

### union 全连接
# 必须是 左连接 + 右连接
select * from employee e left join department d on e.dep_id=d.id
union
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 | 技术         |
  |    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         | ### 重点 👈 ~~~
  | NULL | NULL       | NULL   | NULL |   NULL |  203 | 运营         | ### 重点 👈 ~~~
  +------+------------+--------+------+--------+------+--------------+
###  全连接 错误用法 
# 1. select * from employee e left join department d on e.dep_id=d.id 可以得到 左连接
# 2. select * from department d left join employee e on e.dep_id=d.id   通过调换表的顺序可以得到和右连接一样的效果
# 3. 但是 这样组合起来的东西并不是全连接
select * from employee e left join department d on e.dep_id=d.id union  select * from department d left join employee e 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         |
  |  200 | 技术         | 1     | egon     | male   |   18 | 200         |
  |  201 | 人力资源     | 2     | alex     | female |   48 | 201         |
  |  201 | 人力资源     | 3     | wupeiqi   | male   |   38 | 201         |
  |  202 | 销售         | 4     | yuanhao   | female |   28 | 202         |
  |  200 | 技术         | 5     | liwenzhou | male   |   18 | 200         |
  |  203 | 运营         | NULL   | NULL     | NULL   | NULL | NULL         |
  +------+--------------+--------+-----------+--------+------+--------------+

 

表:

#建表
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)
;

 

练习题:

# 1. 以 内连接的方式 查询employee和department表,并且employee表中的age字段值必须大于25,即找出年龄大于25岁的员工以及员工所在的部门
select e.name,d.name from employee e inner join department d on e.dep_id=d.id where e.age>25;

# 2. 以 内连接的方式 查询employee和department表,年龄大于25 ,并且以age字段的升序方式显示
select * from employee e inner join department d on e.dep_id=d.id where e.age>25 order by e.age;

# 3. 使用 自连接方式 查询employee和department表,年龄大于25 ,并且以age字段的升序方式显示
select * from employee e , department d  where e.dep_id=d.id and e.age>25 order by e.age;

 

二丶子查询

什么是子查询:

1.子查询是将一个查询语句嵌套另一个语句中

2.内层查询语句的结果,可以作为外层查询的条件(where)

3.子查询中可以包含:IN , NOT , ANY , ALL , EXISTS 和 NOT EXISTS等关键字

4.可以包含比较运算符: = , != , > , < 等

5.通俗:携带 两个select 就是子查询.

6.子查询也可以作为字段(只能是单个字段)

带IN关键字的子查询:

# 1. 查询平均年龄在25岁以上的部门名
select * from department where  id in (select dep_id from employee  group by dep_id having avg(age));

# 2. 查看 '技术' 部员工姓名
select name from employee where dep_id=(select id from department where name='技术');

# 3.查看不足1人的部门名(子查询得到的是有人的部门id)
select name from department where id not in(select dep_id from employee );

 

带比较运算符的子查询:

# 1. 查询大于所有人平均年龄的员工名与年龄
select name,age from employee where age>(select avg(age) from employee);

# 2. 查询大于部门内平均年龄的员工名、年龄
select e.name,e.age from employee e inner join  (select dep_id,avg(age) as avg_age from employee group by dep_id) as t on e.dep_id =t.dep_id where e.age >avg_age ;

 

带exists关键字的子查询:

exists表示:内层查询语句返回的是一个bool值,True时执行外层查询,False时不执行外层查询

# 1 . department表中存在dept_id=203,执行查询员工表
    select * from employee
        where exists (select * from department where id=203);

        # 结果:👇
        mysql> select * from employee
        -> where exists (select * from department where id=203);
        +----+------------+--------+------+--------+
        | 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)

# 2.department表中存在dept_id=205,执行查询员工表
    select * from employee
        where exists (select * from department where id=205);
        # 结果:👇
        mysql> select * from employee
        -> where exists (select * from department where id=205);
        Empty set (0.00 sec)

 

select 字段 子查询 (效率极低,不推荐使用,了解):

1.字段可以使一个子查询,但是这个字段必须是唯一值,否则报错

2.子查询处理可以放在条件中,还可以放在连表中,还可以放在select字段(要求查询的结果必须是一个单行单列的值)中.

## 准备 emp 表数据
create table emp(
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 emp(name,sex,age,hire_date,post,salary,office,depart_id) values
('egon','male',18,'20170301','老男孩驻沙河办事处外交大使',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)
;

示例:select A表name ,B表age(通过关联A表和B表的name字段) from A表

# 查询  emp 表中的name 字段 和 employee 表中的age字段, 两个表的的name字段进行关联
 select name as n  ,(select age from employee as e where e.name=n ) as employee_Age from emp;
 	# 分析: n字段来自表emp  , employee_Age字段来自 employee 字段
        +------------+--------------+
        | n          | employee_Age |
        +------------+--------------+
        | egon       |           18 |
        | alex       |           48 |
        | wupeiqi    |           38 |
        | yuanhao    |           28 |
        | liwenzhou  |           18 |
        | jingliyang |           18 |
        | jinxin     |         NULL |
        | 成龙       |         NULL |
        | 歪歪       |         NULL |
        | 丫丫       |         NULL |
        | 丁丁       |         NULL |
        | 星星       |         NULL |
        | 格格       |         NULL |
        | 张野       |         NULL |
        | 程咬金     |         NULL |
        | 程咬银     |         NULL |
        | 程咬铜     |         NULL |
        | 程咬铁     |         NULL |
        +------------+--------------+

 

 

posted on 2020-01-11 15:59  向往1  阅读(416)  评论(0编辑  收藏  举报

导航

……