【MySQL】联合查询

article/2025/10/3 19:10:14

目录

1、前言

2、联合查询

3、内连接和外连接

4、案例演示

4.1 查询篮球哥每科的成绩

4.2 查询所有同学的总成绩及邮箱

5、自连接

5.1 显示所有计算机原理成绩比java成绩高的同学

6、子查询

6.1 查询出篮球哥的同班同学

6.2 多行子查询

7、合并查询


1、前言

在实际开发中,往往数据是来自不同的表,所以需要多表联合查询,多表查询是对多张表的数据取笛卡尔积。

这里就需要简单了解下笛卡尔积的概念了:

集合A {a1,a2,a3} 集合B {b1,b2},他们的 笛卡尔积 是 A*B = { (a1,b1), (a1,b2), (a2,b1), (a2,b2), (a3,b1), (a3,b2)}任意两个元素结合在一起。

如上图所示,笛卡尔积就是把这两个表放到一起进行计算,分别取出第一张表的每一行,和第二张表的每一行配对,得到一个新的记录。


2、联合查询

有了上述笛卡尔积的认识,我们就来使用下联合查询,首先准备 student,class 这两张表,并且增加相关的数据:

create table student (id int primary key,name varchar(20),classId int
);create table class (classId int primary key,name varchar(20)
);insert into student value(23001, '张三', 1),(23002, '李四', 2),(23003, '王五', 1),(23004, '赵六', 3),(23005, '孙七', 3);insert into class value(1, 'java1班'),(2, 'java2班'),(3, 'java3班');

 

有了上述的数据后,我们就来进行简单的联合查询(通过 student class 表 查询出每个学生对应的班级):

这里我们发现,同时查询两张表,进行了笛卡尔积,跟我们上述画的图是一样的效果,但是这里我们发现有很多无效的元素,按道理来说,张三的 classId 为 1,对应 class 表应该是 java1 班的,所以这里的数据是存在很多无效数据的,此时我们就可以使用 where 条件来进行筛选:

有了筛选条件后,显然发现就没有了那些无效的数据了,此时我们再次省略我们不想要的列,只保留学生姓名和班级名称就好了:

这样一来得到的结果就是我们想要的结果了。

上述可能有一个点之前没有说过,比如 student.classId 和 class.classId,这里为什么要加 表名. 前缀呢?由于我们进行的是多表查询,势必可能会出现不同表中存在相同的列名,这里我们就需要告诉 MySQL 是那个表中的列。如果不加表名,这时就区分不了是哪个表的列了,随之就会报错!

上述是最基础的多表查询,后面我们就来用案例来学习更复杂的多表查询。


3、内连接和外连接

在大多数情况下,都是没有啥区别的,比如要连接的两个表中,里面的数据都是一一对应的,这个时候就没有区别,如果不是一一对应,内连接和外连接就有区别了。

这里我们有这样的两张表,通过看数据可以发现,student表中张三在score表中是没有成绩的,而score表中studentId为4是没有对应学生的。我们就用上述两张表进行联合查询演示下外连接和内连接的区别:

select * from student, score where student.id = score.studentId;
select * from student join score on student.id = score.studentId;
-- 这两种的写法都是一样的效果
+------+--------+-----------+-------+
| id   | name   | studentId | java  |
+------+--------+-----------+-------+
|    1 | 张三   |         1 | 89.00 |
|    2 | 李四   |         2 | 92.00 |
+------+--------+-----------+-------+

上述的写法都属于内连接,此处查询结果中,最终剩下的就是两个表里都有的数据,都能关联上的数据,如果使用外连接,那么结果就不相同了。

● 左外连接: 

select * from student left join score on student.id = score.studentId;

● 右外连接:

select * from student right join score on student.id = score.studentId;

我们对比这两种两种连接方式,来观察他们的区别:

  • 左外连接会把左表的结果都列出来,哪怕右表中没有相应的数据,就使用 NULL 来填充
  • 右外连接会把右表的结果都列出来,哪怕左表中没有相应的数据,就使用 NULL 来填充 

后续为了演示更复杂的多表查询,以及结合实际的情况,这里我们需要重新构建四张表: 

create table classes (id int primary key auto_increment, name varchar(20), synopsis varchar(100));create table student (id int primary key, name varchar(20), qq_mail varchar(20) ,classes_id int);create table course (id int primary key auto_increment, name varchar(20));create table score (score decimal(3, 1), student_id int, course_id int);

由于插入数据部分代码太多,不方便放入文章里,大家可以自行录入,也可以去博主的主页去下载现成的 SQL 文件哦。


