连表查询

【实例】通过例子来熟悉连表查询的概念

# 第一步:建表
# 建立英雄职业分类表格
create table classification(
id int,
name varchar(20)
); # 英雄属性表格
create table hero(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') not null default 'male',
cd int, # 技能时间
cha_id int # 英雄职业
); # 插入数据
insert into classification values
(200,'法师'),
(201,'战士'),
(202,'射手'),
(203,'辅助'); insert into hero(name,sex,cd,cha_id) values
('莫甘娜','female',40,200),
('盖伦','male',50,201),
('赵信','male',48,201),
('女警','female',35,202),
('梦魇','male',30,200),
('阿卡丽','female',28,204)
;

笛卡尔积

​ 交叉连接实例:在没有任何条件连接的情况下联合两张表进行查询,结果会以笛卡尔积的形式显示

mysql> select * from hero,classification;
+----+-----------+--------+------+--------+------+--------+
| id | name | sex | cd | cha_id | id | name |
+----+-----------+--------+------+--------+------+--------+
| 1 | 莫甘娜 | female | 40 | 200 | 200 | 法师 |
| 1 | 莫甘娜 | female | 40 | 200 | 201 | 战士 |
| 1 | 莫甘娜 | female | 40 | 200 | 202 | 射手 |
| 1 | 莫甘娜 | female | 40 | 200 | 203 | 辅助 |
| 2 | 盖伦 | male | 50 | 201 | 200 | 法师 |
| 2 | 盖伦 | male | 50 | 201 | 201 | 战士 |
| 2 | 盖伦 | male | 50 | 201 | 202 | 射手 |
| 2 | 盖伦 | male | 50 | 201 | 203 | 辅助 |
| 3 | 赵信 | male | 48 | 201 | 200 | 法师 |
| 3 | 赵信 | male | 48 | 201 | 201 | 战士 |
| 3 | 赵信 | male | 48 | 201 | 202 | 射手 |
| 3 | 赵信 | male | 48 | 201 | 203 | 辅助 |
| 4 | 女警 | female | 35 | 202 | 200 | 法师 |
| 4 | 女警 | female | 35 | 202 | 201 | 战士 |
| 4 | 女警 | female | 35 | 202 | 202 | 射手 |
| 4 | 女警 | female | 35 | 202 | 203 | 辅助 |
| 5 | 梦魇 | male | 30 | 200 | 200 | 法师 |
| 5 | 梦魇 | male | 30 | 200 | 201 | 战士 |
| 5 | 梦魇 | male | 30 | 200 | 202 | 射手 |
| 5 | 梦魇 | male | 30 | 200 | 203 | 辅助 |
| 6 | 阿卡丽 | female | 28 | 204 | 200 | 法师 |
| 6 | 阿卡丽 | female | 28 | 204 | 201 | 战士 |
| 6 | 阿卡丽 | female | 28 | 204 | 202 | 射手 |
| 6 | 阿卡丽 | female | 28 | 204 | 203 | 辅助 |
+----+-----------+--------+------+--------+------+--------+
24 rows in set (0.00 sec)

​ 【结论】实际使用时应该是不会希望在笛卡尔积表中查找信息,毕竟有大量的信息冗余。我们希望的是能够通过一种连接关系,将两张有关系的表组合成一张表。

内连接

​ 内连接,实现两张表中相互匹配的行进行连接,就像hero表中的cha_id与classification里的id是相匹配,匹配格式如下:

select  *  from   表1  inner join  表2  on   条件
select * from 表1,表2,表3 where 表1.字段1=表2.字段1 and 表2.字段2 = 表3.字段1
mysql> select * from hero inner join classification on hero.cha_id = classification.id;
# 如果表格的长度比较长不方便操作的话,给他重命名以下
mysql> select * from hero inner join classification as cla on hero.cha_id = cla.id;
+----+-----------+--------+------+--------+------+--------+
| id | name | sex | cd | cha_id | id | name |
+----+-----------+--------+------+--------+------+--------+
| 1 | 莫甘娜 | female | 40 | 200 | 200 | 法师 |
| 2 | 盖伦 | male | 50 | 201 | 201 | 战士 |
| 3 | 赵信 | male | 48 | 201 | 201 | 战士 |
| 4 | 女警 | female | 35 | 202 | 202 | 射手 |
| 5 | 梦魇 | male | 30 | 200 | 200 | 法师 |
+----+-----------+--------+------+--------+------+--------+

左外连接

连接的两张表中以左侧的表为准,右侧的表匹配左侧的表,优先显示左表全部记录,显示顺序以左侧为主

用法

select  *  from   表1  left  join  表2  on   条件
mysql> select * from hero left join classification as cla on  hero.cha_id = cla.id;
+----+-----------+--------+------+--------+------+--------+
| id | name | sex | cd | cha_id | id | name |
+----+-----------+--------+------+--------+------+--------+
| 1 | 莫甘娜 | female | 40 | 200 | 200 | 法师 |
| 5 | 梦魇 | male | 30 | 200 | 200 | 法师 |
| 2 | 盖伦 | male | 50 | 201 | 201 | 战士 |
| 3 | 赵信 | male | 48 | 201 | 201 | 战士 |
| 4 | 女警 | female | 35 | 202 | 202 | 射手 |
| 6 | 阿卡丽 | female | 28 | 204 | NULL | NULL |
+----+-----------+--------+------+--------+------+--------+

