MySQL数据分析进阶(十二)设计数据库——PART2

news2024/11/15 15:25:45

※食用指南:文章内容为‘CodeWithMosh’SQL进阶教程系列学习笔记,笔记整理比较粗糙,主要目的自存为主,记录完整的学习过程。(图片超级多,慎看!)

【中字】SQL进阶教程 | 史上最易懂SQL教程!10小时零基础成长SQL大师!!icon-default.png?t=N7T8https://www.bilibili.com/video/BV1UE41147KC/?spm_id_from=333.1007.0.0&vd_source=b287f1f4a1fa54cc438e31a0f87ef4e2

目录:

第十二章:设计数据库——PART2

9、NORMALIZATION——标准化

10、FIRST NORMAL FORM(1NF)——第一范式

11、LINK TABLES——链接表

12、SECOND NORMAL FORM(2NF)——第二范式

13、THIRD NORMAL FORM(3NF)——第三范式

14、MY PRAGMATIC ADVICE——实用建议

15、DON’T MODEL THE UNIVERSE——不要对什么都建模

16、FORWARD ENGINEERING A MODEL——模型的正向工程

17、SYNCHRONIZING A MODEL——数据库同步模型

18、REVERSE ENGINEERING A DATABASE——模型的逆向工程


第十二章:设计数据库——PART2

9、NORMALIZATION——标准化

标准化:审查我们的设计,确保它遵循一些防止数据重复的预定义规则的这一过程

总共有七条范式(七范式),对于几乎99%的应用场景,只需要应用前三条范式

确保设计是最优的,不允许存在冗余或重复的数据

因为冗余增加了数据库的大小,使插入、更新和删除操作复杂化

如果某个名字在许多不同的地方重复,决定改名就需要更新好几个不同的地方,会造成无效报告

10、FIRST NORMAL FORM(1NF)——第一范式

第一范式:要求一行中的每个单元格都应该有单一值且不能出现重复列

courses中tags违反了第一范式

我们会在列中存储多个标签,并用逗号分隔它们,所以这个单元格或属性中会存在多个值

❗如果使用标签1、标签2、标签3这样的多个列是否可以

我们无法提前知道每门课有多少个标签,如果将来在课程中添加标签4的话,就必须返回修改设计,也不能保证这种情况不会再次发生

这种方法不具有扩展性

解决方法:需要把标签列从这张表中拎出来,并将其以一个名为tags的单独表建模,然后为tags和courses添加多对多关系

添加新表

设置属性:取决于数据库中有多少标签

需要在业务时搞清楚的问题,这些标签是由终端用户还是管理员创建

如果是终端用户,可能会迅速增加

先假设是由管理员创建并且只有50-60个标签——TINYINT(微整数型)

11、LINK TABLES——链接表

需要在课程和标签表之间添加“多对多“关系,但关系型数据库中并没有”多对多“关系,只有一对一、一对多关系

实现多对多,需要引入一张新的表——链接表(会有两段一对多关系,和注册表一样)

逻辑上,学生和课程之间是一种多对多的关系

链接表在关系型数据库中是很常见的

①建立新表

②把课程表的tags删掉

现在数据库就满足了第一范式

首先没有标签1、标签2、标签3这样的重复列,在一列中也没有多个值

所有标签都存在了一个地方,如果想重命名标签,只需要更新标签表中的一条记录

而在之前设计中,标签作为字符串重复了,在课程表中,每个标签都出现好多次,这样前端会在很多不同地方重复出现

如果想为前端改名,就必须更新好几条课程记录,每次进行更新或删除操作时,MySQL会锁定一行或多行,如果套用之前的设计,行会白白被锁定

想重命名一个标签,却要锁定一门课程,不合理

想要重命名一个标签,标签行应该是唯一需要锁定的行

12、SECOND NORMAL FORM(2NF)——第二范式

第二范式:一组关系必须符合第一范式,并且它不能有任何取决于这组关系任何候选键的任何真子集的非主属性