4、案例演示

4.1 查询篮球哥每科的成绩

此时要注意篮球哥的信息在 student 表中,而成绩在 score 表里,课程名又在 course 表中,而 score 表中包含了 sutdent_id 以及 course_id:

select student.name as '姓名', course.name as '课程名', score.score as '分数' 
from student, score, course 
where student.id = score.student_id and score.course_id = course.id and student.name = '篮球哥';

这里为了大家看的方便,就进行了换行,最终我们只需要显示三个字段,数据来源于 student,score,course 表,接下来就是 where 条件部分了,相信也是清晰明了的。

4.2 查询所有同学的总成绩及邮箱

此时要用到 student,score 这两个表,并且还要使用聚合函数进行求每个同学的总分,也就是要对每个同学的 id 进行分组后,成绩求和。

select student.name, sum(score) as '总分', student.qq_mail
from student, score 
where student.id = score.student_id 
group by student.id;
-- 成绩表对学生表是多对1关系,查询总成绩是根据成绩表的同学id来进行分组的

这里交大家一个简单的方法读 sql 语句,select 后面最终显示的列,from 后面是数据来源的表,where 是进行筛选的条件,group by 是按照某个字段进行分组。这样一来就简洁明了了。


5、自连接

自连接就是自己跟自己笛卡尔积,这不是一个通用的解决方案,而是特殊问题的特殊处理方法,自连接的效果就是把 行 转换成 列,这里我们举个例子:

5.1 显示所有计算机原理成绩比java成绩高的同学

select * from score, score;
-- ERROR 1066 (42000): Not unique table/alias: 'score'

这里发现直接自己跟自己笛卡尔积会报错,说名字重复了,不是唯一的,可以采用取别名的方式来解决这个错误:

select * from score as s1, score as s2;

首先我们要明确这 java 和 计算机原理 的课程 ID 是多少:

select * from course;
+----+--------------------+
| id | name               |
+----+--------------------+
|  1 | Java               |
|  2 | 中国传统文化       |
|  3 | 计算机原理         |
|  4 | 语文               |
|  5 | 高阶数学           |
|  6 | 英文               |
+----+--------------------+
-- 6 rows in set (0.00 sec)

得到了 java 和 计算机原理 的 id 之后,对 score 表自身进行笛卡尔积,就可以指定 s1.class_id = 1 and s2.class_id = 3 这样的条件,也就是将一行中 s1 表显示 java, s2 表显示计算机原理:

select * from score as s1, score as s2 where s1.course_id = 1 and s2.course_id = 3;

此查询结果还存在无效的数据,比如 s1.student_id 与 s2.student_id 应该是一样的, 因为我们查询的是谁的计算机原理比Java成绩高,所以我们还要加上一个条件:

select * from score as s1, score as s2 
where s1.course_id = 1 
and s2.course_id = 3 
and s1.student_id = s2.student_id;

现在这个结果是满足 id 相等,同时满足了要比较的科目,现在就差一个条件了!就是 s1.score < s2.score 这就表示查询的是 java 成绩小于 计算机原理的同学:

select * from score as s1, score as s2 
where s1.course_id = 1 
and s2.course_id = 3 
and s1.student_id = s2.student_id 
and s1.score < s2.score;

最后我们对这个结果保留想要的字段,并且增加 student.name 这个字段,注意增加 student.name 表示要多一个student 表一起进行笛卡尔积,所以我们还要加一个条件 student.id = s1.student_id,这样才是最终完整的结果:

 select student.name, s1.score as Java, s2.score as 计算机原理 from student, score as s1, score as s2where s1.student_id = s2.student_id and s1.course_id = 1 and s2.course_id = 3 and s1.score < s2.score and student.id = s1.student_id;

以上就完整的查询出了 计算机原理成绩大于Java成绩的同学了! 这个过程看似复杂,但不要着急,静下心来一步步分析,阅读 SQL,相信你能理解的!


6、子查询

子查询本质就是套娃,实际开发中,慎重使用,子查询可能会构造出非常复杂,非常不好理解的 SQL,对于代码的可读性就大大降低了,对于 SQL 的执行效率,也有可能是毁灭性的打击!

6.1 查询出篮球哥的同班同学

正常情况下,先查询出篮球哥的班级id,然后条件设置为 claases_id 跟 篮球哥的班级id 相同即可,并排掉篮球哥:

select classes_id from student where name = '篮球哥';
-- 1
select * from student where classes_id = 1 and name != '篮球哥';

这样就能求出篮球哥的同班同学,但是子查询是如何写的呢?

