数据库多表查询

9 篇文章 0 订阅

多表查询

准备员工表和部门表

# 部门表
create table dep (
id int,
name varchar(20)
);

# 员工表
create table emp (
id int primary key auto_increment,
name varchar(20),
sex enum("male","female") not null default "male",
age int,
dep_id int
);


# 插入数据
insert into dep values
(200,'技术'),
(201,'人力资源'),
(202,'销售'),
(203,'运营');

insert into emp(name,sex,age,dep_id) values
("haha","male",18,200),
("xixi","female",48,201),
("dudu","male",38,201),
("lala","female",18,202),
("nana","male",16,200),
("bubu","female",18,204);

# 查看表结构
desc dep;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  |     | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+

desc emp;
+--------+-----------------------+------+-----+---------+----------------+
| 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    |                |
+--------+-----------------------+------+-----+---------+----------------+

# 查看表数据
select * from emp;
+----+------+--------+------+--------+
| id | name | sex    | age  | dep_id |
+----+------+--------+------+--------+
|  1 | haha | male   |   18 |    200 |
|  2 | xixi | female |   48 |    201 |
|  3 | dudu | male   |   38 |    201 |
|  4 | lala | female |   18 |    202 |
|  5 | nana | male   |   16 |    200 |
|  6 | bubu | female |   18 |    204 |
+----+------+--------+------+--------+

select * from dep;
+------+--------------+
| id   | name         |
+------+--------------+
|  200 | 技术         |
|  201 | 人力资源     |
|  202 | 销售         |
|  203 | 运营         |
+------+--------------+
 

连接查询

将多个select语句生成的虚拟表进行拼接,拼接成一张表进行查询!!!

交叉连接:不适用任何匹配条件,生成笛卡尔积

笛卡尔积

  假设集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0),(b, 1), (b, 2)}

 select * from emp,dep;
+----+------+--------+------+--------+------+--------------+
| id | name | sex    | age  | dep_id | id   | name         |
+----+------+--------+------+--------+------+--------------+
|  1 | haha | male   |   18 |    200 |  200 | 技术         |
|  1 | haha | male   |   18 |    200 |  201 | 人力资源     |
|  1 | haha | male   |   18 |    200 |  202 | 销售         |
|  1 | haha | male   |   18 |    200 |  203 | 运营         |
|  2 | xixi | female |   48 |    201 |  200 | 技术         |
|  2 | xixi | female |   48 |    201 |  201 | 人力资源     |
|  2 | xixi | female |   48 |    201 |  202 | 销售         |
|  2 | xixi | female |   48 |    201 |  203 | 运营         |
|  3 | dudu | male   |   38 |    201 |  200 | 技术         |
|  3 | dudu | male   |   38 |    201 |  201 | 人力资源     |
|  3 | dudu | male   |   38 |    201 |  202 | 销售         |
|  3 | dudu | male   |   38 |    201 |  203 | 运营         |
|  4 | lala | female |   18 |    202 |  200 | 技术         |
|  4 | lala | female |   18 |    202 |  201 | 人力资源     |
|  4 | lala | female |   18 |    202 |  202 | 销售         |
|  4 | lala | female |   18 |    202 |  203 | 运营         |
|  5 | nana | male   |   16 |    200 |  200 | 技术         |
|  5 | nana | male   |   16 |    200 |  201 | 人力资源     |
|  5 | nana | male   |   16 |    200 |  202 | 销售         |
|  5 | nana | male   |   16 |    200 |  203 | 运营         |
|  6 | bubu | female |   18 |    204 |  200 | 技术         |
|  6 | bubu | female |   18 |    204 |  201 | 人力资源     |
|  6 | bubu | female |   18 |    204 |  202 | 销售         |
|  6 | bubu | female |   18 |    204 |  203 | 运营         |
+----+------+--------+------+--------+------+--------------+
 

inner join 内连接

  inner join  	将表进行拼接,找两张表共有的部分,相当于利用条件从笛卡尔积结果中筛选出了正确的结果

# dep没有204这个部门,因而emp表中关于204这条员工信息没有匹配出来
select emp.id,emp.name,emp.sex,emp.age,emp.dep_id,dep.name from emp inner join dep on dep.id=emp.dep_id;
+----+------+--------+------+--------+--------------+
| id | name | sex    | age  | dep_id | name         |
+----+------+--------+------+--------+--------------+
|  1 | haha | male   |   18 |    200 | 技术         |
|  2 | xixi | female |   48 |    201 | 人力资源     |
|  3 | dudu | male   |   38 |    201 | 人力资源     |
|  4 | lala | female |   18 |    202 | 销售         |
|  5 | nana | male   |   16 |    200 | 技术         |
+----+------+--------+------+--------+--------------+