要求每张表都应该有一个单一目的只能代表一种且仅有一种实体类型,而那种表中的每一列都应该用来描述那个实体

课程表有course_id、name、price这些列,所以他目的单一:存储课程记录

此表中的每一列都是课程的一种属性

❗如果有一列叫“注册日期“怎么办

注册日期:不是课程属性或课程性质

因为一门课可以容纳多名学生,每名学生可能会有不同的注册日期

所以这列不属于这张表,它不是一门课的属性,而是注册的属性,这就是引入注册实体并在其中添加了日期属性的原因。

简言之,第二范式:一张表中的每一列都应该在描述该表代表的实体

如果有一列描述了其他的东西,应该拿掉它,并放入一张单独表

🔺其他例子:

在这张orders表中,有order_id、date、customer_name,这不符合第二范式

这张表的目的是存储订单,order_id、date是订单属性,属于这张表,描述了一张订单;customer_name描述了一名顾客,而不是订单

在这种设计下,如果一名顾客订购了多笔订单,名字就会重复出现,会产生两个问题:

①浪费空间

②更新辛苦(如果想更新一个客户名,就必须在好几个地方更改它)

因此customer_name不属于orders表

应该拿出来,放到customers表中

现在顾客名被储存在了一个地方,没有浪费空间,如果想更改名字,只需要更新一条记录即可

 

🔺有时候不是上来就很清晰

如果一开始该列是customer,而不是customer_name怎么办

错误理解:每个订单都有一个顾客,所以它确实是订单的一种属性,所以这一列属于这张表

在这种设计下,顾客名会重复,只要出现这个现象,意味着设计没有标准化

能够单独存储但不会重复生成顾客名的地方——顾客表

需要一张单独表来存储所有顾客,在根据订单表中的customer_id引用它们

这也是不要更新主键的原因

表中有重复的customer_id,但那是重复数量最少的情况了,重复了4个字节长的整数,而不是50或者100字符长的顾客名

🔺回到案例:

这里的instructor不属于这张表

同一讲师教多门课,名字也会重复,也必须在好几个地方更改

①新建instructors表

②建立关系,并删除原instructor列

③设置好外键(如果一名讲师有授课,就无法删除那名讲师)

④通过顶部排列菜单整理模型

13、THIRD NORMAL FORM(3NF)——第三范式

第三范式:实体或者表首先应该符合第二范式,表中的所有属性只能由那组关系的候选键决定,而不能是任何非主属性

这张invoices表中有三列:invoice_id、payment_total、balance

❗是否可以通过invoice_id-payment_total得到balance

Balance取决于invoice_id、payment_total,如果这两个列的值变了,就必须重新计算

如果改变其中一个值,但忘了更新balance,数据就不一致了

这条记录中并不能了解实际balance是多少,该选择相信balance的值,还是用invoice_id-payment_total

应该删掉balance列,我们不需要它

第三范式:表中的列不应派生自其他列

🔺另一个例子

full_name不应该出现在这,因为它违反了第三范式

应该通过结合名字和姓氏得到它

第三范式和其他范式一样:减少重复,提高数据完整性

14、MY PRAGMATIC ADVICE——实用建议

不要担心记住这些标准化规则:第一条或者第二条规则,区别在哪(除非考试,需要回答这类问题),这些问题在现实世界中没有应用机会

当和别人合作实际项目时,只需要专注于消除冗余就可以了,不需要对每张表和每列逐个应用标准化规则,无人关心给定表是第二还是第三范式

就如看到这些重复值,且这些值不像是1、2、3、4这样的外键时

意味着设计没有标准化,至于违反了第几范式并不重要,无人关心,重点在如何消除重复

🔺①例子:

顾客表中有3列,customer_id、name、shipping_address

如果有要求,要支持多个收货地址,设计就会出问题

对于一位给定顾客,必须重复他们的名字来添加多个收货地址

