热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

数据库技术:MySQL连接查询的原理和应用

概述mysql最强大的功能之一就是能在数据检索的执行中连接(join)表。大部分的单表数据查询并不能满足我们的需求,这时候我们就需要连接一个或者多个表,并通过一些条件过滤筛选出我们

概述

mysql最强大的功能之一就是能在数据检索的执行中连接(join)表。大部分的单表数据查询并不能满足我们的需求,这时候我们就需要连接一个或者多个表,并通过一些条件过滤筛选出我们需要的数据。

了解mysql连接查询之前我们先来理解下笛卡尔积的原理。

数据准备

依旧使用上节的表数据(包含classes 班级表和students 学生表):

  mysql> select * from classes;  +---------+-----------+  | classid | classname |  +---------+-----------+  |    1 | 初三一班 |  |    2 | 初三二班 |  |    3 | 初三三班 |  |    4 | 初三四班 |  +---------+-----------+  4 rows in set    mysql> select * from students;  +-----------+-------------+-------+---------+  | studentid | studentname | score | classid |  +-----------+-------------+-------+---------+  |     1 | brand    | 97.5 |    1 |  |     2 | helen    | 96.5 |    1 |  |     3 | lyn     | 96  |    1 |  |     4 | sol     | 97  |    1 |  |     7 | b1     | 81  |    2 |  |     8 | b2     | 82  |    2 |  |    13 | c1     | 71  |    3 |  |    14 | c2     | 72.5 |    3 |  |    19 | lala    | 51  |    0 |  +-----------+-------------+-------+---------+  9 rows in set

笛卡尔积

笛卡尔积:也就是笛卡尔乘积,假设两个集合a和b,笛卡尔积表示a集合中的元素和b集合中的元素任意相互关联产生的所有可能的结果。

比如a中有m个元素,b中有n个元素,a、b笛卡尔积产生的结果有m*n个结果,相当于循环遍历两个集合中的元素,任意组合。

笛卡尔积在sql中的实现方式既是交叉连接(cross join)。所有连接方式都会先生成临时笛卡尔积表,笛卡尔积是关系代数里的一个概念,表示两个表中的每一行数据任意组合。

所以上面的表就是 4(班级表)* 9(学生表) = 36条数据;

笛卡尔积语法格式:

   select cname1,cname2,... from tname1,tname2,...;   or   select cname from tname1 join tname2 [join tname...];

图例表示:

MySQL 连接查询的原理和应用

上述两个表实际执行结果如下:

  mysql> select * from classes a,students b order by a.classid,b.studentid;  +---------+-----------+-----------+-------------+-------+---------+  | classid | classname | studentid | studentname | score | classid |  +---------+-----------+-----------+-------------+-------+---------+  |    1 | 初三一班 |     1 | brand    | 97.5 |    1 |  |    1 | 初三一班 |     2 | helen    | 96.5 |    1 |  |    1 | 初三一班 |     3 | lyn     | 96  |    1 |  |    1 | 初三一班 |     4 | sol     | 97  |    1 |  |    1 | 初三一班 |     7 | b1     | 81  |    2 |  |    1 | 初三一班 |     8 | b2     | 82  |    2 |  |    1 | 初三一班 |    13 | c1     | 71  |    3 |  |    1 | 初三一班 |    14 | c2     | 72.5 |    3 |  |    1 | 初三一班 |    19 | lala    | 51  |    0 |  |    2 | 初三二班 |     1 | brand    | 97.5 |    1 |  |    2 | 初三二班 |     2 | helen    | 96.5 |    1 |  |    2 | 初三二班 |     3 | lyn     | 96  |    1 |  |    2 | 初三二班 |     4 | sol     | 97  |    1 |  |    2 | 初三二班 |     7 | b1     | 81  |    2 |  |    2 | 初三二班 |     8 | b2     | 82  |    2 |  |    2 | 初三二班 |    13 | c1     | 71  |    3 |  |    2 | 初三二班 |    14 | c2     | 72.5 |    3 |  |    2 | 初三二班 |    19 | lala    | 51  |    0 |  |    3 | 初三三班 |     1 | brand    | 97.5 |    1 |  |    3 | 初三三班 |     2 | helen    | 96.5 |    1 |  |    3 | 初三三班 |     3 | lyn     | 96  |    1 |  |    3 | 初三三班 |     4 | sol     | 97  |    1 |  |    3 | 初三三班 |     7 | b1     | 81  |    2 |  |    3 | 初三三班 |     8 | b2     | 82  |    2 |  |    3 | 初三三班 |    13 | c1     | 71  |    3 |  |    3 | 初三三班 |    14 | c2     | 72.5 |    3 |  |    3 | 初三三班 |    19 | lala    | 51  |    0 |  |    4 | 初三四班 |     1 | brand    | 97.5 |    1 |  |    4 | 初三四班 |     2 | helen    | 96.5 |    1 |  |    4 | 初三四班 |     3 | lyn     | 96  |    1 |  |    4 | 初三四班 |     4 | sol     | 97  |    1 |  |    4 | 初三四班 |     7 | b1     | 81  |    2 |  |    4 | 初三四班 |     8 | b2     | 82  |    2 |  |    4 | 初三四班 |    13 | c1     | 71  |    3 |  |    4 | 初三四班 |    14 | c2     | 72.5 |    3 |  |    4 | 初三四班 |    19 | lala    | 51  |    0 |  +---------+-----------+-----------+-------------+-------+---------+  36 rows in set