# dep没有204这个部门,因而emp表中关于204这条员工信息没有匹配出来
select * from emp inner join dep on emp.dep_id=dep.id;
+----+------+--------+------+--------+------+--------------+
| id | name | sex    | age  | dep_id | id   | name         |
+----+------+--------+------+--------+------+--------------+
|  1 | haha | male   |   18 |    200 |  200 | 技术         |
|  2 | xixi | female |   48 |    201 |  201 | 人力资源     |
|  3 | dudu | male   |   38 |    201 |  201 | 人力资源     |
|  4 | lala | female |   18 |    202 |  202 | 销售         |
|  5 | nana | male   |   16 |    200 |  200 | 技术         |
+----+------+--------+------+--------+------+--------------+
 

left join 左连接

  left join		将表进行拼接,以左表为准,优先显示左表全部记录

# 以左表为准,即找出所有员工信息,当然包括没有部门的员工信息
select emp.id,emp.name,emp.sex,emp.age,emp.dep_id,dep.name from emp left join dep on emp.dep_id=dep.id;
+----+------+--------+------+--------+--------------+
| id | name | sex    | age  | dep_id | name         |
+----+------+--------+------+--------+--------------+
|  1 | haha | male   |   18 |    200 | 技术         |
|  5 | nana | male   |   16 |    200 | 技术         |
|  2 | xixi | female |   48 |    201 | 人力资源     |
|  3 | dudu | male   |   38 |    201 | 人力资源     |
|  4 | lala | female |   18 |    202 | 销售         |
|  6 | bubu | female |   18 |    204 | NULL         |
+----+------+--------+------+--------+--------------+

# 以左表为准,即找出所有员工信息,当然包括没有部门的员工信息
select * from emp left join dep on emp.dep_id=dep.id;
+----+------+--------+------+--------+------+--------------+
| id | name | sex    | age  | dep_id | id   | name         |
+----+------+--------+------+--------+------+--------------+
|  1 | haha | male   |   18 |    200 |  200 | 技术         |
|  5 | nana | male   |   16 |    200 |  200 | 技术         |
|  2 | xixi | female |   48 |    201 |  201 | 人力资源     |
|  3 | dudu | male   |   38 |    201 |  201 | 人力资源     |
|  4 | lala | female |   18 |    202 |  202 | 销售         |
|  6 | bubu | female |   18 |    204 | NULL | NULL         |
+----+------+--------+------+--------+------+--------------+
 

right join 右连接

  right join		将表进行拼接,以右表为准,优先显示右表全部记录

# 以右表为准,即找出所有部门信息,包括没有员工的部门
select emp.id,emp.name,emp.sex,emp.age,emp.dep_id,dep.name from emp right join dep on emp.dep_id=dep.id;
+------+------+--------+------+--------+--------------+
| id   | name | sex    | age  | dep_id | name         |
+------+------+--------+------+--------+--------------+
|    1 | haha | male   |   18 |    200 | 技术         |
|    2 | xixi | female |   48 |    201 | 人力资源     |
|    3 | dudu | male   |   38 |    201 | 人力资源     |
|    4 | lala | female |   18 |    202 | 销售         |
|    5 | nana | male   |   16 |    200 | 技术         |
| NULL | NULL | NULL   | NULL |   NULL | 运营         |
+------+------+--------+------+--------+--------------+

# 以右表为准,即找出所有部门信息,包括没有员工的部门
select * from emp right join dep on emp.dep_id=dep.id;
+------+------+--------+------+--------+------+--------------+
| id   | name | sex    | age  | dep_id | id   | name         |
+------+------+--------+------+--------+------+--------------+
|    1 | haha | male   |   18 |    200 |  200 | 技术         |
|    2 | xixi | female |   48 |    201 |  201 | 人力资源     |
|    3 | dudu | male   |   38 |    201 |  201 | 人力资源     |
|    4 | lala | female |   18 |    202 |  202 | 销售         |
|    5 | nana | male   |   16 |    200 |  200 | 技术         |
| NULL | NULL | NULL   | NULL |   NULL |  203 | 运营         |
+------+------+--------+------+--------+------+--------------+

union 全外连接

  union 		将左连接的表数据和右连接的表数据进行拼接,显示左右两个表全部记录