如果还有两列(电邮、生日),为这名顾客存储多个收货地址,就必须要重复所有值,如何处理

①首先思考逻辑实体和这里的关系

顾客和地址是一对多的关系

一名顾客可以有很多收货地址

一个收货地址仅针对一名顾客

②逻辑模型转为实体模型,得到一下两张表

 

没有考虑任何标准化规则以及如何通过到处移动列来应用它们,只考虑逻辑实体和它们之间的关系

所以如果遵循同样的过程,不必顾虑标准化规则

先从逻辑和概念模型开始,不要直接跳到创建表

再次强调:业务需求

在这个例子中,假设需要支持多个收货地址的需求,基于这个要求,最初的设计违反了第三范式

但如果没有这个要求,这样的设计是完全合理的,所以不要盲目套用标准化规则,永远要把需求考虑进去

15、DON’T MODEL THE UNIVERSE——不要对什么都建模

许多数据建模人员犯的错:总是视图泛化模型,以便支持未来的需求

大多数时候,未来的需求只存在于脑中,实际不会发生

最终创建了一个过于复杂且没用的模型告终

(无视项目范围,无视项目背景,无视业务需求,对所有大大小小的事件都建模,最终超大的模型且除他以外无人能懂)

“这个模型可以处理所有未来需求,不需要任何更改“(试图一劳永逸)

有三张表(EAV):Entities、Attributes、Values

所有事物都是实体,都放Entities(实体表)

所有东西都有属性和值,存储在Attributes(属性表)、Values(值表)

本质是在关系型数据库上又建立了一个关系型数据库——第六范式

虽然理论上确实有点优势,现实中制造了一个没人能收拾的巨大混乱

如果想选择一条学生记录,首先要从三个表拿到数据,然后在分组数据,过于浪费时间和空间

只需要为现下问题指定最佳解决方案就可以,而不是可能永远不会发生的未来问题

🔺现实世界中

人们可能改法定名字,那就不要在顾客表中增加“过去的名字”,除非这对你的问题域真的很重要

人们会搬家,如果你只需知道顾客的当前住址,就不要想着支持多个地址

不要什么都要建模,或者太过参照现实世界建模

为你的问题域建模就好了,建立在当下的需求之上,而不是复杂的现实世界

别想着万一发生这个、发生那个,万一没有发生呢,最后得到一个负担很重还得拖拽很长一段时间的设计,就跑不快,在应用中也很难增添新特色

一切从简,简单才是最高境界

不要为设计了一个复杂的模型骄傲

拿到复杂模型并不断简化到其他人都做不到的程度才是真正值得骄傲的

这样就有了一个漂亮的模型,能以最佳的方式支持当下的需求,代码漂亮又不复杂,查询执行很快,所有人都能看懂这个设计,也能为了支持未来需求很轻松地拓展模型

永远无法预测所有未来需求,因为这取决于业务、取决于CEO的想法,而不是程序员的想法

未来有变,也总可以写查询修改数据模型,并在必要时迁移数据

16、FORWARD ENGINEERING A MODEL——模型的正向工程

目前建立的还只是一个模型,不是数据库

如何把模型转化为真实的物理数据库

①在数据库菜单中打开正向工程

②选择我们的连接

③保留所有默认设置不变

默认情况下连接的应该是MySQL工作台主页

如果密码没存,可能还需要输入密码

④设置这个导向要生成的脚本的选项

多数时候保持设置不变就好,除非知道自己在做什么

⑤选择要编写脚本的对象类型

目前为止,只在实体模型中创建了表,但也可以创建视图、存储历程(如存储过程和函数)、触发器和用户对象,但现在先不用考虑其他这些对象

⑥选择显示过滤器,从而编写对象中排除一张或多张表

默认情况下,所有的表都会被选中,可以排除一张或多张表,只用选中并移动到排除对象列表中,也可把它移回要处理的对象列表中

⑦这就是这个向导为创建数据库生成的脚本了(学校数据库、所有表)

暂时不用纠结语句细节