这样的数据肯定不是我们想要的,在实际应用中,表连接时要加上限制条件,才能够筛选出我们真正需要的数据。

我们主要的连接查询有这几种:内连接、左(外)连接、右(外)连接,下面我们一 一来看。

内连接查询 inner join

语法格式:

   select cname from tname1 inner join tname2 on join condition;   或者   select cname from tname1 join tname2 on join condition;   或者   select cname from tname1,tname2 [where join condition];

说明:在笛卡尔积的基础上加上了连接条件,组合两个表,返回符合连接条件的记录,也就是返回两个表的交集(阴影)部分。如果没有加上这个连接条件,就是上面笛卡尔积的结果。

MySQL 连接查询的原理和应用

  mysql> select a.classname,b.studentname,b.score from classes a inner join students b on a.classid = b.classid;  +-----------+-------------+-------+  | classname | studentname | score |  +-----------+-------------+-------+  | 初三一班 | brand    | 97.5 |  | 初三一班 | helen    | 96.5 |  | 初三一班 | lyn     | 96  |  | 初三一班 | sol     | 97  |  | 初三二班 | b1     | 81  |  | 初三二班 | b2     | 82  |  | 初三三班 | c1     | 71  |  | 初三三班 | c2     | 72.5 |  +-----------+-------------+-------+  8 rows in set

从上面的数据可以看出 ,初三四班 classid = 4,因为没有关联的学生,所以被过滤掉了;lala 同学的classid=0,没法关联到具体的班级,也被过滤掉了,只取两表都有的数据交集

  mysql> select a.classname,b.studentname,b.score from classes a,students b where a.classid = b.classid and a.classid=1;  +-----------+-------------+-------+  | classname | studentname | score |  +-----------+-------------+-------+  | 初三一班 | brand    | 97.5 |  | 初三一班 | helen    | 96.5 |  | 初三一班 | lyn     | 96  |  | 初三一班 | sol     | 97  |  +-----------+-------------+-------+  4 rows in set

查找1班同学的成绩信息,上面语法格式的第三种,这种方式简洁高效,直接在连接查询的结果后面进行where条件筛选。 

左连接查询 left join

left join on / left outer join on,语法格式:

  select cname from tname1 left join tname2 on join condition;

说明: left join 是left outer join的简写,全称是左外连接,外连接中的一种。 左(外)连接,左表(classes)的记录将会全部出来,而右表(students)只会显示符合搜索条件的记录。右表无法关联的内容均为null。

MySQL 连接查询的原理和应用

  mysql> select a.classname,b.studentname,b.score from classes a left join students b on a.classid = b.classid;  +-----------+-------------+-------+  | classname | studentname | score |  +-----------+-------------+-------+  | 初三一班 | brand    | 97.5 |  | 初三一班 | helen    | 96.5 |  | 初三一班 | lyn     | 96  |  | 初三一班 | sol     | 97  |  | 初三二班 | b1     | 81  |  | 初三二班 | b2     | 82  |  | 初三三班 | c1     | 71  |  | 初三三班 | c2     | 72.5 |  | 初三四班 | null    | null |  +-----------+-------------+-------+  9 rows in set

从上面结果中可以看出,初三四班无法找到对应的学生,所以后面两个字段使用null标识。 

右连接查询 right join

right join on / right outer join on,语法格式:

  select cname from tname1 right join tname2 on join condition;

说明:right join是right outer join的简写,全称是右外连接,外连接中的一种。与左(外)连接相反,右(外)连接,左表(classes)只会显示符合搜索条件的记录,而右表(students)的记录将会全部表示出来。左表记录不足的地方均为null。 

MySQL 连接查询的原理和应用

  mysql> select a.classname,b.studentname,b.score from classes a right join students b on a.classid = b.classid;  +-----------+-------------+-------+  | classname | studentname | score |  +-----------+-------------+-------+  | 初三一班 | brand    | 97.5 |  | 初三一班 | helen    | 96.5 |  | 初三一班 | lyn     | 96  |  | 初三一班 | sol     | 97  |  | 初三二班 | b1     | 81  |  | 初三二班 | b2     | 82  |  | 初三三班 | c1     | 71  |  | 初三三班 | c2     | 72.5 |  | null   | lala    | 51  |  +-----------+-------------+-------+  9 rows in set