# 将左连接和右连接进行拼接
select emp.id,emp.name,emp.sex,emp.age,emp.dep_id,dep.name from emp left join dep on emp.dep_id=dep.id 
union 
select emp.id,emp.name,emp.sex,emp.age,emp.dep_id,dep.name from emp right join dep on emp.dep_id=dep.id;
+------+------+--------+------+--------+--------------+
| id   | name | sex    | age  | dep_id | name         |
+------+------+--------+------+--------+--------------+
|    1 | haha | male   |   18 |    200 | 技术         |
|    5 | nana | male   |   16 |    200 | 技术         |
|    2 | xixi | female |   48 |    201 | 人力资源     |
|    3 | dudu | male   |   38 |    201 | 人力资源     |
|    4 | lala | female |   18 |    202 | 销售         |
|    6 | bubu | female |   18 |    204 | NULL         |
| NULL | NULL | NULL   | NULL |   NULL | 运营         |
+------+------+--------+------+--------+--------------+

# 将左连接和右连接进行拼接
select * from emp left join dep on emp.dep_id=dep.id 
union 
select * from emp right join dep on emp.dep_id=dep.id;
+------+------+--------+------+--------+------+--------------+
| id   | name | sex    | age  | dep_id | id   | name         |
+------+------+--------+------+--------+------+--------------+
|    1 | haha | male   |   18 |    200 |  200 | 技术         |
|    5 | nana | male   |   16 |    200 |  200 | 技术         |
|    2 | xixi | female |   48 |    201 |  201 | 人力资源     |
|    3 | dudu | male   |   38 |    201 |  201 | 人力资源     |
|    4 | lala | female |   18 |    202 |  202 | 销售         |
|    6 | bubu | female |   18 |    204 | NULL | NULL         |
| NULL | NULL | NULL   | NULL |   NULL |  203 | 运营         |
+------+------+--------+------+--------+------+--------------+
 

连接查询案例

# 找出年龄大于18岁的员工以及员工所在的部门
select emp.id,emp.name,emp.age,dep.name from emp inner join dep on emp.dep_id = dep.id where emp.age>18;
+----+------+------+--------------+
| id | name | age  | name         |
+----+------+------+--------------+
|  2 | xixi |   48 | 人力资源     |
|  3 | dudu |   38 | 人力资源     |
+----+------+------+--------------+

# 以内连接的方式查询emp和dep的表,并且以age字段的升序方式显示
select emp.id,emp.name,emp.age,dep.name from emp inner join dep on emp.dep_id = dep.id order by age;
+----+------+------+--------------+
| id | name | age  | name         |
+----+------+------+--------------+
|  5 | nana |   16 | 技术         |
|  1 | haha |   18 | 技术         |
|  4 | lala |   18 | 销售         |
|  3 | dudu |   38 | 人力资源     |
|  2 | xixi |   48 | 人力资源     |
+----+------+------+--------------+
 

子查询

将一个select语句的查询结果,当作条件给另一个select语句使用!!!

1:子查询是将一个查询语句嵌套在另一个查询语句中。
2:内层查询语句的查询结果,可以为外层查询语句提供查询条件。
3:子查询中可以包含:in、not in、any、all、exists 和 not exists等关键字
4:还可以包含比较运算符:= 、 !=、> 、<等

带in关键字的子查询
 

# 查询平均年龄在25岁以上的部门名
select id,name from dep where id in (select dep_id from emp group by dep_id having avg(age)>25);
+------+--------------+
| id   | name         |
+------+--------------+
|  201 | 人力资源     |
+------+--------------+

# 查询技术部员工姓名
select dep_id "技术部",name from emp where dep_id in (select id from dep where name = "技术");
+-----------+------+
| 技术部    | name |
+-----------+------+
|       200 | haha |
|       200 | nana |
+-----------+------+

# 查看不足1人的部门名(子查询得到的是有人的部门id)
select * from dep where id not in (select distinct dep_id from emp);
+------+--------+
| id   | name   |
+------+--------+
|  203 | 运营   |
+------+--------+

sql语句中 not in 无法处理null的值,即子查询中如果存在null的值,not in将无法处理

# 插入一条不属于任何组的员工数据
insert into emp(name,sex,age,dep_id) values("biubiu","male",26,null);

select * from emp;
+----+--------+--------+------+--------+
| id | name   | sex    | age  | dep_id |
+----+--------+--------+------+--------+
|  1 | haha   | male   |   18 |    200 |
|  2 | xixi   | female |   48 |    201 |
|  3 | dudu   | male   |   38 |    201 |
|  4 | lala   | female |   18 |    202 |
|  5 | nana   | male   |   16 |    200 |
|  6 | bubu   | female |   18 |    204 |
|  7 | biubiu | male   |   26 |   NULL |
+----+--------+--------+------+--------+

# not in无法查询字段名包含null的数据
select * from dep where id not in (select distinct dep_id from emp);
# Empty set (0.00 sec)

select * from dep where id not in (select distinct dep_id from emp where dep_id is not null);
+------+--------+
| id   | name   |
+------+--------+
|  203 | 运营   |
+------+--------+