⑧保存为文件:可以保存为脚本文件,并录入源代码控制资源库

复制粘贴后返回MySQL工作台,粘贴到查询窗口中

⑨点击NEXT,向导会生成这个数据库

⑩回到会话,刷新导航面板

17、SYNCHRONIZING A MODEL——数据库同步模型

❗已经建立好数据库,想做任何更改怎么办,想添加一张新表或修改一张现有的表

在设计模式下打开这些表,然后可以做任何必要的更改(添加一列、修改、删除、重命名)

限于你是唯一使用这个数据库的人,可以用这个方法,没有其他人会使用

但在大中型组织架构中,通常有好几个服务器,模拟了实际生产环境

生产环境:用户访问我们的应用程序或数据库的地方

阶段环境:非常接近生产环境

测试环境:仅仅为测试用

开发环境

每个环境都有一个或多个服务器

所以任何时候开发人员想要对这些数据库做任何更改,需要能够在其他数据库上复制相同的更改,在不同环境里这些数据库应该具有一致性

❗如何办到

①回到模型,做出更改然后将这个模型与数据库同步

在enrollments表中添加一个新列——优惠券

假设学生在注册时要使用的优惠券

为了保持一致使用VARCHAR(50)属性;设置非空值(不是每个人都能在注册时使用优惠券)

②随后选择同步模型

在没有数据的时候使用正向工程,也就是用一个模型生成一个数据库

有一个数据库想,想将数据库与模型同步选择同步模型

③选择连接到本地计算机的一个数据库

如果我是组织的开发人员,还可以访问测试环境、阶段环境、生产环境

所以此出不选择本地实例连接,选择连接到一个测试环境的数据库

④保留所有默认设置不动

⑤MySQL工作台检测到我们正在使用学校这个数据库

⑥检测到了需要更新的表

因为更新了注册表,会有一个绿色箭头

注册表和课程表有相关联,课程表可能也会受影响,课程和课程标签之间也是

因为两个表有关系,MySQL工作台不得不暂时取消这两个表之间的关系,以便在注册表中应用必要更改,然后再次启用

⑦数据库代码自动更新

可以看到一堆ALTER TABLE、DROP FOREIGN KEY语句,它们用于消除表之间的关系⑧

在下面可以看到ALTER TABLE语句、ADD COLUMN `coupon` VARCHAR(50)

首先关系先被禁用,然后再注册表中添加一个新列,最后又启用了这些关系

⑧可以执行脚本查看变动

更好的方法是将脚本保存在我们的文件系统中,然后录入GIT这样的源代码控制资源库中,这样可以明确我们对数据库做了什么变动,然后可以将相同的变动复制到其他数据库,我们只需要在那些数据库服务器中执行那个脚本

(本案例中暂不用管这些,直接执行)

18、REVERSE ENGINEERING A DATABASE——模型的逆向工程

❗如果想更改一个没有模型的数据库怎么办

比如sql_store,这个数据不想school那么全面,如何更改这个数据库

第一次需要这么做的时候,为这个数据库进行逆向工程,来创建一个模型,然后使用该模型用于任何未来更改

①先关闭创建的模型

非常重要,当我们对这个数据库进行逆向工程,如果一个模型已经打开了,MySQL工作台会把数据添加到这个模型上

虽然无大碍,但最好还是为每个数据库配备单独模型,可以在一个模型中包含多个数据库,这些数据库高度相关的时候这么做,并且像在同一个模型中使用它们

②数据菜单中打开逆向工程

③MySQL工作台自动创建了一个新模型

模型中没有任何图,所以在窗口中选择连接

④选择你想要进行逆向工程的数据库sql_store

可以选择多个数据库

重申:如果这些数据库确实高度相关,又想在同一个模型中使用它们再这么做

⑤是否把数据库中全部7张表都导入

同样可以选择显示过滤器来排除一张或多张表

目前想添加所有表到模型中

⑥现在有一个新图,被添加到我们的新模型中