从上面结果中可以看出,lala同学无法找到班级,所以班级名称字段为null。  

连接查询+聚合函数

使用连接查询的时候,经常会配合使用聚集函数来进行数据汇总。比如在上面的数据基础上查询出每个班级的人数和平均分数、班级总分数。

  mysql> select a.classname as '班级名称',count(b.studentid) as '总人数',sum(b.score) as '总分',avg(b.score) as '平均分'  from classes a inner join students b on a.classid = b.classid  group by a.classid,a.classname;  +----------+--------+--------+-----------+  | 班级名称 | 总人数 | 总分  | 平均分  |  +----------+--------+--------+-----------+  | 初三一班 |   4 | 387.00 | 96.750000 |  | 初三二班 |   2 | 163.00 | 81.500000 |  | 初三三班 |   2 | 143.50 | 71.750000 |  +----------+--------+--------+-----------+  3 rows in set

这边连表查询的同时对班级(classid,classname)做了分组,并输出每个班级的人数、平均分、班级总分。

连接查询附加过滤条件

使用连接查询之后,大概率会对数据进行在过滤筛选,所以我们可以在连接查询之后再加上where条件,比如我们根据上述的结果只取出一班的同学信息。

  mysql> select a.classname,b.studentname,b.score from classes a inner join students b on a.classid = b.classid where a.classid=1;  +-----------+-------------+-------+  | classname | studentname | score |  +-----------+-------------+-------+  | 初三一班 | brand    | 97.5 |  | 初三一班 | helen    | 96.5 |  | 初三一班 | lyn     | 96  |  | 初三一班 | sol     | 97  |  +-----------+-------------+-------+  4 rows in set

如上,只输出一班的同学,同理,可以附件 limit 限制,order by排序等操作。

总结

1、连接查询必然要带上连接条件,否则会变成笛卡尔乘积数据,使用不正确的联结条件,也将返回不正确的数据。

2、sql规范推荐首选inner join语法。但是连接的几种方式本身并没有明显的性能差距,性能的差距主要是由数据的结构、连接的条件,索引的使用等多种条件综合决定的。

我们应该根据实际的业务场景来决定,比如上述数据场景:如果要求返回返回有学生的班级就使用 inner join;如果必须输出所有班级则使用left join;如果必须输出所有学生,则使用right join。

3、性能上的考虑,mysql在运行时会根据关联条件处理连接的表,这种处理可能是非常耗费资源的,连接的表越多,性能下降越厉害。所以要分析去除那些不必要的连接和不需要显示的字段。

之前我的项目团队在优化旧的业务代码时,发现随着业务的变更,某些数据不需要显示,对应的某个连接也不需要了,去掉之后,性能较大提升。

以上就是mysql 连接查询的原理和应用的详细内容,更多关于mysql 连接查询的资料请关注<编程笔记>其它相关文章!

需要了解更多数据库技术:MySQL 连接查询的原理和应用,都可以关注数据库技术分享栏目—编程笔记


推荐阅读
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文由编程笔记小编整理,介绍了PHP中的MySQL函数库及其常用函数,包括mysql_connect、mysql_error、mysql_select_db、mysql_query、mysql_affected_row、mysql_close等。希望对读者有一定的参考价值。 ... [详细]
  • Oracle分析函数first_value()和last_value()的用法及原理
    本文介绍了Oracle分析函数first_value()和last_value()的用法和原理,以及在查询销售记录日期和部门中的应用。通过示例和解释,详细说明了first_value()和last_value()的功能和不同之处。同时,对于last_value()的结果出现不一样的情况进行了解释,并提供了理解last_value()默认统计范围的方法。该文对于使用Oracle分析函数的开发人员和数据库管理员具有参考价值。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文详细介绍了MysqlDump和mysqldump进行全库备份的相关知识,包括备份命令的使用方法、my.cnf配置文件的设置、binlog日志的位置指定、增量恢复的方式以及适用于innodb引擎和myisam引擎的备份方法。对于需要进行数据库备份的用户来说,本文提供了一些有价值的参考内容。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 解决VS写C#项目导入MySQL数据源报错“You have a usable connection already”问题的正确方法
    本文介绍了在VS写C#项目导入MySQL数据源时出现报错“You have a usable connection already”的问题,并给出了正确的解决方法。详细描述了问题的出现情况和报错信息,并提供了解决该问题的步骤和注意事项。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
author-avatar
Devil灬旋律
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有