当前位置: 首页 > news >正文

数据库-联表查询

先赞后看,养成习惯!!! ^ _ ^ ❤️ ❤️ ❤️
码字不易,大家的支持就是我坚持下去的动力,点赞后不要忘记关注我哦

📘 本系列文章为本人在学习路上遇到的问题和解决方法,在这里撰写成文是为了巩固知识和帮助其他友友

个人主页🔍:小许学java

1. 目标

了解联合查询的计算过程

掌握内连接、左外连接、右外连接和自连接查询

掌握子查询和合并查询

掌握插入查询结果和根据拆线呢结果创建表

2. 简介

2.1 为什么要使用联合查询

在数据设计时由于范式的要求,数据被拆分到多个表中,那么要查询一条数据的完整信息,就要从多个表中获取数据,如下图所示:要获取学生的基本信息和班级信息就要从学生表和班级表中获取,这时就需要使用联合查询,这里的联合指的是多个表的组合。

学生表:

编号姓名性别班级编号

1

张三1
2李四1
3王五2

 

班级表:

编号班级
1Java1班
2Java2班
3Java3班

2.2 多表联合查询MYSQL内部是如何进行计算的

参与查询的所有表取笛卡尔积,结果集在临时表中

编号姓名性别班级编号编号班级
1张三11Java1班
1张三12Java2班
1张三13Java3班
2李四11Java1班
2李四12Java2班
2李四13Java3班
3王五21Java1班
3王五22Java2班
3王五23Java3班

观察哪些记录是有效数据,根据两个表的关联关系过滤掉无效的数据

编号姓名性别班级编号编号班级
1张三11Java1班
2李四11Java1班
3王五22Java2班

如果联合查询表的个数越多,表中的数据量越大,临时表就会越大,所以根据实际情况确定联合查询表的个数。

2.3 构造练习案例数据