图中可以看到所有表以及它们的关系

这对理解我们的数据库设计非常有帮助

例如产品和订单项目之间有一对多的关系

也可以使用这些图来识别设计中的问题,并允许我们对设计进行任何可能的更改,然后生成更改的代码,以便在别的MySQL数据库中执行

🔺例如订单项目注释表,这张表和任何其他表都不相关

问题:可以在order_id列插入任何值,而MySQL工作台却不会验证它,因此我们确实了数据完整性

当我们在表之间添加关系时,MySQL工作台会强制保证数据的完整性

所以子表中,只能添加与母表中的值相对应的值,目前这里没有任何关系,这意味着可以在order_id列和product_id列中插入无效值

————TBC

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1992459.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大模型(LLMs)LLM生成SFT数据方法面

一、SFT数据集如何生成? SFT数据集构建通常有两种方法:人工标注和使用LLM(比如GPT-4)来生成的,人工标注对于构 建垂直领域比较合适,可以减少有偏数据,但是成本略高;使用LLM生成&…

【算法设计题】计算有向图G中每个结点的入度和出度,第4题(C/C++)

目录 第4题 计算有向图G中每个结点的入度和出度 得分点(必背) 题解:计算有向图G中每个结点的入度和出度 数据结构定义 边表结点 顶点表结点 图的邻接表存储表示 计算图G中每个结点的入度和出度 详细解释 1. 初始化入度和出度数组 2…

容器适配器的介绍和模拟实现

💗 💗 博客:小怡同学 💗 💗 个人简介:编程小萌新 💗 💗 如果博客对大家有用的话,请点赞关注再收藏 🌞 Stack的介绍 stack是一种容器适配器,专门用在具有后进先出操作的上…

如何看到公司所有员工的收发件,并以员工名义一键发信

对于企业管理层来说, 了解并监控员工的企业邮箱成为了日常工作中的一部分。这不仅可以帮助企业更好地掌握业务进展, 还能够提高工作效率。本文将详细介绍如何通过Zoho邮箱实现这一目标, 包括相关的技术原理、实现的好处以及具体的实施步骤。 一、实现的技术: POP3 和 IMAP 要…

C++类和对象(2)——构造函数和析构函数

###前言:此文主要介绍C中的六种默认成员函数;默认的意思就是我们不写编译器会自动生成;这些函数在类里面自动生成;但是我们也可以自己写;学习这几种默认成员函数从两个方面入手: (1&#xff09…

“AI大语言模型+”助力大气科学相关交叉领域实践技术应用

查看原文>>>“AI大语言模型”助力大气科学相关交叉领域实践技术应用 目录 专题一、预备知识 专题二、科研辅助专题 专题三、可视化专题——基于GPT实现 专题四、站点数据处理 专题五、WRF专题——基于GPT和Python实现 专题六、遥感降水专题——基于GPT和Python…

#java学习笔记(面向对象)----(未完结)