select * from student where classes_id = (select classes_id from student where name = '篮球哥') and name != '篮球哥';

子查询的写法其实就是套娃!把一个查询的结果,作为另一个查询的一部分条件(此处作为另一个一部分查询条件的查询结果只能返回一条数据) 。

6.2 多行子查询

● 查询语文或英文课程的成绩信息

正常情况下,我们需要先查询出语文和英文的课程id,然后去成绩表中查询对应课程id 的成绩:

select id from course where name = '语文' or name = '英文';
-- 4 6
select * from score where course_id = 4 or course_id = 6;

如果要用多行子查询就需要利用 in 关键字:

select * from score where course_id in (select id from course where name = '语文' or name = '英文');

如果查询是排除语文英文信息呢?就使用 not in 就行,可以把 in 理解成再这个范围内,整体查询结果必须满足 in 后面子查询的结果范围。

这里的套娃是无穷无尽的,一般不建议这样做,实际上更推荐是直接多步完成查询就好,没必要强行合成一个!


7、合并查询

合并查询就比较简单了,本质上就是把两个查询的结果集合并成一个。

● 查询课程id小于3,或者课程名为英文的课程

select * from course where id < 3 union select * from course where name = '英文';

这里可能有小伙伴就很奇怪,这中间直接来个 or 不就行了吗?是的!

注意:这里的 union 是可以来自于不同的表,只要查询的结果的列匹配即可,而 or 只能是同一表。  

除了 union 还有一个 union all,他们区别不大,union 是会进行去重(重复的行只会保留一份),而 union all 是不会去重的!



http://chatgpt.dhexx.cn/article/QbreOufL.shtml

相关文章

数据库组合查询

在使用数据库的过程中&#xff0c;数据的查询是使用最多的&#xff0c;所以&#xff0c;数据的精确查询是一个很重要的问题。以前的数据查询是最简单的数据查询&#xff0c;也从来没想过组合查询的问题&#xff0c;可是在做机房收费系统的时候&#xff0c;遇到了一个很大的问题…

SQL组合查询知识

大多数SQL查询只从一个或者多表中返回数据都是单个select语句。但是SQL server允许多个select语句执行&#xff0c;它返回的结果是一个结果集&#xff0c;需要使用 union 组合 &#xff0c;这些组合一般称为并&#xff08;union&#xff09;和复合查询&#xff08;compound que…

组合查询

今天我们来学习一下组合查询的方法。什么叫组合查询&#xff0c;就是根据自己选择的内容进行数据查询。我们可以根据单个数据查询&#xff0c;也可以根据多个数据查询我们想要的内容。而我今天要讲的是根据学院、年级、班级还有学号和姓名进行查询的方法&#xff0c;我们首先打…

MySQL入门学习:组合查询

一、组合查询 多数SQL查询都只包含从一个或多个表中返回数据的单条SELECT语句。MySQL也允许执行多个查询&#xff08;多条SELECT语句&#xff09;&#xff0c;并将结果作为单个查询结果集返回。这些组合查询通常称为并&#xff08;union&#xff09;或复合查询&#xff08;comp…

SQL数据库的组合查询和统计查询

数据库的组合查询和统计查询 一、实验目的 对数据库进行组合查询和统计查询 二、实验内容 1、加深对SQL语言查询语句的理解 2、熟练掌握数据查询中的分组统计、计算和组合操作方法。 三、实验要求 在本题下面提交基本操作效果截图。 一&#xff0c;组合查询简单查询。 1、…

组合多个查询

紫色代表一级目录 粉红代表二级目录 蓝色代表三级目录 红色代表关键字 橙色代表说明 单查询与组合查询   单查询实例      使用了操作符UNION    组合查询操作符   UNION     UNION 操作符可以组合两个或多个 SELECT 语句的结果&#xff0c;不包含重复的记录。换…

[Mysql] 组合查询

组合查询可以将多个SELECT结果拼接在一起作为最终结果输出(输出组合成单个查询结果集) 当存在多个查询结果符合条件&#xff0c;需要将多个查询结果进行纵向拼接时&#xff0c;就会用到组合查询 如下图所示&#xff0c;如果需要查出的结果包含表A和表B两个部分&#xff0c;则…

MySQL必知必会:组合查询(Union)

本篇文章主要介绍使用Union操作符将多个SELECT查询组合成一个结果集。本文参考《Mysql必知必会》工作实践融合 组合查询 定义 在大多数开发中&#xff0c;使用一条SELECT查询就会返回一个结果集。如果&#xff0c;我们想一次性查询多条SQL语句&#xff0c;并将每一条SELECT查询…