create DATABASE pricaice;
-- 1. 创建课程表 (course)
CREATE TABLE course (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- 2. 创建班级表 (class)
CREATE TABLE class (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- 3. 创建学生表 (student)
CREATE TABLE student (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(50) NOT NULL,sno VARCHAR(20) NOT NULL UNIQUE,  -- 学号唯一age INT NOT NULL,gender TINYINT NOT NULL,          -- 1:男, 0:女 或其他约定enroll_date DATE NOT NULL,class_id INT NOT NULL,FOREIGN KEY (class_id) REFERENCES class(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- 4. 创建成绩表 (score)
CREATE TABLE score (id INT AUTO_INCREMENT PRIMARY KEY,score DECIMAL(5,2) NOT NULL,      -- 支持小数成绩,如 98.5student_id INT NOT NULL,course_id INT NOT NULL,FOREIGN KEY (student_id) REFERENCES student(id) ON DELETE CASCADE,FOREIGN KEY (course_id) REFERENCES course(id) ON DELETE CASCADE,UNIQUE KEY unique_student_course (student_id, course_id)  -- 防止重复录入同一门课成绩
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- 插入课程数据
INSERT INTO course (name) VALUES 
('Java'), 
('C++'), 
('MySQL'), 
('操作系统'), 
('计算机网络'), 
('数据结构');-- 插入班级数据
INSERT INTO class (name) VALUES 
('Java001班'), 
('C++001班'), 
('前端001班');-- 插入学生数据
INSERT INTO student (name, sno, age, gender, enroll_date, class_id) VALUES
('唐三藏', '100001', 18, 1, '1986-09-01', 1),
('孙悟空', '100002', 18, 1, '1986-09-01', 1),
('猪悟能', '100003', 18, 1, '1986-09-01', 1),
('沙悟净', '100004', 18, 1, '1986-09-01', 1),
('宋江', '200001', 18, 1, '2000-09-01', 2),
('武松', '200002', 18, 1, '2000-09-01', 2),
('李逹', '200003', 18, 1, '2000-09-01', 2),
('不想毕业', '200004', 18, 1, '2000-09-01', 2);INSERT INTO score (score, student_id, course_id) VALUES
(70.5, 1, 1), (98.5, 1, 3), (33, 1, 5), (98, 1, 6),
(60, 2, 1), (59.5, 2, 5),
(33, 3, 1), (68, 3, 3), (99, 3, 5),
(67, 4, 1), (23, 4, 3), (56, 4, 5), (72, 4, 6),
(81, 5, 1), (37, 5, 5),
(56, 6, 2), (43, 6, 4), (79, 6, 6),
(80, 7, 2), (92, 7, 6);

2.4 案例:一个完整的联合查询过程

查询学生姓名为孙悟空的详细信息,包括学生个人信息和班级信息

1. 确定参与查询的表,学生表和班级表

select * from student, class;

2. 确定连接条件,student表中的class_id与class表中的id列的值相等

select * from student,class where student.class_id=class.id;

3. 加入查询条件

select * from student,class where student.class_id=class.id and name='宋江';

由于两个表中都有name列,所有MySQL不清楚具体要使用哪个列,这时可以用“表名.列号”的方式指定具体的列。

select * from student,class where student.class_id=class.id and student.name='宋江';

4. 精减查询结果字段

SELECT student.id,student.name,student.sno,student.age,student.gender,student.enroll_date,class.name AS class_name
FROM studentINNER JOIN class ON student.class_id = class.id
WHERE student.name = '宋江';

5. 可以为表名指定别名

selects.id, s.name, s.sno, s.age, s.gender, s.enroll_date, c.name 
fromstudent s , class c 
wheres.class_id = c.id 
ands.name = '宋江';

3. 内连接

3.1 语法

select 字段 from 1 别名1, 2 别名2 where 连接条件 and 其他条件

select 字段 from 1 别名 1 [ inner ] join 2 别名 2 on 连接条件 where 其他条件 ;

3.2 示例

查询"唐三藏"同学的成绩

select s.name,sc.score from student s join score sc on sc.student_id=s.id where s.name='唐三藏';

查询所有同学的总成绩,及同学的个人信息

select s.name,sum(sc.score) from student s,score sc where sc.student_id=s.id group by(s.id);

Group by 使用了student.id进行分组,查询表列表中的student.name没有出现在Group by分组
中,也没有包含在聚合函数中,这是因为SQL规定在Group by分组查询时,如果查询列表中的列没
有出现在GROUP BY⼦句中,但这些列的值在每个分组内部是相同的,那么它们可以出现在查询结果中。
查询所有同学每门课的成绩,及同学的个人信息
 SELECTs.id AS id,s.name AS 姓名,s.sno AS 学号,s.gender AS 性别,c.name AS 班级,sc.score AS 分数
FROMstudent s,course c,score sc
WHEREs.id = sc.student_idAND c.id = sc.course_id
ORDER BYs.id;

结果集中没有"不想毕业"同学的成绩,因为score表中没有这位同学的记录

4. 外连接

外连接分为左外连接、右外连接和全外连接三种类型,MySQL不支持全外连接。

左外连接:返回左表中的所有记录和右表中匹配的记录。如果右表中没有匹配的记录,则结果集中对应字段会显示为NULL。

右外连接:与左外连接相反,返回右表的所有记录和左表中匹配的记录。如果左表中没有匹配的记录,则结果集中对应字段会显示为NULL。

全外连接:结合了左外连接和右外连接的特点,返回左右表中的所有记录。如果某一边表中没有匹配的记录,则结果集中对应字段会显示为NULL。

4.1 语法

-- 左外连接,表1完全显⽰ 
select 字段名 from 表名1 left join 表名2 on 连接条件;
-- 右外连接,表2完全显⽰ 
select 字段 from 表名1 right join 表名2 on 连接条件;

4.2 示例

查询没有参加考试的同学信息

左连接以JOIN左边的表为基准,左表显示全部记录,右表中没有匹配的记录用NULL填充

select s.id, s.name, s.sno, s.age, sc.* from student s LEFT JOIN score 
sc on sc.student_id = s.id;

过滤参加了考试的同学

select s.* from student s left join score sc on sc.student_id=s.id where sc.score is null;

查询没有学生的班级

select * from student s right join class c on c.id=s.class_id;

过滤有学生的班级

select c.* from student s right join class c on c.id=s.class_id where s.id is null;

5. 自连接

5.1 应用场景

自连接是自己与自己取笛卡尔积,可以把行转化成列,在查询的时候可以使用where条件对结果进行过滤,或者说实现行与行之间的比较。在做表连接时为表起不同的别名。

//不为表指定别名
select * from score,score;
ERROR 1066 (42000): Not unique table/alias: 'score'
//指定别名
mysql> select * from score s1,score s2;

5.2 示例

显示所有"MySQL"成绩比"JAVA"成绩高的成绩信息

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

结合在一起查询

select s1.* from score s1, score s2, course c1,course c2
where s1.student_id = s2.student_id
and s1.course_id = c1.id
and s2.course_id = c2.id 
and s1.score > s2.score
and c1.`name` = 'MySQL'
and c2.`name` = 'Java';

6. 子查询

子查询是把一个SELECT语句的结果当做别的一个SELECT语句的查询条件,也叫嵌套查询。

6.1 语法

select * from table1 where col_name1 {= | IN} (select col_name1 from table2 where col_name2 {= | IN} [(select ...)] ...
)

6.2 单行子查询

嵌套的查询中只返回一行数据

示例:查询与"不想毕业"同学的同班同学。

select * from student where class_id=(select class_id from student where name='不想毕业');

6.3 多行子查询

嵌套的查询中返回多行数据,使用[NOT] IN 关键字。

示例:查询"MySQL"或"Java"课程的成绩信息

 select * from score where course_id in (select id from course where name="Java" or name="MySQL");

使用NOT IN 可以查询除了"MySQL"或"Java"课程的成绩

select * from score where course_id not in (select id from course where name="Java" or name="MySQL");

6.4 多列子查询

单列子查询或多行子查询都只返回一列数据,多列子查询中可以返回多个列的数据,外层查询与嵌套的内层查询的列要匹配。

示例:查询重复录入的分数

插入重复的分数:score, student_id, course_id列重复(上述MySQL语句设置了值必须唯一,所以可以自己在创建一个数据库来验证)。

insert into score(score, student_id, course_id) values-> (70.5, 1, 1),(98.5, 1, 3),(60, 2, 1);
SELECT * FROM score WHERE (score, student_id, course_id ) IN ( SELECT score, student_id,course_id FROM score GROUP BY score, student_id, course_id HAVINGcount( 0 ) > 1 );

6.5 在from子句中使用子查询

示例:查询所有比"Java001班"平均分高的成绩信息

//第一步查出Java001班的平均分
select avg(sc.score) score from student sjoin class c on s.class_id=c.idjoin score sc on s.id=sc.student_idwherec.name='Java001班';

//把以上查询作为临时表,与真是表进行比较
select * from score s,(select avg(sc.score) score from student sjoin class c on s.class_id=c.idjoin score sc on s.id=sc.student_idwherec.name='Java001班') tmpwhere s.score > tmp.score;

tmp是临时表的表明

7. 合并查询

在实际应用中,为了合并多个select操作返回的结果,可以使用集合操作符union,union all

7.1 创建新表并初始化数据

create table student1 like student;insert into student1 (name, sno, age, gender, enroll_date, class_id) values('唐三藏', '100001', 18, 1, '1986-09-01', 1),('刘备', '300001', 18, 1, '1993-09-01', 3),('张飞', '300002', 18, 1, '1993-09-01', 3),('关羽', '300003', 18, 1, '1993-09-01', 3);
select * from student1;

7.2 Union

该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行。

示例:查询student表中id<3的同学和student1表中的所有同学

结果集中有两张表数据,但是唐三藏只返回了一条数据 
select * from student where id<3 union select * from student1;

7.3 Union all

该操作符用于获取两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行

//该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行
select * from student where id<3 union all select * from student1;

8. 插入查询结果

8.1 语法

INSERT INTO table_name [(column [, column ...])] SELECT ...

8.2 示例

将student表中C++001班的学生复制到student1表中

insert into student1 (name, sno, age, gender, enroll_date, class_id)select s.name, s.sno, s.age, s.gender, s.enroll_date, s.class_idfrom student s,class c where s.class_id=c.id and c.name='C++001班';
select * from student1;

 

http://www.dtcms.com/a/496034.html

相关文章:

  • 德化网站建设新开的网页游戏大全
  • 仿网站建设平凉哪家做企业网站
  • 长沙岳麓区做网站湘潭做网站选择磐石网络
  • 简述网站设计规划的步骤响应式网站开发
  • CF2124B Minimise Sum 题解
  • 招标网站有哪些成长厉程网站
  • 购物网站哪个最便宜网站建设 统一质量标准
  • 多模态大模型OCR幻觉缓解思路:DianJin-OCR-R1通过“再看一眼”图像减轻幻觉
  • JJJ:SD 卡中的 OCR(Operating Conditions Register)寄存器
  • 手机网站图片切换网站设计师需要什么知识与技能
  • 20251017流程控制Demo
  • 浔川 AI 翻译 v7.0 公测版介绍(即将上线)
  • CPU性能对GPU服务器有影响吗?
  • 安徽省港航建设投资集团网站牛商网网站后台
  • 永磁体的磁导率
  • 亚马逊网站建设进度计划网站怎么做落款
  • h5模板网站西安到北京的高铁
  • wordpress建站两秒打开论坛模板建站
  • AI服务器工作之服务器的种类分类
  • 校园网站建设的目的中国建设机械教育协会网站
  • nextjs 接入 谷歌分析
  • asp.net core CVE-2025-55315漏洞验证修复
  • 建网站要多少费用加强信息管理 维护网站建设
  • 读书笔记:《2049未来10000天的可能》
  • 多GPU服务器在大型量子比特状态向量模拟中的实现方式
  • 网站下载器国际论坛网站模板
  • ui设计公司审美积累 | 金融人工智能与用户体验 用户界面仪表盘设计
  • 盗版小说网站怎么做售卖网站建设实验报告
  • 工业互联与设备IOT助力生产制造实践分享
  • 网站服务器试用网站定做公司