一基础相关知识点: 1. 一个对象的调用 首先我们创建一个Phone类 public class Phone {//成员变量String name;int age;String favourite;//成员方法public void myName(){System.out.println(name);}public void myAge(){System.out.println(age);}public void m…

免费写作神器,自动生成高质量文章

在当今数字化的时代,信息的传播和创作变得前所未有的重要。无论是企业的营销推广、个人的博客写作,还是学术研究报告,优质的文章都能发挥巨大的作用。而随着人工智能技术的飞速发展,免费的ai写作工具应运而生,为我们带…

虚拟内存惹

二、理解 虚拟内存 虚拟内存存在的原因物理地址和虚拟地址虚拟内存的其他介绍 虚拟内存存在的原因 计算机系统有两种地址:1、物理地址 2、虚拟地址 物理地址:是指真实的地址,是物理存在的,比如RAM、flash等 虚拟地址:…

使用相同模型相同数据集,为什么每次运行得到的损失值都不一样?

今天小编在学习 PyTorch 时,突然发现咋每次运行所得损失绘制的曲线都不一样呢?即使小编使用torch.manual_seed()函数固定 torch 的随机数种子每次运行的结果还是不一样,因此小编就写一篇文章记录一下。 数据集 本次使用的数据集是小编自定义的小型数据…

MySQL数据管理 - 查询语句

文章目录 查询数据1 查询指定列2 条件查询3 合并查询4 模糊查询5 聚合函数查询6 对值进行排序7 分组查询8 分页查询9 数据库关联查询1 内连接 INNER JOIN2 LEFT JOIN3 右连接 10 数据库子查询参考 查询数据 数据库最常用的操作就是查询,也是数据操作的基础&#xf…

MySQL基础练习题23-门店处理

目录 题目 准备数据 分析数据 方法一 方法二 题目 从分店明细表中获取门店面积。 准备数据 -- 创建库 drop database if exists db_1; create database db_1; use db_1;-- 创建门店面积表 tb_store_area CREATE TABLE tb_store_area (store_no VARCHAR(50),area…

[器械财讯]TRiCares完成近4亿融资,推动Topaz三尖瓣置换系统发展

一、融资成功助力临床研究 法国医疗器械公司TRiCares近期宣布,其D轮融资成功筹集5000万美元,所得资金将专用于支持其核心产品——经导管三尖瓣置换系统(TTVR)Topaz的临床研究和开发。这笔资金将用于在美国和欧盟开展临床研究&…

手持红外热成像仪的使用方法_鼎跃安全

手持红外热成像仪是一种便携设备,方便在现场进行温度检测和成像。他们能将物体发出的不可见红外能量转化为可见的热图像,直观展示物体表面的温度分布情况;广泛应用于电气设备维修、环保检查、应急救援等领域。接下来,我们一起来了…

行业原型:智慧教育线上平台-学院原型

行业原型预览链接: 文件类型:.rp 支持版本:Axrure RP 8 文档名称:智慧教育线上平台-学院 文件大小:1.80 MB 目录内容介绍 文档内容介绍 回复“211110” 领取

《最新出炉》系列小成篇-Python+Playwright自动化测试-66 - 等待元素至指定状态(出现、移除、显示和隐藏)

1.简介 在我们日常工作中进行UI自动化测试时,保证测试的稳定性至关重要。其中一个关键方面是正确地定位和操作网页中的元素。在网页中,元素可能处于不同的状态,有些可能在页面加载完成之前不在DOM中,需要某些操作后才会出现&…

视频剪辑sdk,跨平台部署,助力企业差异化竞争

在这个内容为王的时代,视频已成为连接用户、传递价值的核心媒介。无论是社交媒体、在线教育、短视频平台还是新闻资讯,高质量的视频内容都是吸引用户、提升用户体验的关键。然而,对于众多企业而言,如何高效、专业地处理视频内容&a…

字节跳动春节抖音视频红包系统设计与实现--图文解析

字节跳动春节抖音视频红包系统设计与实现–图文解析 原作者:字节跳动技术团队 原文链接:https://www.toutiao.com/article/7114224228030841374 原标题:2022 春节抖音视频红包系统设计与实现 我们做了什么 业务背景 在春节活动期间&…

洛谷 P10034 「Cfz Round 3」Circle

[Problem Discription] \color{blue}{\texttt{[Problem Discription]}} [Problem Discription] [Solution] \color{blue}{\texttt{[Solution]}} [Solution] 这是道好题。 建图,对每一个 i → p i i \to p_{i} i→pi​ 都建立一个有向边,就可以得到一个…

记一次学习--[网鼎杯 2018]Comment二次注入

目录 本文章只展示二次注入过程,后续获取flag并不展示 靶场 网站流程、密码的破解和目录的查询以及对于源代码获取 密码暴力破解 网站目录扫描 网站源代码获取 网站流程 尝试注入 注入代码 本文章只展示二次注入过程,后续获取flag并不展示 靶场…