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

全面解析MySQL(4)——三大范式与联合查询实例教程

1.三大范式

概念:数据库三大范式(Normal Forms)是关系型数据库设计中的基本原则,用于减少数据冗余和提高数据一致性

1.1 第一范式(1NF)

定义:确保每一列的原子性,即每一列都是不可再分的最小数据单元 要求:

  • 每个字段只能包含单一值,不能是集合数组
  • 表中不能有重复的列。关系模型的创始人 E.F. Codd 最初提出范式理论时,要求关系表必须有一个主键/联合主键(唯一标识每一行的字段或字段组合)

示例:订单表

订单ID(order_id)客户信息(customer_info)
1张三,四川省XXX市,17392871691
  • 无法单独查询四川省的客户信息(insert into table_name where address = '四川省')
  • 更新客户地址时需要解析字符串(可能需要借助后端额外处理)

修正后示例:

订单ID(order_id)客户姓名(user_name)地址(address)电话号码(tele)
1张三四川省XXX市17392871691

1.2 第二范式(2NF)

定义:在满足第一范式的基础上,消除非主键字段对主键的部分函数依赖(即非主键字段必须完全依赖整个主键/联合主键,而非部分主键)
联合主键(Composite Primary Key):是指由数据库表中两个或多个字段共同组成的主键,用于唯一标识表中的每一行数据。与单字段主键不同,联合主键通过多个字段的组合确保数据的唯一性

示例:学生-课程成绩表
使用学号+课程名唯一标识某一行记录,这两列就是该表的联合主键

学号(student_id)姓名(student_name)性别(sex)课程名(course_name)学分(credit)分数(score)
1张三MySQL480
2李四Java475
1张三Java470
3王五MySQL485

姓名、性别两列由学号确定,和课程名没关系,即姓名学号两列部分依赖学号学分课程名确定,和学号没关系,即学分这列部分依赖课程名

  • 数据冗余:姓名、性别、学分三列在表中重复出现,造成大量冗余
  • 更新异常:更新Java这门课的学分时,如果因为某些意外而中断更新,就会导致该表中Java的学分不一致

修正后示例:
学生表

学号(id)姓名(name)性别(sex)
1张三
2李四
1张三
3王五

课程表

课程ID(id)课程名(course_name)学分(credit)
1MySQL4
2Java4

分数表

学号课程ID(id)分数(score)
1180
1270
2275
3185

1.3 第三范式(3NF)

定义:在满足第二范式的基础上,消除非主键字段之间的传递依赖(即非主键字段不能依赖于其他非主键字段)

示例:员工部门表

员工ID姓名部门ID部门名称
1张三研发部北京总部
2李四市场部上海分部
3王五研发部北京总部

部门名称依赖于部门ID,而不是直接依赖于员工ID,存在传递依赖:员工ID → 部门ID → 部门信息

  • 数据冗余:研发部名称重复存储
  • 更新异常:修改部门所在地需要更新多条记录

2.联合查询

2.1 概述

使用场景:在数据设计时由于三大范式的要求,数据被拆分到多个表中,那么要查询⼀条数据的完整信息,就要从多个表中获取数据,这时就要使用联合查询

笛卡尔积(Cartesian Product):联合查询的基础,指两个集合中所有可能的有序组合。在MySQL中,当联合查询未指定关联条件时,查询结果会返回所有表的行组合(列相加,行相乘)

学生表

学号姓名性别班级编号
1张三1
2李四3
3王五2

班级表

编号班级
1Java班
2C++班
3Python班

两表进行笛卡尔积

学号姓名性别班级编号编号班级
1张三11Java班
1张三12C++班
1张三13Python班
2李四31Java班
2李四32C++班
2李四33Python班
3王五21Java班
3王五22C++班
3王五23Python班

笛卡尔积生成的结果集可能包含无效或冗余数据。无效数据通常指不符合业务逻辑、无实际意义或违反约束条件的组合。上述笛卡尔积的结果集中,只有学生表的班级编号与班级表的编号相同的记录才有实际意义

学号姓名性别班级编号编号班级
1张三11Java班
2李四33Python班
3王五22C++班

构造练习数据:

-- 创建学生表
create table classes (class_id int primary key auto_increment,class_name varchar(50) not null,teacher_name varchar(50),created_at timestamp default current_timestamp
);
-- 插入班级数据
insert into classes (class_name, teacher_name) values
('计算机科学1班', '张老师'),
('计算机科学2班', '李老师'),
('数学实验班', '王老师'),
('英语提高班', '赵老师'),
('物理竞赛班', NULL);  -- 这个班级暂时没有分配老师
--创建班级表
create table students (student_id int primary key auto_increment,student_name varchar(50) not null,gender char(1) check (gender in ('M', 'F')),age int,class_id int,enrollment_date date,foreign key (class_id) references classes(class_id) on delete set null 
);
-- 插入学生数据
insert into students (student_name, gender, age, class_id, enrollment_date) values
('张三', 'M', 20, 1, '2023-09-01'),
('李四', 'M', 21, 1, '2023-09-01'),
('王五', 'F', 19, 2, '2023-09-01'),
('赵六', 'F', 20, 2, '2023-09-02'),
('钱七', 'M', 22, 3, '2023-09-03'),
('孙八', 'F', 20, 3, '2023-09-03'),
('周九', 'M', 21, NULL, '2023-09-04'),  -- 这个学生尚未分班
('吴十', 'F', 19, NULL, '2023-09-05'); -- 这个学生尚未分班

2.2 内连接(inner join)

定义:在笛卡尔积的有效结果集基础上,仅返回满足条件的记录(如果不指定其他条件,内连接的结果集和笛卡尔积的有效结果集完全一样)
在这里插入图片描述

基础语法:

#语法1
select 字段 from1 别名1,2 别名2 where 连接条件 and 其他条件;
#语法2
select 字段 from1 别名1 [inner] join2 别名2 on 连接条件 where 其他条件;

示例:查询(student_id <= 3)的学生信息和班级信息
写法1: 在这里插入图片描述
写法2: 在这里插入图片描述

2.3 外连接

2.3.1 左外连接(left outer join)

定义:返回左表的所有/指定行,即使在右表中没有匹配的行(右表中未匹配的部分用null填充)。换言之,在有效笛卡尔积基础上增加未能与右表匹配的行,这些新增行的右表部分用null值填充在这里插入图片描述

基础语法:

select 字段 from 表名1 left outer join 表名2 on 连接条件;

示例:
在这里插入图片描述

2.3.2 右外连接(right outer join)

定义:返回右表的所有行,即使在左表中没有匹配的行(左表中未匹配的部分用null填充)。换言之,在有效笛卡尔积基础上增加未能与左表匹配的行,这些新增行的左表部分用null值填充在这里插入图片描述

基础语法:

select 字段 from 表名1 right outer join 表名2 on 连接条件;

示例:
在这里插入图片描述

2.3.3 全外连接(full outer join,MySQL不支持)

定义:返回左表和右表的所有行,未匹配的部分用null填充。若某行在另一表中有匹配,则显示匹配值在这里插入图片描述

2.4 自连接

使用场景:实现行与行之间的比较
在这里插入图片描述
定义:自连接(Self Join)是SQL中的一种特殊连接操作,指同一张表通过别名(as)模拟成两张表,将行与行之间的关系转换为列与列之间的关系,并根据关联条件进行连接查询在这里插入图片描述

基础语法:

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

示例:查询数学成绩高于语文成绩的记录
在这里插入图片描述

2.5 子查询(Subquery)

定义:指一个SQL语句查询内部嵌套另一个完整的select查询语句

构造数据

#学生表
create table students (student_id int primary key,name varchar(50) NOT NULL,class_id int,gender char(1),age int
);
insert into students values
(101, '张三', 1, '男', 18),
(102, '李四', 1, '女', 17),
(103, '王五', 2, '男', 19),
(104, '赵六', 2, '女', 18),
(105, '钱七', 3, '男', 17);
#成绩表
create table scores (score_id int primary key,student_id int,subject varchar(20),score int,foreign key (student_id) references students(student_id)
);
insert into scores values
(1, 101, '数学', 85),
(2, 101, '英语', 78),
(3, 102, '数学', 92),
(4, 102, '英语', 88),
(5, 103, '数学', 65),
(6, 103, '英语', 72),
(7, 104, '数学', 55),
(8, 104, '英语', 91),
(9, 105, '数学', 82),
(10, 105, '英语', 77);