【结论】左侧的表全部显示,右侧匹配左侧,缺失项为NULL

右外连接

连接的两张表中以右侧的表为准,左侧的表匹配右侧的表,优先显示左表全部记录,显示顺序以左侧为主

select  *  from   表1 right join  表2  on   条件
mysql> select * from hero right join classification as cla on  hero.cha_id = cla.id;
+------+-----------+--------+------+--------+------+--------+
| id | name | sex | cd | cha_id | id | name |
+------+-----------+--------+------+--------+------+--------+
| 1 | 莫甘娜 | female | 40 | 200 | 200 | 法师 |
| 2 | 盖伦 | male | 50 | 201 | 201 | 战士 |
| 3 | 赵信 | male | 48 | 201 | 201 | 战士 |
| 4 | 女警 | female | 35 | 202 | 202 | 射手 |
| 5 | 梦魇 | male | 30 | 200 | 200 | 法师 |
| NULL | NULL | NULL | NULL | NULL | 203 | 辅助 |
+------+-----------+--------+------+--------+------+--------+

全外连接

根据匹配项连接两张表,显示所有内容,缺失项以NULL填充

select  *  from   表1  full  join  表2  on   条件

【注意】目前各个DBMS对外连接的支持星泪不尽相同,MySQL仅仅支持左右两个外连接,并不支持全外连接

在MySQL中实现全外连接

select  *  from   表1 right join  表2  on   条件
union
select * from 表1 left join 表2 on 条件
+------+-----------+--------+------+--------+------+--------+
| id | name | sex | cd | cha_id | id | name |
+------+-----------+--------+------+--------+------+--------+
| 1 | 莫甘娜 | female | 40 | 200 | 200 | 法师 |
| 5 | 梦魇 | male | 30 | 200 | 200 | 法师 |
| 2 | 盖伦 | male | 50 | 201 | 201 | 战士 |
| 3 | 赵信 | male | 48 | 201 | 201 | 战士 |
| 4 | 女警 | female | 35 | 202 | 202 | 射手 |
| 6 | 阿卡丽 | female | 28 | 204 | NULL | NULL |
| NULL | NULL | NULL | NULL | NULL | 203 | 辅助 |
+------+-----------+--------+------+--------+------+--------+

符合条件的连接查询

# 找出cd时间大于40的英雄名称以及该英雄的职业属性
mysql> select hero.name,cla.name,hero.cd from hero inner join classification as cla on hero.cha_id = cla.id where cd> 40;
+--------+--------+------+
| name | name | cd |
+--------+--------+------+
| 盖伦 | 战士 | 50 |
| 赵信 | 战士 | 48 |
+--------+--------+------+ # 以内连接的方式查询hero和classification表,并且以age字段的升序方式显示
mysql> select * from hero inner join classification as cla on hero.cha_id = cla.id order by cd asc;
+----+-----------+--------+------+--------+------+--------+
| id | name | sex | cd | cha_id | id | name |
+----+-----------+--------+------+--------+------+--------+
| 5 | 梦魇 | male | 30 | 200 | 200 | 法师 |
| 4 | 女警 | female | 35 | 202 | 202 | 射手 |
| 1 | 莫甘娜 | female | 40 | 200 | 200 | 法师 |
| 3 | 赵信 | male | 48 | 201 | 201 | 战士 |
| 2 | 盖伦 | male | 50 | 201 | 201 | 战士 |
+----+-----------+--------+------+--------+------+--------+

9.10 子查询

  • 将一个查询语句前台到另一个查询语句中;
  • 内层查询语句的结果可以作为外层查询语句的条件;
  • 子查询中可以包含IN,NOT IN,ANY,ALL,EXISTS和 NOT EXISTS等关键字;EXISTS关字键字表示存在。在使用EXISTS关键字时,内层查询语句不返回查询的记录。而是返回一个真假值。True或False,当返回True时,外层查询语句将进行查询;当返回值为False时,外层查询语句不进行查询
  • 还可以包含比较运算符 = != > <

【举例1】

# 带in关键字的子查询
# 查询cd时间在40秒以上的英雄职业有哪些 第一步:通过hero查询cd时间在40秒的职业id
mysql> select cha_id from hero where cd>40;
+--------+
| cha_id |
+--------+
| 201 |
| 201 |
+--------+
第二步:从第一步的查询到的id在classification里找到对应的name
mysql> select name from classification where id in (201);
+--------+
| name |
+--------+
| 战士 |
+--------+ # 将两部结合在一起
mysql> select name from classification where id in (select cha_id from hero where cd>40);
+--------+
| name |
+--------+
| 战士 |
+--------+

【举例2】