# 删除新插入的数据
delete from emp where id=7;
 

带any关键字的子查询

any必须和其他的比较运算符共同使用,而且any必须将比较运算符放在any关键字之前,所比较的值需要匹配子查询中的任意一个值。

      = any 和 in 的用法一样    (any后面不能直接跟结果集,只能跟sql语句)
      > any         大于任意一个(即范围内大于最小)
      < any         小于任意一个(即范围内小于最大)

# 查询技术部门和销售部门的员工
select * from emp where dep_id in (select id from dep where name = "技术" or name = "销售");
+----+------+--------+------+--------+
| id | name | sex    | age  | dep_id |
+----+------+--------+------+--------+
|  1 | haha | male   |   18 |    200 |
|  4 | lala | female |   18 |    202 |
|  5 | nana | male   |   16 |    200 |
+----+------+--------+------+--------+

# =any跟in的用法一样(等于任意一个)
select * from emp where dep_id =any (select id from dep where name = "技术" or name = "销售");
+----+------+--------+------+--------+
| id | name | sex    | age  | dep_id |
+----+------+--------+------+--------+
|  1 | haha | male   |   18 |    200 |
|  4 | lala | female |   18 |    202 |
|  5 | nana | male   |   16 |    200 |
+----+------+--------+------+--------+

# 每个部门的平均年龄
select dep_id,avg(age) from emp group by dep_id;
+--------+----------+
| dep_id | avg(age) |
+--------+----------+
|    200 |  17.0000 |
|    201 |  43.0000 |
|    202 |  18.0000 |
|    204 |  18.0000 |
+--------+----------+

# 查询员工表中所有员工年龄大于任意部门平均年龄的员工信息(即大于平均年龄最小的部门)
select * from emp where age >any (select avg(age) from emp group by dep_id);
+----+------+--------+------+--------+
| id | name | sex    | age  | dep_id |
+----+------+--------+------+--------+
|  1 | haha | male   |   18 |    200 |
|  2 | xixi | female |   48 |    201 |
|  3 | dudu | male   |   38 |    201 |
|  4 | lala | female |   18 |    202 |
|  6 | bubu | female |   18 |    204 |
+----+------+--------+------+--------+

# 查询员工表中所有员工年龄小于任意部门平均年龄的员工信息(即小于平均年龄最大的部门)
select * from emp where age <any (select avg(age) from emp group by dep_id);
+----+------+--------+------+--------+
| id | name | sex    | age  | dep_id |
+----+------+--------+------+--------+
|  1 | haha | male   |   18 |    200 |
|  3 | dudu | male   |   38 |    201 |
|  4 | lala | female |   18 |    202 |
|  5 | nana | male   |   16 |    200 |
|  6 | bubu | female |   18 |    204 |
+----+------+--------+------+--------+
 

带all关键字的子查询

all用法和any类似,只不过all表示的是所有,any表示任一个值。

   > all		大于全部(即范围内大于最大)
   < all	    小于全部(即范围内小于最小)

# 查询员工表中所有员工年龄大于全部部门平均年龄的员工信息(即大于平均年龄最大的部门)
select * from emp where age >all (select avg(age) from emp group by dep_id);
+----+------+--------+------+--------+
| id | name | sex    | age  | dep_id |
+----+------+--------+------+--------+
|  2 | xixi | female |   48 |    201 |
+----+------+--------+------+--------+

# 查询员工表中所有员工年龄小于全部部门平均年龄的员工信息(即小于平均年龄最小的部门)
select * from emp where age < all (select avg(age) from emp group by dep_id);
+----+------+------+------+--------+
| id | name | sex  | age  | dep_id |
+----+------+------+------+--------+
|  5 | nana | male |   16 |    200 |
+----+------+------+------+--------+

exists布尔值判断(了解即可)

只返回布尔值 True or False
返回True的时候外层查询语句执行
返回False的时候外层查询语句不再执行

# 查询哪一个部门里面是没有员工的
# 查询结果跟原表做对比,203运营部门里面是没有人的
select * from dep where exists(select * from emp where emp.dep_id=dep.id);
+------+--------------+
| id   | name         |
+------+--------------+
|  200 | 技术         |
|  201 | 人力资源     |
|  202 | 销售         |
+------+--------------+

exist可以这么去理解:
for line in dep:            # 读出dep表中的每一行
    for lines in emp:            # 读出emp表中的每一行
        where emp.dep_id = dep.id        # 取出两张表的部门id做对比,判断有没有输出结果(true或者false)
 

多表查询总结

多表查询就两种方式

1. 连接查询:先拼接,再查询

2. 子查询:一步一步来

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值