组合查询——union

文章目录 1.组合查询2.创建组合查询2.1 使用union2.2 union规则2.3 包含或取消重复的行2.4 对组合查询结果排序 1.组合查询 组合查询指的是&#xff1a;在Mysql中执行多个查询&#xff0c;并将结果作为单个查询结果集返回。 这些组合查询通常称为并或复合查询。 以下2种情况&…

【SQL自学打卡|DAY13】——组合查询

前言 ❤欢迎大家阅读我的文章呀❤ 今天是SQL必知必会的最后一块练习。 希望你们在我的文章当中能有所收获&#xff01;&#xff01;&#xff01; SLogan:利用有限的时间&#xff0c;撸起袖子加油干&#xff01; 知识点回顾 内联结&#xff1a;inner join。取两列的交集。 外联…

PyCharm取消波浪线、下划线和中划线

默认情况下&#xff0c;PyCharm中如果有无法错误或者不符合PEP8规范代码下面会有波浪线&#xff0c;语法错误波浪线为红色&#xff08;如下图的第10行&#xff09;&#xff0c;不符合PEP8规范为浅黄色波浪线&#xff08;如下图的第8行&#xff09;&#xff0c;见下图&#xff1…

Python中下划线的含义及用法

看代码的时候&#xff0c;经常看到各种变量名带各种下划线&#xff0c;有单下划线、双下划线等&#xff0c;主要有五种下划线&#xff08;按照下划线位置命名类型&#xff09;&#xff1a; 单下划线&#xff1a;_单下划线变量名&#xff1a;_var变量名单下划线&#xff1a;var…

Python 中下划线的 6 个作用

初学者看到 Python 中的下划线 _ 时可能会有些懵圈&#xff0c;不知道这个到底是干什么用的&#xff0c;今天就来盘点一下 Python 中的下划线有哪些用处。以后看到下划线时就可以对号入座了。 1、用在 Python 解释器&#xff0c;表示上一次的执行结果 即使不把 Python 用于编程…

html中的:下划线标签、中划线标签、斜体标记、粗体标记

<!-- 下划线标记 --><b>下划线标签&#xff1a;</b><u>u标签是下划线标签</u><br><!-- 中划线标签 --><b>中划线标题&#xff1a;</b><s>s是中划线标签</s><del>del也是中划线标签</del><br…

多种方法在Markdown加入上划线、中划线、下划线

上划线和下划线不是Markdown自身语法&#xff0c;因此需要一点摸索&#xff0c;特将结果记录于此 中划线 中划线是markdown自身语法&#xff0c;实现起来很简单&#xff1a; ~~中划线~~效果&#xff1a; 中划线 下划线 法一&#xff1a;借助Latex公式 $\underline{\text{…

UILabel,文字添加下划线,中划线

//显示下划线 //中划线 // NSDictionary *attribtDic {NSStrikethroughStyleAttributeName: [NSNumber numberWithInteger:NSUnderlineStyleSingle]}; //下划线 NSDictionary *attribtDic {NSUnderlineStyleAttributeName: [NSNumber numberWithInteger:NSUnderlineS…

CSS文本样式(中划线下划线行高之类的还有color也是)

1.颜色 2.对齐方式 3.首行缩进 4.行高 5.下划线&#xff08;装饰&#xff09; 6.文字跟图片对齐 1.颜色 颜色可以用 单词 表示也可以用 #RGB 表示 RGB代表的就是红绿蓝三种颜色 000000-FFFFFF 或者用 color&#xff1a;rgb&#xff08;0&#xff0…

为文字添加下划线和中划线

Android开发中如何给文字添加下划线和中划线呢&#xff0c;先看一下效果图&#xff1a; 下划线&#xff1a; 中划线&#xff1a; 方式一&#xff1a; //添加下划线 // textView.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);//添加中划线textView.getPaint().setFl…

Python中下划线的5种含义

作者&#xff1a;地球的外星人君 链接&#xff1a;https://zhuanlan.zhihu.com/p/36173202 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 分享一篇文章&#xff1a;The Meaning of Underscores in Python。 本文介…

Python中的下划线到底什么意思?

1. 概述 在Python经常能见到含下划线&#xff08;underscore&#xff09;修饰的的变量和方法&#xff08;如__name__&#xff0c;_var等&#xff09;&#xff0c;这些下划线的作用称之为名字修饰&#xff08;name decoration&#xff09;。在Python中&#xff0c;名字修饰通常…