# 查询平均cd在30以上的英雄职业,平均cd
【方法一】先查平均cd>30的职业id,平均cd,查出结果在之后再连表
mysql> select c.name,avg_cd from classification as c inner join (select avg(cd) as avg_cd ,cha_id from hero group by cha_id having avg(cd) > 30 )as tem on tem.cha_id = c.id;
+--------+---------+
| name | avg_cd |
+--------+---------+
| 法师 | 35.0000 |
| 战士 | 49.0000 |
| 射手 | 35.0000 |
+--------+---------+
3 rows in set (0.00 sec) 【方法二】先查各职业的平均cd,查出结果在之后再连表筛选
mysql> select c.name,avg_cd from classification as c inner join (select avg(cd) as avg_cd,cha_id from hero group by cha_id) as tem on tem.cha_id = c.id where avg_cd > 30;
+--------+---------+
| name | avg_cd |
+--------+---------+
| 法师 | 35.0000 |
| 战士 | 49.0000 |
| 射手 | 35.0000 |
+--------+---------+

【注意】

如果最终需要的结果只出现在一张表中,可以用子查询解决问题

如果最终需要的结果出现在两张表中,那么最后用的一定是连表查询

能用连表的时候就用连表,效率比子查询快

【举例三】

# 运算符的使用
# 查看法师职业有谁
mysql> select name from hero where cha_id = (select id from classification where name = '法师');
+-----------+
| name |
+-----------+
| 莫甘娜 |
| 梦魇 |
+-----------+ # 查询大于所有人平均cd的英雄名与cd
mysql> select name,cd from hero where cd > (select avg(cd) from hero);
+-----------+------+
| name | cd |
+-----------+------+
| 莫甘娜 | 40 |
| 盖伦 | 50 |
| 赵信 | 48 |
+-----------+------+ # 扩展练习:查询大于职业平均cd的英雄名、cd
mysql> select hero.name,hero.cd from hero inner join (select cha_id,avg(cd) as avg_cd from hero group by cha_id) as tem on tem.cha_id = hero.cha_id where tem.avg_cd <hero.cd;
+-----------+------+
| name | cd |
+-----------+------+
| 莫甘娜 | 40 |
| 盖伦 | 50 |
+-----------+------+

【举例四】

# 带EXISTS关键字的子查询
# EXISTS关字键字表示存在。在使用EXISTS关键字时,内层查询语句不返回查询的记# 录。而是返回一个真假值。True或False当返回True时,外层查询语句将进行查询 # 当返回值为False时,外层查询语句不进行查询 # classification表中存在203,True
mysql> select * from hero where exists (select id from classification where id = 203);
+----+-----------+--------+------+--------+
| id | name | sex | cd | cha_id |
+----+-----------+--------+------+--------+
| 1 | 莫甘娜 | female | 40 | 200 |
| 2 | 盖伦 | male | 50 | 201 |
| 3 | 赵信 | male | 48 | 201 |
| 4 | 女警 | female | 35 | 202 |
| 5 | 梦魇 | male | 30 | 200 |
| 6 | 阿卡丽 | female | 28 | 204 |
+----+-----------+--------+------+--------+ # classification表中存在205,False
mysql> select * from hero where exists (select id from classification where id = 205);
Empty set (0.00 sec)

总结

select干了什么:首先是根据条件对每行记录进行检索,再根据其他条件进行字段筛选

数据库数据导入

# 准备表、记录
mysql> create database 数据库名;
mysql> use 数据库名;
mysql> source init.sql路径;

最新文章

  1. apache中怎么配置网站的默认首页
  2. SSRS 2008 ReportServerTempDB增长异常分析
  3. 使用 Box2D 做一个 JansenWalker 机器人
  4. NOIP201103瑞士轮【B002】
  5. Gcc的编译流程分为了四个步骤:
  6. PHP如何连接Access数据库
  7. [推荐]移动H5前端性能优化指南
  8. Android完美禁用Home键
  9. Windows下查看机器监听端口
  10. 解决json_encode中文UNICODE转码问题
  11. ASP实现用年月日时分秒和两位随机数字来作为上传文件名的函数
  12. [转]iOS设备唯一标识探讨
  13. Json.Net系列教程 1.Json.Net介绍及实例
  14. IOS开发应用
  15. 【实验室笔记】C#以本地时间创建txt文件
  16. 共有49款Windows GUI开发框架开源软件 【转】
  17. springboot情操陶冶-@Conditional和@AutoConfigureAfter注解解析
  18. 操作系统-进程通信(信号量、匿名管道、命名管道、Socket)
  19. 一脸懵逼学习oracle(图形化界面操作---》PLSQL图形化界面)
  20. Python学习之旅(三十四)

热门文章

  1. RAID的多种实现
  2. 【原】涉及数据库的单元测试-JTeser
  3. HTML5测试题整理Ⅱ
  4. jquery change() 函数 语法
  5. Linux内核概述
  6. Confluence 6.15 使用附件宏
  7. Qbxt AH d4 && day-6
  8. 灰度图像--图像增强 Robert算子、Sobel算子
  9. jQuery事件之自定义事件
  10. AtCoder AGC014E Blue and Red Tree (启发式合并)