mysql,SQL标准,多表查询中内连接,外连接,自然连接等详解之查询结果集的笛卡尔积的演化

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 先附上数据 CREATE TABLE `course` ( `cno` int(11) NOT NULL, `cname` char(30) CHARACTER SET utf8 NOT NULL, `ctime` int(11) NOT NULL, `scount` ...

先附上数据

CREATE TABLE `course` (
  `cno` int(11) NOT NULL,
  `cname` char(30) CHARACTER SET utf8 NOT NULL,
  `ctime` int(11) NOT NULL,
  `scount` int(11) NOT NULL,
  `ctest` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `course` VALUES ('4', '应用数学基础', '48', '120', '2016-03-10 10:08:29');
INSERT INTO `course` VALUES ('5', '生物工程概论', '32', '80', '2016-03-10 10:09:24');
INSERT INTO `course` VALUES ('1', '计算机软件基础', '32', '70', '2016-03-10 10:09:47');
INSERT INTO `course` VALUES ('2', '计算机硬件基础', '24', '80', '2016-03-10 10:10:28');
INSERT INTO `course` VALUES ('8', '模拟电路设计', '28', '90', '2016-04-06 10:11:02');
INSERT INTO `course` VALUES ('7', '机械设计实践', '48', '68', '2016-03-10 10:11:29');
INSERT INTO `course` VALUES ('3', '生物化学', '32', '40', '2016-03-29 10:11:54');
INSERT INTO `course` VALUES ('9', '数据库设计', '16', '80', '2016-03-10 10:12:14');
INSERT INTO `course` VALUES ('6', '设计理论', '28', '45', '2016-03-10 10:12:33');
INSERT INTO `course` VALUES ('10', '计算机入门', '24', '150', '2016-03-10 10:12:53');
INSERT INTO `course` VALUES ('11', '数字电路设计基础', '30', '125', '2016-03-10 10:13:10');

CREATE TABLE `student` (
  `sno` char(4) CHARACTER SET utf8 DEFAULT NULL,
  `sname` char(10) CHARACTER SET utf8 DEFAULT NULL,
  `dname` char(10) CHARACTER SET utf8 DEFAULT NULL,
  `ssex` char(2) CHARACTER SET utf8 NOT NULL,
  `cno` int(11) NOT NULL,
  `mark` decimal(3,1) NOT NULL,
  `type` char(4) CHARACTER SET utf8 NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `student` VALUES ('9701', '刘建国', '管理工程', '', '4', '82.5', '必修');
INSERT INTO `student` VALUES ('9701', '刘建国', '管理工程', '', '10', '70.0', '必修');
INSERT INTO `student` VALUES ('9701', '刘建国', '管理工程', '', '1', '78.5', '选修');
INSERT INTO `student` VALUES ('9702', '李春', '环境工程', '', '5', '63.0', '必修');
INSERT INTO `student` VALUES ('9702', '李春', '环境工程', '', '10', '58.0', '选修');
INSERT INTO `student` VALUES ('9703', '王天', '生物', '', '5', '48.5', '必修');
INSERT INTO `student` VALUES ('9703', '王天', '生物', '', '2', '86.0', '选修');
INSERT INTO `student` VALUES ('9704', '李华', '计算机', '', '4', '76.0', '必修');
INSERT INTO `student` VALUES ('9704', '李华', '计算机', '', '1', '92.0', '必修');
INSERT INTO `student` VALUES ('9704', '李华', '计算机', '', '2', '89.0', '必修');
INSERT INTO `student` VALUES ('9704', '李华', '计算机', '', '9', '80.0', '必修');
INSERT INTO `student` VALUES ('9704', '李华', '计算机', '', '8', '70.0', '选修');
INSERT INTO `student` VALUES ('9705', '孙庆', '电子工程', '', '8', '79.0', '必修');
INSERT INTO `student` VALUES ('9705', '孙庆', '电子工程', '', '1', '59.0', '必修');
INSERT INTO `student` VALUES ('9705', '孙庆', '电子工程', '', '11', '52.0', '必修');
INSERT INTO `student` VALUES ('9705', '孙庆', '电子工程', '', '6', '68.0', '必修');
INSERT INTO `student` VALUES ('9706', '高伟', '机械工程', '', '13', '93.0', '必修');
INSERT INTO `student` VALUES ('9706', '高伟', '机械工程', '', '12', '88.5', '必修');
INSERT INTO `student` VALUES ('9706', '高伟', '机械工程', '', '1', '78.0', '选修');
INSERT INTO `student` VALUES ('9706', '高伟', '机械工程', '', '10', '76.0', '选修');

CREATE TABLE `teacher` (
  `tno` int(11) NOT NULL,
  `tname` varchar(10) CHARACTER SET utf8 NOT NULL,
  `cno` int(11) NOT NULL,
  `sal` int(11) DEFAULT NULL,
  `dname` char(10) CHARACTER SET utf8 NOT NULL,
  `tsex` char(2) CHARACTER SET utf8 NOT NULL,
  `age` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `teacher` VALUES ('1', '王军', '4', '800', '数学', '', '32');
INSERT INTO `teacher` VALUES ('2', '李丹', '5', '1200', '生物', '', '54');
INSERT INTO `teacher` VALUES ('3', '王永军', '1', '900', '计算机', '', '40');
INSERT INTO `teacher` VALUES ('4', '刘小静', '2', '1200', '计算机', '', '46');
INSERT INTO `teacher` VALUES ('5', '高伟', '8', '2100', '电子工程', '', '39');
INSERT INTO `teacher` VALUES ('6', '李伟', '7', '1200', '机械工程', '', '29');
INSERT INTO `teacher` VALUES ('7', '刘辉', '3', '900', '生物', '', '46');
INSERT INTO `teacher` VALUES ('8', '刘静', '12', '1300', '经济管理', '', '28');
INSERT INTO `teacher` VALUES ('9', '李伟', '9', null, '计算机', '', '43');
INSERT INTO `teacher` VALUES ('10', '刘一凯', '13', null, '计算机', '', '33');

简单的二表连接

SELECT tname,dname,cname,ctest from teacher,course WHERE teacher.cno=course.cno
该语句的执行过程实例可以表示这样:
a,系统首先执行from子句,这里from子句列出有两个表teacher表和course表,DBMS讲计算这两个表的笛卡尔积,列出这两个表中行的所以可能组合,形成一个中间表。中间表中的每条记录包含了两个表中的所有行。
b,然后系统执行where子句,根据teacher.cno=course.cno关系对中间表进行搜索,去除那些不满足该关系的记录。
c,最后系统执行select语句,从执行where子句后得到的中间表的每条记录中,提取tname,dname,cname,ctest4个字段的信息作为结果表。
 
 
需要强调,表的连接所依据的关系是在where子句中定义的。在实际应用中,用户要实现表的连接必然要依据一定的关系。
 
 
如果不指明连接关系,即不使用where子句。
SELECT tname,dname,cname,ctest from teacher,course

        
从结果可以看到,每个教师的信息均与所有课程信息进行了匹配连接。它实际返回连接表中所有数据行的笛卡尔积,其结果集合中的数据行数等于第一个表中符合查询条件的数据行乘以第二个表中符合查询条件的数据行数,即10X11=110条记录。

采用join关键字建立连接

        也可以在from子句中,通过连接关键字实现表的连接,这样有助于将连接操作与where的搜索条件区分开来。
SELECT COLUMN from join_table join_type join_table on (join_condition)
 
join_type为连接类型,可分为4种:自然连接,内连接,外连接和交叉连接。
 

自连接

自连接是指表与其自身进行连接,这需要使用表别名。
查询成绩中存在不及格课程的学生的姓名,所在系,所有的课程及成绩信息
SELECT s.sname,s.dname,s.cno,s.mark
from student s
where s.mark<60
无法得到想要结果
 
 
SELECT s.sname,s.dname,s.cno,s.mark
from student s
where s.sno in(SELECT DISTINCT s.sno from student s where s.mark<60)
得到想要结果
 
 
SELECT DISTINCT s.sname,s.dname,s.cno,s.mark
from student s,student s2
where s.sno=s2.sno
and s2.mark<60
f rom子句中的两个表实际上都是表student。为了独立地使用它们,采用表别名方法。
 
SELECT s.sname,s.dname,s.cno,s.mark
from student s,student s2
where s.sno=s2.sno
and s2.mark<60
系统首先执行from子句,将student表S1与它自身S2的笛卡尔积,作为中间表。
实际上,该中间表的每一条记录包含两部分信息,一部分是S1的记录,一部分是S2的记录。而后执行where子句,在中间表中,搜索S2中成绩低于60的学生的记录,同时要求记录中S1与S2是同一个学生的记录即学号相同。最后执行select语句,从中间表获取S1中相应的信息作为结果表。
 
当执行where子句,从中间表中逐条搜索S2中成绩低于60的学生的记录时,由于孙庆有两门课程不及格,所以对每门不及格的记录都满足搜索条件,因此导致从S1得到的信息中出现了重复的记录。
 
简单来说,中间表是没有重复记录的,但是S1部分字段是有重复的,而结果集提取的只是S1部分的字段,因此就有可能有重复记录。
 
一般情况,自连接也可以使用子查询的方式实现。
 
 
SELECT DISTINCT s.sname,s.dname,s.cno,s.mark
from student s,student s2
where s.sno=s2.sno
and s.mark<60
 

自然连接

它将表中具有相同名称的列自动进行记录匹配,自然连接不必指定任何同等连接条件。
自然连接自动判断相同名称的列,而后形成匹配。缺点是,虽然可以指定查询结果包括哪些列,但是不能人为地指定哪些列被匹配。另外,自然连接的一个特点是连接后的结果表中匹配的列只有一个。如上,在自然连接后的表中只有一列C。
 
 
从student表和teacher表中查询学生姓名,所在系,所修的本系教师开设的课程的课程号以及开课教师姓名。这时候就采用natural join对两个表进行自然连接。
SELECT sname,dname,cno,tname
from student NATURAL join teacher
等价
SELECT sname,s.dname,s.cno,tname
from student s, teacher t
where s.dname=t.dname
and s.cno=t.cno

 

事实上,使用基于where子句的等值连接要比使用natural join运算符进行自然连接要灵活的多。
正如前面介绍的,使用natural join运算符自动判断出具有相同名称的列,而后形成匹配,不能人为地指定哪些列被匹配。当自然连接student和teacher表时,CNO和dname列同时被匹配,而不能只匹配一列。
 
 
 

外连接

不管是内连接还是带where子句的多表查询,都组合自多个表,并生成结果表。换句话说,如果任何一个源表中的行在另一个源表中没有匹配,DBMS将把该行放在最后的结果表中。
 
而外连接告诉ODBC生成的结果表,不仅包含符合条件的行,而且还包含左表(左外连接时),右表(右外连接时)或两个边接表(全外连接)中所有的数据行。
 
 
SQL的外连接共有三种类型:左外连接,右外连接,全外连接。
 

1,左外连接

左外连接,left outer join ,告诉DBMS生成的结果表中,除了包括匹配行外,还包括join关键字(from子句中)左边表的不匹配行。
左外连接实际可以表示为:
左外连接=内连接+左边表中失配的元组。
其中,缺少的右边表中的属性值用null表示。如下:

SELECT s.sno,sname,s.cno,cname,ctest,mark
from student s LEFT JOIN course c
on s.cno=c.cno
ORDER BY sname
 

右外连接

外连接,right outer join ,告诉DBMS生成的结果表中,除了包括匹配行外,还包括join关键字(from子句中)边表的不匹配行。
外连接实际可以表示为:
外连接=内连接+边表中失配的元组。
其中,缺少的左边表中的属性值用null表示。如下:
SELECT s.sno,sname,s.cno,cname,ctest,mark
from student s RIGHT JOIN course c
on s.cno=c.cno
ORDER BY sname

 

全外连接

全外连接,full outer join,告诉DBMS生成的结果表中,除了包括匹配行外,还包括join关键字(from子句中)左边表和右边表的不匹配行。
可以这样表示:
全外连接=内连接+左边表中失配的元组+右边表中失配的元组
 
SELECT s.sno,sname,s.cno,cname,ctest,mark
from student s full OUTER JOIN course c
on s.cno=c.cno
ORDER BY sname
 
本人使用mysql数据库,因为mysql暂时还不支持全外连接full的功能.
 
 一些语句流程顺序,等我有空回顾在写把。等我。勿急躁。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
作者: intsmaze(刘洋)
老铁,你的--->推荐,--->关注,--->评论--->是我继续写作的动力。
微信公众号号:Apache技术研究院
由于博主能力有限,文中可能存在描述不正确,欢迎指正、补充!
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
7天前
|
SQL 存储 缓存
浅析MySQL中的SQL执行过程
本文探讨了MySQL的体系结构、SQL执行流程及SQL执行时间分析方法。首先介绍了MySQL由连接层、SQL层和存储引擎层构成;接着详细描述了SQL从客户端发送到服务器执行的具体流程;最后,通过启用profiling功能,展示了如何分析SQL执行时间,并说明了MySQL 8.0版本后移除查询缓存的原因。
浅析MySQL中的SQL执行过程
|
14天前
|
自然语言处理 关系型数据库 MySQL
MySQL MATCH 匹配中文 无法查询的问题如何处理?
【8月更文挑战第27天】MySQL MATCH 匹配中文 无法查询的问题如何处理?
134 62
|
12天前
|
自然语言处理 关系型数据库 MySQL
MySQL MATCH 匹配中文 无法查询的问题如何处理?
【8月更文挑战第29天】MySQL MATCH 匹配中文 无法查询的问题如何处理?
40 6
|
12天前
|
SQL 存储 关系型数据库
mysql查询怎么用
mysql查询怎么用【8月更文挑战第31天】
17 4
|
11天前
|
前端开发 C# 设计模式
“深度剖析WPF开发中的设计模式应用:以MVVM为核心,手把手教你重构代码结构,实现软件工程的最佳实践与高效协作”
【8月更文挑战第31天】设计模式是在软件工程中解决常见问题的成熟方案。在WPF开发中,合理应用如MVC、MVVM及工厂模式等能显著提升代码质量和可维护性。本文通过具体案例,详细解析了这些模式的实际应用,特别是MVVM模式如何通过分离UI逻辑与业务逻辑,实现视图与模型的松耦合,从而优化代码结构并提高开发效率。通过示例代码展示了从模型定义、视图模型管理到视图展示的全过程,帮助读者更好地理解并应用这些模式。
27 0
|
11天前
|
SQL 关系型数据库 MySQL
|
11天前
|
SQL 关系型数据库 MySQL
SQL Server、MySQL、PostgreSQL:主流数据库SQL语法异同比较——深入探讨数据类型、分页查询、表创建与数据插入、函数和索引等关键语法差异,为跨数据库开发提供实用指导
【8月更文挑战第31天】SQL Server、MySQL和PostgreSQL是当今最流行的关系型数据库管理系统,均使用SQL作为查询语言,但在语法和功能实现上存在差异。本文将比较它们在数据类型、分页查询、创建和插入数据以及函数和索引等方面的异同,帮助开发者更好地理解和使用这些数据库。尽管它们共用SQL语言,但每个系统都有独特的语法规则,了解这些差异有助于提升开发效率和项目成功率。
70 0
|
2月前
|
SQL 存储 监控
SQL Server的并行实施如何优化?
【7月更文挑战第23天】SQL Server的并行实施如何优化?
55 13
|
2月前
|
SQL
解锁 SQL Server 2022的时间序列数据功能
【7月更文挑战第14天】要解锁SQL Server 2022的时间序列数据功能,可使用`generate_series`函数生成整数序列,例如:`SELECT value FROM generate_series(1, 10)。此外,`date_bucket`函数能按指定间隔(如周)对日期时间值分组,这些工具结合窗口函数和其他时间日期函数,能高效处理和分析时间序列数据。更多信息请参考官方文档和技术资料。
|
2月前
|
SQL 存储 网络安全
关系数据库SQLserver 安装 SQL Server
【7月更文挑战第26天】
44 6