2.5.1 单行子查询

定义:单行子查询指返回单个值(一行一列)的子查询,主查询将子查询结果作为标量值使用

基础语法:

select 列名 from table1 where 列名 = (select 列名 from table2...);

示例:查询张三的数学成绩

#先在students表中查询到张三的student_id
select student_id from students where name = '张三';
#再在scores表中利用查到的student_id来查询张三的数学成绩
select subject,score from scores where subject = '数学' and student_id = 101;#合并后的子查询
select subject,score from scores where subject = '数学' and student_id = 
(select student_id from students where name = '张三');

在这里插入图片描述

2.5.2 多行子查询

定义:主查询将子查询返回的多行单列结果集作为条件使用

基础语法:

select 列名 from table1 where 列名 in (select 列名 from table2...);

示例:查询数学成绩大于80的学生姓名

#先在scores表中查询数学成绩大于80的student_id
select student_id from scores where subject = '数学' and score > 80;
#再在students表中利用查到的student_id来姓名
select name from students where student_id in (101,102,105);#合并后的子查询
select name from students where student_id in 
(select student_id from scores where subject = '数学' and score > 80);

在这里插入图片描述

2.5.3 from子句中的子查询

定义:子查询作为临时表嵌入from子句(称为派生表),需指定别名

示例:查询成绩大于平均成绩的记录

select * from scores as s,(select avg(score) as avg_score from scores) as a 
where s.score > a.avg_score;

在这里插入图片描述

2.6 合并查询

定义:合并查询(Set Operation Queries)是SQL中用于组合多个select结果集的操作
要求:需要查询的列数和数据类型匹配,列名不影响

基础语法1:

select col_1,col_2 ... from table_1
union
sekect col_1,col_2 ... from table_2;
  • 自动去除重复行

在这里插入图片描述
基础语法2:

select col_1,col_2 ... from table_1
union all 
sekect col_1,col_2 ... from table_2;
  • 保留重复行
  • 性能优于union

在这里插入图片描述

http://www.lryc.cn/news/602079.html

相关文章:

  • Deep Learning_ Foundations and Concepts-Springer (2024)【拜读】前向编码器20章
  • 【CSS】设置表格表头固定
  • 深度学习----视觉里程计
  • 工业场景工服识别准确率↑32%!陌讯多特征融合算法实战解析
  • STM32 usb HOST audio USB 音频设备 放音乐
  • Pandas 里的分箱操作
  • 负载均衡集群HAproxy
  • MCP工作原理
  • Java-泛型类的定义与使用
  • 浅谈面试中的递归算法
  • 【Linux】编辑器vim和编译器gcc/g++
  • 解析分区、挂载与块设备:Linux 存储管理核心命令详解
  • 近屿智能正式发布AI得贤招聘官的AI面试官智能体6.3版本:交付替代人类面试官的打分结果
  • 零基础学习性能测试第九章:全链路追踪-项目实操
  • Jenkins + SonarQube 从原理到实战一:基于 K8s 部署与使用(含中文插件与 Python 扫描)
  • 力扣1457. 二叉树中的伪回文路径
  • 力扣面试150(42/150)
  • 旧物回收小程序:科技赋能,让旧物回收焕发生机
  • 软件测试之功能测试
  • 6种将iPhone照片传输到Windows 10电脑的方法
  • 跨境协作系统文化适配:多语言环境下的业务符号隐喻与交互习惯
  • 快速了解MySQL
  • Ubuntu lamp
  • 分布式IO选型指南:2025年分布式无线远程IO品牌及采集控制方案详解
  • 四、计算机组成原理——第3章:存储系统
  • 低速信号设计之 SMBUS 篇
  • Power Query概述及导入多源数据方法
  • 从fork到exit:剖析Linux进程的诞生、消亡机制
  • C盘清理大赛技术指南
  • 凸优化:凸函数的一些常用性质