Meta-数据库工程师笔记-全-
Meta 数据库工程师笔记(全)
入门 1:课程计划介绍 🎯
在本节课中,我们将要学习Meta数据库工程师专业证书课程的整体计划与目标。本课程旨在帮助初学者掌握成为数据库工程师所需的技能。
数字空间是一个充满连接与机遇的世界。以此刻为例,网络使你能够注册本课程,并向你讲述Meta开发者的个人经历。当你完成这个专业证书课程后,你将成为数字体验的创造者。连接正在进化,你也是如此。你可能完全没有技术背景,这没关系。即使你没有任何经验,本课程也能让你在一年内做好工作准备。
那么,这个专业证书课程如何为你进入像Meta这样的组织工作做好准备呢?数据库工程师专业证书将帮助你建立数据库工程师职位所需的工作技能,同时获得Meta颁发的证书。
你将学习的内容 📚
上一段我们了解了课程的目标,本节中我们来看看具体的学习路径。
你将向Meta的工程师学习,了解他们如何协作创建和测试高性能数据库。你还将与其他有抱负的数据库工程师讨论有趣的话题,并完成一系列编码练习以提高技能。
按顺序完成证书中的所有课程非常重要,因为每门课程都将建立在你已有的技能之上。虽然我们为每门课程推荐了学习计划,但整个课程完全是自定进度的,这意味着你可以自由管理自己的时间。
核心技能与工具 🛠️
在了解了学习方式后,接下来我们看看课程将涵盖的核心技能。
以下是你在课程中将掌握的关键技能:
- 数据库设计与建模:学习如何根据最佳实践对数据库进行建模和结构化。
- SQL语言:学习使用
SQL(结构化查询语言)来创建、管理和操作数据。SQL是处理数据库最广泛使用的语言之一。 - Django Web框架:学习使用
Django框架将Web应用程序的前端连接到你的数据库。 - 版本控制:学习使用
Git和GitHub进行版本控制,以便与其他开发者协作。
最终项目与职业准备 🚀
掌握了核心技能后,你将通过实践项目来整合所学知识。
在你的最终项目中,你将创建一个功能性的关系数据库设计,并使用最佳实践架构进行开发,以作为你求职作品集的一部分展示。在最后的课程中,你将为编码面试做准备。你将练习面试技巧,完善简历,并解决一些通常在技术职位面试中出现的常见编码挑战。
课程完成后的支持 🤝
课程不仅教授技能,还提供职业发展的支持。
一旦你完成课程,你将获得访问Meta课程职位板的权限。这是一个求职平台,将你与超过200家承诺通过Meta证书项目寻找人才的雇主联系起来。你最终会走向何方?无论未来的连接是什么样子,你都将成为其创造的一部分。
让我们开始吧。
本节课中我们一起学习了Meta数据库工程师专业证书课程的整体介绍、学习路径、核心技能(包括数据库设计、SQL、Django和Git)、最终的实践项目,以及课程完成后的职业支持资源。本课程旨在从零开始,系统性地培养你成为一名合格的数据库工程师。
入门 2:数据库介绍 🗄️
在本节课中,我们将要学习数据库的基本概念、它在现实世界中的应用,以及本课程的学习路径和目标。
几乎每个人都使用过数据库。很可能,关于我们的信息就存储在世界各地的许多数据库中。但是,谁真正理解数据库是什么,以及数据库工程对全球工业、政府和组织有多么重要呢?


一个非常直接的描述是:数据库是一种存储数据的电子形式。当然,这个解释远不足以说明数据库技术的影响力。
现实世界中的数据库应用 🌍


为了让大家对数据库在现实世界中的应用有一个概念,我们来简要描述一些典型的使用场景。
以下是几个常见的例子:
- 银行:使用数据库存储客户信息、银行账户和交易记录。
- 医院:存储患者数据、员工数据、实验室数据等。
- 在线商店:保留你的个人资料信息、购物历史和会计交易记录。


许多这类服务还能访问各种数据。它们收集并存储其他信息,例如你的位置、你在其平台上花费的时间、你联系的朋友以及更多事实。

数据时代的挑战与机遇 📈
这类在线服务和社交媒体平台因其庞大的用户基数和持续的用户活动,产生了海量的数据。

随着物联网(IoT)的发展,现在有更多设备连接到互联网。这些持续不断的数据流引发了一场数据库技术的革命,以适应所谓“大数据”的体量、多样性和复杂性。
数据库的核心功能 ⚙️

无论数据来源如何,数据库通常都会执行以下操作。数据库工程师必须熟悉所有这些操作:
- 存储数据。
- 在数据的不同部分之间建立连接或关系。
- 筛选数据以显示相关记录。
- 搜索数据以返回匹配的记录。
- 提供允许数据根据需要进行更新、更改和删除的功能。

如果你现在还不能完全理解所有这些术语,请不要担心。目前你只是对数据库和数据有一个初步的了解。

本课程你将学到什么 📚


在课程中,你将更详细地探索这些概念,以及构成数据库工程师职责的许多其他任务。


你将学习以下内容:
- 数据和数据库的概念,数据在数据库中如何关联,以及不同的数据库结构及其用途。
- 如何执行创建、读取、更新和删除操作(即 CRUD 操作)。
- 如何使用 SQL 运算符对数据进行排序和筛选。
- 什么是数据库规范化,以及如何规范化数据库。
你将有机会构建一个功能完整的数据库。你还将在你的计算机上安装和设置一个名为 Zamp 的软件,以帮助你推进本地和远程数据库的学习。
如何成功学习本课程 🎯

你现在并不需要已经是一名数据库工程师。课程中有许多视频将逐步引导你实现这个目标。观看、暂停、回放并重新观看视频,直到你对自己的技能充满信心。
然后,通过查阅课程资料来巩固你的知识,并在课程练习中将你的技能付诸实践。在此过程中,你会遇到几个知识测验,可以自我检查学习进度。

你并不是唯一一个考虑从事数据库工程师职业的人。因此,你还会参与课程讨论提示,这使你能够与同学建立联系。这是分享知识、讨论困难和结交新朋友的好方法。
为了在本课程中取得成功,坚持有规律、有纪律的学习方法会很有帮助。你需要认真对待学习,如果可能的话,制定一个包含日期和时间的学习计划,并投入其中。这是一个在线自定进度的课程,但将你的学习想象成定期去一个学习机构上课,会对你有所帮助。

总结 ✨
本节课中,我们一起学习了数据库的基本定义及其在银行、医院、电商等领域的广泛应用。我们了解到,在大数据和物联网时代,数据库技术正面临处理海量、多样、复杂数据的挑战。数据库的核心功能包括存储、建立关系、筛选、搜索和更新数据。本课程将引导你从零开始,逐步掌握数据库概念、CRUD操作、SQL以及数据库规范化等核心技能,并通过实践项目、测验和社区讨论,为你迈向数据库工程师的职业生涯打下坚实的基础。
入门 3:数据库工程师的一天 🗓️
在本节课中,我们将跟随Meta的软件工程师Daniel Bloomfield Rammagen,了解数据库工程师的日常工作、核心技能与思维方式。我们将看到技术如何服务于解决实际问题,并学习如何成为一名高效的数据库工程师。
核心理念:技术服务于人 💡
上一节我们介绍了数据库的基本概念,本节中我们来看看数据库工程师的核心工作哲学。
我十分认同一个理念:我们最终是通过技术来解决人类的问题。作为一名软件工程师,我的角色不仅仅是开发技术解决方案,这些方案必须能产生实际的人类价值。
我是Daniel Bloomfield Rammagen,是Meta的一名软件工程师。我于2017年加入公司,在华盛顿特区办公室工作。
无处不在的数据库 📖
数据库并非遥不可及的概念,它存在于我们生活的方方面面。
我立刻想到了我母亲的食谱书,那是一个活页笔记本。她把所有食谱都记在这个活页本里,每一页都有编号,并且在笔记本的开头做了一个索引,以便轻松找到想要的食谱。这,就是一个数据库。可以说,我母亲就是一位数据库工程师(或许不是工程师),但她确实依赖并创建了自己的数据库。
我喜欢这个有趣的例子,因为它展示了一旦你以结构化的方式存储数据,使其易于检索,所能实现的各种可能性。它可以是食谱书,也可以是我刚刚在Facebook上分享的照片,让世界各地的朋友都能迅速看到。这一切的核心,都由大量的基础设施和数据库驱动。
数据层的重要性与影响力 ⚙️

理解了数据库的普遍性后,我们来看看它在应用开发中的核心地位。
我认为数据是每个应用的核心。因此,学会创建一个有效的数据层,能够为用户提供快速、准确的响应和结果,是至关重要的。特别是作为一名数据库工程师,你参与的是构建应用程序中如此关键的一环,你对后续的一切都有着巨大的影响力。

这包括用户界面、客户端、API等,所有这些都会受到影响。数据层如何被建模、存储,以及有效检索数据的特性,如何让技术栈的其他部分更容易地使用这些信息,你都拥有巨大的影响力。我希望你能认识到,你对应用程序的开发有着非常重要的影响。
数据库工程师的日常技能 🛠️
那么,数据库工程师具体需要哪些技能呢?以下是日常工作中用到的关键技能。

技术技能:
- 编程: 我每天都会编码。这不仅指使用标准的Web编程语言进行开发。
- 数据库操作: 我也在数据库领域工作,创建那些提取、转换、加载(ETL) 大量数据的管道,这些数据最终会进入我们开发的应用程序。
软技能:
- 沟通与组织: 我日常使用的软技能当然包括大量的沟通和组织能力。刚从学校毕业时,你可能会对编码和你学到的技术技能感到非常兴奋,这些显然非常重要。

超越代码:沟通的价值 📝
技术技能是基础,但仅有技术是不够的。上一节我们提到了软技能,本节我们来深入探讨其中最重要的部分:沟通。
我曾以为代码就是一切,我来这里就是为了编程。我期望人们能理解我的代码输出。
但我后来认识到这是不够的。我看到过一些技术能力很强的人,他们之所以能取得更大的成功,仅仅是因为他们能够向内部团队,以及可能使用这些工具特性的其他人,清楚地解释他们在做什么。

“完美是优秀的敌人。”
特别是在数据库开发中,很容易过度复杂化解决方案,尤其是在进行数据建模和数据存储时。你会想要覆盖数据的每一种可能变化、每一个不同的用例和边缘情况,这可能导致你创建出非常复杂、难以维护且性能不佳的数据模式。

你需要对你的工作进行迭代。对于数据库,我会说,尽量关注数据当前和近期的需求。

要特别警惕那些对海量数据可扩展性的臆想需求,这可能会再次导致你的解决方案过度复杂化。而事实上,你可能只需要一个规模小得多的方案,至少可以用于启动项目,并更好地理解功能和数据的真实需求。所以,从小处着手,频繁迭代。
实践建议:多写与联系实际 ✍️
了解了核心技能和沟通的重要性后,这里有一些具体的行动建议可以帮助你成长。
多写:
我知道,通常当你想到工程师和数据库程序员时,你认为你的工作成果就是程序、代码和SQL查询。是的,确实如此。
但仅此而已,我认为是不够的。所以要用写作来补充。你要写什么?当然有伴随代码的文档。我在Meta有一位好同事,每当我我说我完成了某件事时,他会看着我说:“你是真的完成了吗?”我第一次听到时回答:“是的,我完成了。”然后他会接着问:“你的文档准备好了吗?你的代码提交到正确的地方了吗?Wiki页面更新了吗?你为此写过文章吗?”他强调了一个重要性:代码只完成了80%,另外20%是所需的额外沟通。
所以我会说,多写。不要害怕写得不完美,先写点什么,发布点什么。无论是分享你正在做的工作状态,还是仅仅增强你正在编写的文档,养成多写的习惯。

联系实际:
尝试将你学到的东西与一些实际的、你能看到用途的事物联系起来。无论是学习数据库时,想到你母亲或父亲活页笔记本里的食谱书,还是你小时候收集的棒球卡或漫画书。
尝试思考如何将你学到的技术知识应用到这些现实生活的问题中。它们可以是小问题,比如在合适的时间找到食谱;当然也可以是更大、或许更有趣的问题,比如人与人之间的技术和数字通信问题。
总结 📚
本节课中,我们一起学习了数据库工程师的日常工作视角。我们认识到,数据库工程师的核心使命是通过技术解决人类问题,而不仅仅是编写代码。数据层是应用的心脏,数据库工程师对其有着深远的影响。日常技能不仅包括编程和数据库操作(如ETL管道),更包括沟通、组织和写作等软技能。记住“完美是优秀的敌人”,在数据库开发中应避免过度设计,从小处着手,频繁迭代。最后,通过多写作和将学习与实际应用场景联系起来,可以更有效地提升自己,为构建有影响力的应用打下坚实基础。
入门 4:3_什么是数据库 📚
在本节课中,我们将要学习数据库的基本概念。我们将探讨什么是数据,什么是数据库,并了解数据在数据库中是如何被组织和存储的。课程结束时,你将能够在概念层面描述数据库,识别现实世界中数据库的应用实例,并理解数据在数据库中的组织方式。

什么是数据?🔍

我们日常的在线生活都离不开数据和数据库。例如,在社交媒体上发布照片、在工作中下载文件、在线玩游戏,这些都是使用数据库的例子。

那么,数据究竟是什么?简单来说,数据是关于任何事物的事实和数字。例如,如果收集一个人的数据,那么这些数据可能包括其姓名、年龄、电子邮件和出生日期。
或者,数据也可以是与在线购物相关的事实和数字。这可能包括订单号、商品描述、订单数量、日期,甚至是客户的电子邮件。

数据对个人和组织都至关重要。但这些数据都存储在哪里呢?

什么是数据库?🗄️

在我们的数字世界中,数据不再存储在纸质文件中。相反,开发者使用一种叫做数据库的东西。数据库是一种电子存储形式,数据在其中被系统化地组织。它以电子方式存储和操作数据,使其更易于管理、更高效、更安全。
现实世界中有许多使用数据库的例子。例如,银行可以使用数据库来存储客户数据、银行账户和交易记录;医院使用数据库来存储患者数据、员工数据、实验室数据等等。

数据库的组织形式 📊
你可能会问,数据库到底是什么样子的?数据库看起来像是系统化组织的数据,这种组织通常类似于电子表格或表格。

“系统化”具体是什么意思?所有数据都包含可以被识别的元素、特征或属性。例如,一个人可以通过年龄、身高或发色等属性来识别。这些数据被分离并存储在代表这些元素的实体中。

正如你刚刚学到的,一个实体就像一张表格。它包含行和列,用于存储与特定元素相关的数据。换句话说,这些是关系型元素,它们彼此关联。这些实体可以是物理的,如员工、客户或产品;也可以是概念性的,如订单、发票或报价单。

实体随后以类似表格的格式,根据与元素相关的属性来存储数据。例如,一个在线商店可以在一个“客户”实体中保存客户数据,该实体包含与客户相关的特定属性。这些属性可以包括名字、姓氏、出生日期和电子邮件。
同样,产品数据可以存储在一个“产品”实体中,其属性包括产品代码、描述、价格和库存状态。
关系型数据库的核心概念 🔗

在关系型数据库的世界里,这些实体被称为关系或表。属性成为表的列,而表的每一行代表该实体的一个实例。
让我们以刚才探讨的在线商店例子中的实体为例。这两个例子可以合并成商店从客户那里收到的订单列表。在数据库中,这些数据可以呈现为一个“订单”表或实体。数据可以被组织成行,每行包含一个唯一的订单号、下订单的客户姓名、他们订购的产品以及该产品的价格。

其他类型的数据库 🌐


在数据库中组织数据的方式有很多种。关系型数据库并不是你作为数据库工程师会遇到的唯一一种数据库类型,你将接触到许多不同类型的数据库。

以下是其他几种常见数据库类型的例子:

- 面向对象数据库:在这种数据库中,数据以对象的形式存储,而不是表格或关系。例如,一个在线书店的数据库可以将作者、客户、书籍和出版商呈现为类(类似于集合或类别)。这些类的对象或实例则保存实际的数据。
- 图数据库:这种数据库以节点的形式存储数据。在这种情况下,像客户、订单和产品这样的实体被表示为节点。它们之间的关系则被表示为边。
- 文档数据库:这种数据库将数据存储为 JSON(JavaScript对象表示法)对象。数据被组织成类似于表的集合。在每个集合中,是用JSON编写的记录数据的文档。例如,客户文档保存在“客户”集合中,而订单和产品文档则分别存储在“订单”和“产品”集合中。

数据库的存储位置 ☁️
那么数据库本身存储在哪里呢?数据库可以托管在组织内部的专用机器上,也可以托管在云端。目前,云数据库是更受欢迎的选择。这是因为它们允许你通过云平台存储、管理和检索数据,并通过互联网访问数据,同时为数据管理等提供了成本更低的选项。
总结 📝



本节课中,我们一起学习了数据库的基础知识。我们首先定义了数据是事实和数字,然后介绍了数据库作为系统化组织数据的电子存储系统。我们深入探讨了数据在关系型数据库中的组织形式,包括实体、表、行和列。此外,我们还简要了解了其他类型的数据库,如面向对象数据库、图数据库和文档数据库。最后,我们讨论了数据库可以存储在本地或云端。现在,你应该对数据库的概念有了基本的理解,能够识别数据库的应用实例,并说明数据在数据库中的组织方式了。这是一个很好的开始,很快你就能自己存储和管理数据了。
入门 5:数据之间的关系
在本节课中,我们将要学习数据库中数据之间如何建立关系。理解数据关系是设计高效、无冗余数据库的关键。我们将通过一个在线商店的例子,来探索主键、外键等核心概念,并解释它们如何将不同的数据表连接起来。
数据不能孤立存在
存储在数据库中的数据不能孤立存在。它必须与其他数据建立关系,才能被处理成有意义的信息。那么,如何确保数据库中的所有数据都是相关的呢?
上一节我们介绍了数据关联的必要性,本节中我们来看看如何在实际场景中建立这种关系。
在线商店示例
让我们以在线商店为例,探索数据是如何关联的。
在在线商店的数据库中,可能有一个订单表和一个客户表。为了查找某个客户的订单详情,你需要根据客户ID来核对订单号。换句话说,数据库在数据和表之间建立了链接。

深入客户表
让我们更详细地查看客户表。
在这个表中,列包括:customer_id、first_name、last_name和email。

用关系数据库的术语来说,这些是字段。表中还有多行数据,每一行都包含了这些字段对应的值。
在关系数据库中,这些行被称为表的记录。

所有这些字段和行共同协作,存储关于客户(也称为实体)的信息。客户表中的每一条记录都是客户实体的一个实例。
例如,Sarah Hogan(客户ID为C1)是一个客户实例。Katrina Langley(客户ID为C4)是另一个客户实例。
最重要的是,每一个客户实例或记录都必须能够被唯一地标识。
但如果两个或更多客户共享相似的信息,比如相同的名字或姓氏,该怎么办呢?
为了避免数据库中的这种混淆,你可以使用一个只包含唯一值的字段,例如customer_id。

主键字段
这个字段被称为主键字段。它包含在表中其他地方不能被复制的唯一值。
因此,即使两个客户共享相同的姓名,他们仍然会有不同的客户ID。

这意味着你的数据库可以确定哪一位是所需的客户。
查看订单表

接下来,让我们看看订单表。
就像客户表一样,订单表也有字段和记录。
在这个表中,主键字段是order_id。

但表中还有一个名为customer_id的字段,其数据与客户表中的数据完全相同。
那么,这个customer_id字段在订单表中的目的是什么呢?
建立表间关系
customer_id字段的作用是帮助确定下订单的人是谁。

因此,通过将customer_id字段添加到订单表中,就在客户表和订单表之间建立了一种关系。

由于这种关系,你可以以一种有意义的方式从两个表中提取数据。
外键字段
订单表中的customer_id字段被称为外键字段。

外键是一个表中的字段,它连接到原始表(在本例中是客户表)中的主键字段。
所以,customer_id是客户表的主键,但它成为了订单表中的外键。通过这种方式,关系得以建立,这两个表中的数据就关联起来了。

总结
本节课中我们一起学习了数据库中数据之间的关系。你现在应该能够解释数据库中数据之间的关系,并识别相关数据的实例。我们了解到,通过使用主键(如 customer_id)和外键,可以在不同的表(如客户表和订单表)之间建立明确的链接,从而确保数据的完整性和查询的高效性。
入门 6:替代类型的数据库 🗄️
在本节课中,我们将要学习“大数据”和“云数据库”等术语的含义,识别不同类型的数据库,并解释数据库是如何响应大数据等新趋势而演变的。

数据库已经存在很长时间,并受到许多不同趋势的影响,但在近几十年里,它们经历了巨大的变化。得益于互联网的发展,数据库现在必须能够存储不断增长的非结构化数据。然而,这带来了困难,因为它们主要存储结构化数据。让我们简要了解一些不同类型的数据库,以及它们是如何受到这一趋势影响的。
关系型数据库的局限性与NoSQL的兴起
关系型数据库在存储数据方面存在局限性,因为它们主要存储结构化数据。然而,现在数据库需要存储越来越多的非结构化数据。
因此,近年来的趋势是转而依赖 NoSQL数据库。

NoSQL数据库是一种以多种不同格式存储数据的数据库类型。本质上,它们为数据库提供了灵活的结构。这使得扩展变得容易,因为它便于更改数据库结构本身,而无需复杂的数据模型。
NoSQL数据库被社交媒体平台、物联网、人工智能以及其他生成海量非结构化数据的应用程序所使用。

以下是NoSQL数据库的主要类型:
- 文档数据库
- 键值数据库
- 图数据库
深入大数据与云数据库

现在您已经熟悉了不同类型的数据库,让我们更深入地看看大数据和云数据库。本质上,这些术语用于描述我们在处理数据和数据库方法上的近期变化。
让我们从大数据开始。

大数据是可能随时间推移而体积增长的复杂数据。换句话说,是可能随时间呈指数级增长的数据。但这种复杂的数据从何而来?
社交媒体平台、在线购物网站和其他服务每时每刻都在生成海量数据,因为它们捕捉着全球数十亿用户的行为。随着物联网(IoT)的发展,越来越多的设备连接到互联网,生成的数据也越来越多。
这就是复杂数据或大数据的产生方式。
所有这些数据都是高度非结构化或半结构化的。传统的数据库系统可以使用表、记录和关系来处理结构化数据,但大数据是一个全新的挑战。大数据是从许多不同来源收集的结构化、半结构化和非结构化数据的组合,它为数据增添了更多力量,因为它可以解决传统结构化数据无法处理的复杂业务问题。
最后,大数据有助于提供独特的见解,从而帮助改善决策。因此,它在许多行业都受到高度重视。

以下是几个行业应用大数据的例子:


- 制造业:处理大数据以预测设备故障、评估生产过程、主动响应客户反馈以及通过监控当前销售来预测未来需求。
- 零售业:处理大数据以预测客户需求、改善客户体验、分析客户行为和消费模式,并识别定价改进机会。
- 电信业:利用大数据分析和网络使用分析来规划基础设施投资、设计满足客户需求的新服务、分析服务质量数据以预测客户满意度,并规划客户保留机制。

云数据库与商业智能

现在您已经熟悉了大数据及其如何助力业务,让我们转向数据库的另一个趋势:云数据库的使用。
组织正在向云端迁移,以摆脱处理物理服务器基础设施(如维护和存储成本)的困难。
云存储服务的一些例子包括Dropbox和iCloud。通过这些云存储服务,可以将文档和其他数据存储在云端,这是一个更经济实惠的解决方案。
数据库的另一个趋势是商业智能。传统上,数据库只是存储数据的手段。但现在,组织利用与商业智能相关的技术和策略来处理他们的数据。


通过这些技术,组织可以分析其数据并提取有价值的信息,以帮助他们做出明智的业务决策。

数据库技术中不断涌现新的趋势,并且会随着时间的推移而持续进步。目前,以上是您应该了解的几种主要趋势。
在本节课中,我们一起学习了NoSQL数据库、大数据、云数据库和商业智能等关键概念,了解了它们如何应对数据存储和处理的新挑战,并在不同行业中发挥重要作用。
入门 7:什么是结构化查询语言 (SQL) 🗃️
在本节课中,我们将要学习结构化查询语言(SQL)的基本概念,了解它是什么以及它在数据库操作中的核心作用。
概述
在课程的这个阶段,你可能已经熟悉了数据库的基础知识以及它们如何存储和管理数据。但了解如何与数据库交互以处理数据同样重要。

数据库工程师的交互操作

那么,数据库工程师需要与数据库建立哪些类型的交互呢?以下是一些你可能需要对数据执行的操作:
- 创建 数据
- 读取 数据
- 更新 数据
- 删除 数据
这些操作也被称为 CRUD 操作。如果你对这些操作还不熟悉,不用担心,本课程后续阶段会深入讲解。
什么是 SQL?

上一节我们介绍了数据库的基本交互操作,本节中我们来看看实现这些操作的核心工具——SQL。
SQL 是一种可以与所有数据库一起使用的标准语言。它在处理关系型数据库时特别有用,因为关系型数据库需要一种能与结构化数据进行交互的语言。


SQL 可以与之交互的关系型数据库示例包括:
- MySQL
- PostgreSQL
- Oracle
- Microsoft SQL Server

SQL 如何工作?

接下来产生的问题是:数据库如何解释、读取和执行使用 SQL 给出的指令?

数据库通过使用数据库管理系统(DBMS)来理解和解释 SQL 指令。作为开发者,你将使用 DBMS 在数据库上执行所有 SQL 指令。DBMS 负责将 SQL 指令转换为底层数据库能够理解的形式。
总结
本节课中,我们一起学习了 SQL 的快速入门知识。在这个早期阶段,你应该能够解释什么是 SQL,并说明 SQL 在数据库中的角色。在接下来的视频中,你将学到更多关于 SQL 的知识,并对这门语言有更深入的理解。
入门 8:SQL用法 🗃️
在本节课中,我们将学习SQL(结构化查询语言)的核心操作及其子语言。你将了解如何使用SQL来创建、读取、更新和删除数据库中的数据,并理解SQL的不同功能分类。
想象一下,你刚被雇佣来为一家大学创建数据库。首先,你需要创建表格来存储大学各个方面的数据。接着,你需要向这些表格中插入数据,并在情况发生变化时修改这些数据。这是一项繁重的工作。但借助SQL和CRUD操作,这一切都能实现。
如果不熟悉这些操作,没关系。在接下来的几分钟里,你将学习如何解释构建数据库时SQL语法的任务,并展示对SQL子集和子语言的理解。让我们回到大学数据库的场景。
你如何在数据库中实现所有这些更改呢?答案是借助Web开发者所称的CRUD操作。执行CRUD操作是处理数据库时最常见的任务。CRUD代表创建、读取、更新和删除。用操作术语来说,即创建、添加或插入数据,读取数据,更新现有数据以及删除数据。
除了这些操作,SQL还能完成许多其他任务。根据SQL的用途,它可以被划分为多个子部分或子语言。这些包括DDL(数据定义语言)、DML(数据操纵语言)、DQL(数据查询语言)和DCL(数据控制语言)。

上一节我们介绍了SQL的总体功能,本节中我们来详细看看这些子语言及其命令,首先从数据定义语言(DDL)开始。
数据定义语言(DDL)🏗️
顾名思义,DDL帮助你定义数据库中的数据。

但“定义数据”是什么意思呢?在将数据存储到数据库之前,你需要创建数据库以及相关的对象(如表)来存储数据。为此,SQL的DDL部分有一个名为 CREATE 的命令。

然后,你可能需要修改已创建的数据库对象。例如,你可能需要通过添加新列来修改表的结构。你可以使用DDL的 ALTER 命令来执行此任务。


你还可以使用DDL的 DROP 命令从数据库中移除一个对象(如表)。

了解了如何定义数据库结构后,接下来我们看看如何操作其中的数据。
数据操纵语言(DML)🛠️
数据操纵语言(DML)命令用于操纵数据库中的数据,例如插入、更新或删除数据。大多数CRUD操作都属于DML。

要向表中添加数据,你可以使用 INSERT 命令。


此命令允许你指定要添加数据的字段以及要插入的值。
如果你需要编辑已插入表中的数据,只需使用 UPDATE 命令。



你可以使用 DELETE 命令来指定要删除的数据。



到目前为止,我们已经学习了如何添加数据库对象并管理其中的数据。那么,如何读取或检索这些数据呢?

数据查询语言(DQL)🔍
要读取存储在数据库中的数据,你可以使用数据查询语言(DQL)。DQL定义了 SELECT 命令来检索数据。
SELECT 允许你从一个或多个表中检索数据,让你能够根据首选的筛选条件指定所需的数据字段。

最后,我们还需要了解如何控制对数据的访问。
数据控制语言(DCL)🔐
你还可以使用DCL(数据控制语言)来控制对数据库的访问。例如,使用DCL命令,你可以控制对数据库中存储数据的访问。

GRANT 和 REVOKE 这两个DCL命令用于授予用户数据访问权限,以及撤销已授予用户的访问权限。
本节课中,我们一起学习了SQL作为数据库与其用户之间接口的作用。你现在应该熟悉了SQL的CRUD操作,并能够识别SQL在不同子语言(DDL、DML、DQL、DCL)中的操作。掌握这些核心概念是进行有效数据库管理和开发的基础。
入门 9:SQL的优点 🚀
在本节课中,我们将要学习SQL语言的核心优势。通过了解这些优点,你将明白为何SQL成为与关系型数据库交互的首选工具。

现在,你可能已经熟悉了数据库的基础知识,甚至接触过一些简单的SQL语法。那么,开发者为何选择使用SQL来与数据库交互呢?SQL之所以成为数据库领域的流行语言,是因为它提供了诸多优势。接下来,我们将识别SQL的主要优点,并演示这些优点如何协助完成数据库任务。
SQL是关系型数据库与其用户之间的接口或桥梁,为Web开发者提供了广泛的优势。让我们来具体看看其中的几点。

优势一:易于学习与使用 📚
SQL最大的优点之一是使用它所需的编码技能非常少。它本质上只是一组关键词。执行基本的CRUD操作(即对数据库进行增加、创建、更新和删除任务)并不需要编写很多行代码,因此它是一种对开发者或用户非常友好的语言。

优势二:交互性与高效性 ⚡
SQL的交互性使其更加用户友好,因为它允许开发者在短时间内编写复杂的查询。因此,如果你需要在下一个项目中处理关系型数据库,你只需要知道在何时使用哪些关键词即可。


优势三:标准化与广泛支持 🌐

SQL也是一种标准语言,可以与所有关系型数据库(如MySQL)一起使用。这也意味着有大量的支持和信息可供参考。一旦安装了数据库软件,SQL就可以在任何计算机上运行。

优势四:可移植性 🔄
SQL还是一种可移植的语言。一旦你编写了代码,它就可以在任何硬件、任何操作系统或平台上使用,无论你在哪里需要它。例如,如果你在桌面电脑上编写SQL代码,然后将其移动到生产服务器环境,它在两个地方都能以相同的方式运行。

优势五:功能全面 🛠️

此外,SQL是一种全面的语言,涵盖了数据库管理和管理的所有领域。例如,它允许你创建数据库、插入、更新和删除数据、在多个用户之间检索和共享数据以及管理数据库安全。

这是通过SQL的子集实现的,例如:
- DDL 或数据定义语言
- DML,也称为数据操作语言
- DQL 或数据查询语言
- DCL,也称为数据控制语言


优势六:处理大数据高效迅速 📊

SQL的最后一个优点是,它允许数据库用户快速高效地处理大量数据。


本节课中,我们一起学习了SQL是一种简单、标准、可移植、全面且高效的语言,可用于与关系型数据库进行通信和协作。掌握这些优点,你就在精通SQL的道路上迈出了坚实的一步。
入门 10:SQL语法介绍 🗄️
在本节课中,我们将学习如何使用SQL(结构化查询语言)与数据库进行交互。我们将重点介绍SQL的三个核心子集:数据定义语言(DDL)、数据操纵语言(DML)和数据查询语言(DQL),并通过创建一个简单的大学数据库示例来演示其基本语法。
概述
SQL是与数据库交互的标准语言。与其他编程语言一样,需要熟悉其语法和子集才能有效使用。接下来,我们将学习如何使用DDL创建数据库和表,使用DML来插入、更新和删除数据,以及使用DQL来查询和读取数据。
使用DDL创建数据库和表

上一节我们介绍了SQL的基本概念,本节中我们来看看如何使用数据定义语言(DDL)来构建数据库的结构。
DDL主要用于定义和修改数据库结构,例如创建数据库和表。
以下是创建数据库的基本语法:
CREATE DATABASE database_name;
例如,要创建一个名为“College”的数据库,可以执行以下命令:
CREATE DATABASE College;

创建数据库后,下一步是创建表。😊
创建表同样使用DDL,语法如下:

CREATE TABLE table_name (
column1 datatype,
column2 datatype,
...
);
例如,在“College”数据库中创建一个“student”表,用于存储学生信息:

CREATE TABLE student (
ID INT,
first_name VARCHAR(50),
last_name VARCHAR(50),
date_of_birth DATE
);
对于要添加到数据库中的每个新表,重复上述步骤即可。
使用DML操作数据
现在我们已经有了数据库和表的结构,本节中我们来看看如何使用数据操纵语言(DML)来填充和修改表中的数据。
DML用于插入、更新和删除数据库中的记录。

要向表中插入数据,使用 INSERT INTO 语句。其语法是插入一行数据到指定表中。

以下是插入数据的基本语法:
INSERT INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...);

例如,向“student”表中添加一名学生的数据:
INSERT INTO student (ID, first_name, last_name, date_of_birth)
VALUES (1, ‘John‘, ‘Murphy‘, ‘1999-05-15‘);
如果需要更新或修改现有数据,例如更正一名学生的出生日期,可以使用 UPDATE 语句。
以下是更新数据的基本语法:

UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
例如,将ID为2的学生的出生日期更新为新的日期:

UPDATE student
SET date_of_birth = ‘2000-01-20‘
WHERE ID = 2;
如果需要从表中删除数据,可以使用 DELETE 语句。😊

以下是删除数据的基本语法:

DELETE FROM table_name
WHERE condition;
例如,删除ID为3的学生记录:

DELETE FROM student
WHERE ID = 3;

执行此语句后,该学生的数据将从表中移除。
使用DQL查询数据
我们已经学会了如何添加、更新和删除数据,本节中我们来看看如何读取数据库中存储的数据。
这时就需要用到SQL的数据查询语言(DQL)。DQL的主要语句是 SELECT,顾名思义,它用于从数据库中选择数据。

一个 SELECT 语句的基本语法如下:
SELECT column1, column2, ...
FROM table_name
WHERE condition;

例如,查询“student”表,找出ID为1的学生的姓名:

SELECT first_name, last_name
FROM student
WHERE ID = 1;
此查询将返回结果“John Murphy”。
总结
本节课中我们一起学习了SQL语法的基础及其三个核心子集:DDL、DML和DQL。我们使用DDL创建了数据库和表,使用DML进行了数据的插入、更新和删除操作,并使用DQL执行了简单的数据查询。目前只需对这些概念建立初步的工作熟悉度即可,在本专业的后续课程中,我们将对每个子集进行更深入的探索,并有机会亲自实践。😊
入门 11:数据库中的表是什么 📊
在本节课中,我们将要学习数据库中的一个核心概念:表。我们将探讨表的结构、组成部分以及它在组织数据中的关键作用。

在课程的这个阶段,你可能已经熟悉了数据库如何存储和交互数据的基础知识。但是,数据库是如何存储所有这些数据并以一种逻辑方式呈现出来的呢?答案是通过表的形式。在本视频结束时,你将能够在概念层面概述什么是数据库表,并解释数据在数据库表中是如何组织的。

正如你可能已经知道的,表由行和列组成,它们用于存放数据。一个表存储在数据库中。在一个包含多个表的数据库中,这些表被称为关系,因为它们彼此关联。从更概念化或逻辑化的意义上讲,表也被称为实体。在面向对象数据库(OODB)中,实体是一个对象,其属性类似于表中的列或字段。


因此,本质上,表、实体和对象都指向同一个概念。

上一节我们介绍了表的整体概念,本节中我们来看看表的内部结构。每个表内部都有列,列有时也被称为字段或属性。每个列或字段都有一个唯一的名称和数据类型。例如,我有一个包含公司员工数据的表。


该表将数据组织在诸如ID和角色等列中。每一列可以容纳不同类型的数据,例如数值型或字符串型。


一组列或字段构成一行。在关系数据库术语中,一行被称为一条记录。因此,记录是包含数据的列或字段的组合。在我的员工表中,例如,每一行就是一条员工记录。



现在,让我们更深入地了解一下列。正如你现在所知,每一列都有一个数据类型。列的数据类型定义了该列可以容纳什么类型的值,例如整数、字符、日期和时间等。由开发者决定每列的数据类型。

数据类型也为SQL提供了指导,使其了解每列中预期的数据类型以及如何与底层物理存储的数据进行交互。

然而,数据类型可能因数据库系统而异。例如,MySQL、SQL Server或Access可能支持不同的类型。请务必参考相关数据库系统的文档以检查其支持的数据类型。

以下是常见的数据类型类别:
- 字符串数据类型:用于存储字符和字符串。
- 数值数据类型:用于存储精确或整数以及近似数字。
- 日期和时间数据类型:用于存储日期和时间信息。
- 二进制数据类型:用于存储图像、文件和其他信息。
理解了数据类型后,我们来看一个与之相关的重要概念:域。域是可以分配给属性的合法值的集合。基本上,这意味着确保一个字段可以容纳的值是明确定义的。例如,你只能在数值域中放置数字,只能在字符串域中放置字符或字符串。每个域都必须包含长度、值和其他定义其功能的相关规则。


最后,我们来探讨表中用于唯一标识记录的关键部分。表中的每一行或记录也通过所谓的主键来唯一标识。表中具有唯一值的列将成为该表的主键。例如,在员工表中,ID列是主键,因为每个ID都是唯一的。这是因为其他列可能包含重复的值。例如,两名员工可能共享相同的姓名或角色。如果单列本身不具备唯一值,主键也可以是多个列的组合。


本节课中我们一起学习了数据库表的核心概念。你现在应该熟悉了什么是数据库表,并能够解释它的结构。你也应该能够解释关键概念,如列、行和键。干得不错。
入门 12:数据库表中的键类型 🔑
在本节课中,我们将要学习关系型数据库中表之间建立联系的核心机制——键。理解不同类型的键是掌握数据库表设计与关系的基础。
概述

在课程的这个阶段,你可能已经熟悉了关系型数据库模型。但要完全理解关系型数据库模型的工作原理,你首先需要理解数据库中的表是如何关联的。本质上,表之间的关系是通过使用键来建立的。通过本视频的学习,你将能够识别关系型数据库表中使用的主要键类型,并解释表中键之间的关系。
关系型数据库模型基础
关系型数据库模型基于两个主要概念:定义为表的实体,以及连接到相关表的关系。要理解这个模型如何工作,你需要了解关系型数据库中存在的不同键属性。

为了演示,我们使用一个体育比赛的例子,它使用三个表来跟踪联赛信息:联赛表、球队表和积分表。
表的属性
每个表都有相关的列,每一列代表表实体的一个属性。联赛表跟踪每支球队在联赛中的位置、队名以及所代表的州。球队表跟踪队名、队长和教练。积分表记录球队在联赛中的位置、队名以及本赛季获得的积分。
请注意,球队表中包含了队名,这个属性也属于联赛表。这些属性可以是能保存单个值的简单属性类型。

例如,在一个学院的员工表中,每个员工姓名的属性在每一行都有一个单一的值。
它们也可以是能拥有多个值的多值属性,例如所教科目的列表。然而,在关系型数据库设计中应避免使用多值属性。你将在课程后面了解更多关于这个概念的内容。
键属性类型

让我们使用员工表的例子来探索一些键属性的示例。以下是关系型数据库中存在的不同类型的键属性。

键属性
这是一个用于唯一标识表中单个数据记录的值。例如,在员工表中,键属性是员工ID。这个属性在表的每一行都有唯一的值,因此它是唯一标识每条数据的完美方式。
候选键属性
这是指在表的每一行都包含唯一值的任何属性。在员工表的例子中,员工ID和联系电话都是候选键的示例。每一行都有一个新的唯一值。其他列可能包含重复信息,因此它们被指定为非键属性。
复合键
复合键是由两个或更多属性组成,以在每一新行中形成唯一值的键。在员工表中,一个复合键的例子是员工姓名和员工职位的组合,前提是表中没有其他相同的组合实例。通常在无法识别单一属性键时,会考虑使用复合键。
主键
关系型数据库还必须包含一个主键,你应该已经熟悉这个概念。在员工表中,员工ID是主键。
备用键
备用键,也称为次键,是未被选为主键的候选键。就像主键一样,它是一个在每一行都包含唯一值的列。对于员工表,联系电话是每一行的次键。
外键
外键是表中的一个属性,它引用另一个表中的唯一键。通常,外键引用另一个表的主键。例如,员工ID也可能是学院数据库中一个或多个表的外键。主键和外键之间的关系将在本课程后面详细讨论。
总结

本节课中,我们一起学习了关系型数据库中不同类型的键。你了解了键属性、候选键、复合键、主键、备用键和外键的定义与作用。理解这些键是设计高效、无冗余的数据库表并建立正确表间关系的关键。在后续课程中,我们将深入探讨如何利用这些键来构建复杂的数据库关系。
入门 13:模块小结
在本节课中,我们将对“数据库介绍”模块的核心内容进行回顾与总结。我们将梳理你所学到的关于数据库、SQL以及数据库结构的基础知识。
概述
你已经完成了本模块的学习,即数据库入门介绍。在本模块中,你探索了数据库和数据的基础知识,初步了解了SQL(结构化查询语言),并研究了数据库的基本结构。现在,是时候回顾你学到的关键知识点、概念以及掌握的技能了。
数据库与数据基础回顾


模块从数据库和数据的介绍开始。完成第一课的学习后,你现在能够:

- 从概念层面概述什么是数据库。
- 列举数据库在现实世界中的应用实例。
- 解释数据在数据库中是如何组织的。
上一节我们介绍了数据库的基本概念,本节中我们来看看数据库内部数据的关系与类型。


你现在还能解释数据库中相关数据的重要性,识别数据库内相关数据的实例,并概述数据库应用的新趋势。

此外,你能够识别不同类型的数据库,并对数据库的演进历程提供一个高层次的概述。

SQL入门知识梳理
在探索了数据库和数据之后,你接着被引入了SQL的世界。😊

这一课的重点是SQL(结构化查询语言)的基础。在这节课中,你学习了如何概述SQL的用途,并理解SQL和数据库所扮演的角色。😊
以下是SQL的主要优势:

- 低入门门槛:易于学习。
- 应用广泛:用途多样。
- 跨操作系统可移植性:可在不同系统上使用。


你现在也能解释这些优势将如何帮助你在处理数据库时更加得心应手。
并且,你能够概述SQL中DDL(数据定义语言)、DML(数据操作语言)和DQL(数据查询语言)语法的基本用法,并识别数据库中使用的主要SQL命令。


数据库结构核心总结
在本模块的最后一课,你探索了数据库的基本结构。
现在你已经完成了本课的学习,你可以解释数据库表的概念,概述表的用途,并识别数据库表的关键组成部分,例如列、行、数据类型和键。😊



总结
本节课中我们一起学习了数据库的基础知识。你现在已经熟悉了数据库的基本原理,可以解释它们如何存储数据,识别通过SQL与数据库交互的方法,并概述数据库的基本结构。这为你开启数据库学习之旅奠定了良好的基础。
做得好。
入门 14:数值数据类型 📊
在本节课中,我们将要学习数据库中的数值数据类型。你将了解数据类型的核心概念,并学会区分整数和十进制这两种最常见的数值数据类型。
数据类型的核心概念
你可能知道数据库表以列和行的形式存储数据。但如何确保每一列都接受正确类型的数据?例如,确保你的“成本”列存储十进制数值,或者“产品数量”列接受正数。这正是数据类型的作用。通过数据类型,你可以确定表中每个字段接受何种数据。
在开始探索数值数据类型之前,我们先花点时间了解数据类型的概念。当你在数据库中创建表时,需要定义列名以及这些列将存放内容的数据类型。

数据类型告诉数据库管理系统(如MySQL)如何解释列的值。数据类型以正确的格式维护数据,并确保每列的值符合预期。


最常用的数据类型包括数值型、字符串型以及日期和时间型。让我们以在线商店数据库中的一个表为例。




该表通过名为“客户姓名”、“订单日期”、“产品”、“数量”和“总价”的列来收集信息。这些列中的每一列都必须以合适的数据类型存储数据。“客户姓名”列可以使用字符串数据。“订单日期”可以使用日期类型。而“产品数量”和“总价”列最适合使用数值数据。


数值数据类型简介
本视频的重点是数值数据类型。数值数据类型是一个通用术语,指代所有允许列在数据库中存储数字数据的特定数据类型。

数据库中两种最常见的数值数据类型是:
- 整数数据类型:用于存储整数值。
- 十进制数据类型:用于存储带有小数部分的数值。
回到我们之前的表格示例,“产品数量”列被定义为整数数据类型。这是因为它只保存整数。

虽然可以插入小数,但它们在数据库中总是会自动向上或向下舍入到最接近的整数。

而“总价”列是十进制类型。这是因为它保存小数。例如,一件价值 $80.90 的商品就是一个小数值。80 是整数部分,90 是小数部分。当然,也可以插入整数。

数据库会自动添加一个小数点以及一个值为0的小数部分。

整数与十进制数据类型的变体
在大多数数据库管理系统中,你会发现不同类型的整数和十进制数据类型。每种类型都旨在存储一个最小和最大的数值范围。
例如,在MySQL数据库管理系统中:
TINYINT用于非常小的整数值,其可插入的最大可能值是 255。- 而
INT可用于存储非常大的数字,其可存储的最大值超过 40亿。
这些数据类型也可以接受负值和正值。

在某些数据库管理系统中,你还可以强制列只接受正数。这会增加它们可以存储的最大值。

总结
本节课中,我们一起学习了数据库中的数值数据类型。你现在应该能够解释数值数据类型,并且能够区分整数和十进制数据类型。干得漂亮!


入门 15:字符串数据类型 📚
在本节课中,我们将要学习数据库中的字符串数据类型。你将了解字符串数据类型的定义、用途,并重点区分 CHAR 和 VARCHAR 这两种最常用的类型。通过学习,你将能够为数据库表中的列选择合适的数据类型,以确保数据的完整性和存储效率。
字符串数据类型简介

在数据库中创建表时,必须定义列名以及该列将存储内容的数据类型。字符串数据类型用于定义列的数据类型,特别是在该列需要同时接受数字和文本字符的情况下。
为了确保数据完整性,必须保证只有有效的值被插入表中。例如,当你打算存储包含多种字符类型的数据时,就应该使用字符串数据类型。如果你将一列定义为字符串类型,那么任何类型的文本都可以被插入,这包括字母字符、数字字符和特殊字符。
字符串数据类型示例


让我们通过一个例子来进一步了解字符串数据类型的工作原理。
以大学数据库中的学生表为例,该表存储了学生登录学校在线门户的信息。信息存储在以下四列中:student_name(学生姓名)、username(用户名)、password(密码)和 email_address(电子邮件地址)。其中,student_name 列仅包含字母字符,username 列包含字母数字字符,而 password 和 email 列则包含混合的字符类型。
主要字符串类型:CHAR 与 VARCHAR

“字符串数据类型”是一个通用术语,指代数据库中不同的字符串数据类型。最常用的字符串数据类型是 CHAR(代表 Character,字符)和 VARCHAR(代表 Variable Character,可变字符)。

上一节我们介绍了字符串数据类型的通用概念,本节中我们来看看这两种具体的类型。

CHAR数据类型用于保存固定长度的字符。VARCHAR数据类型用于保存可变长度的字符。
CHAR 数据类型详解
CHAR 意味着字符的给定长度是预先确定的,在声明后无法更改。列属性被定义为 CHAR,后跟括号中的字符长度。

例如,CHAR(50) 表示该列每个字段只允许占用 50 个字符的空间。如果你希望维持一个预定义大小的字符长度,CHAR 是最佳选择。
在学生表的例子中,你可以为 username 列设置最大长度为 50 个字符,在 SQL 中使用 CHAR(50)。例如,表中有一条记录的用户名是 “Mark123”,总共 7 个字符。然而,由于该列被定义为 CHAR(50),这个用户名在存储空间中仍会占据 50 个字符的长度。
VARCHAR 数据类型详解

VARCHAR 数据类型的工作方式与 CHAR 类似,但它是可变长度的。这意味着长度可以改变,不是固定的。
当你无法确定列字段中可能插入多少个字符时,通常使用 VARCHAR。因此,你可以在 SQL 中键入 VARCHAR(50),以允许最多 50 个字符的任何输入。

在学生表示例中,student_name 列很可能包含不同长度的姓名,因此你可以将 student_name 列在 SQL 中定义为 VARCHAR(50)。这意味着每个学生的姓名只占用其名字字符数量的空间。例如,“Mark Simpson” 占用的空间远少于 50 个字符,但如果需要,该字段最多可以容纳长达 50 个字符的姓名。
其他常用字符串类型

除了 CHAR 和 VARCHAR,还有一些其他常用的字符串数据类型,适用于存储不同长度的文本。
以下是几种常见的文本类型及其典型用途:
TINYTEXT:用于定义需要少于 255 个字符的列,例如短段落。TEXT:用于定义少于 65,000 个字符的列,例如一篇文章。MEDIUMTEXT:用于定义最多 1670 万个字符的列,例如一本书的文本。LONGTEXT:该数据类型最多可存储 4GB 的文本数据。

总结 🎯
本节课中我们一起学习了数据库中的字符串数据类型。你现在应该能够解释字符串数据类型在数据库中的用途,并且能够区分不同的字符串数据类型,包括 CHAR 和 VARCHAR。CHAR 用于固定长度的字符串,会占用预定义的空间;而 VARCHAR 用于可变长度的字符串,只占用实际内容所需的空间。根据数据的特点选择合适的类型,对于优化数据库存储和性能至关重要。
入门 16:默认值约束
在本节课中,我们将学习数据库约束的概念,特别是两种常用的约束:NOT NULL 和 DEFAULT。我们将了解它们如何确保数据的准确性和可靠性,并通过具体的SQL语句示例来掌握其应用方法。

数据库约束概述

为了确保数据库中数据的准确性和可靠性,必须限制可以存入数据库表的数据类型。
数据库约束用于限制可以存储在表中的数据类型,这确保了插入表中的所有数据都是准确和可靠的。
如果数据库检测到约束与数据操作之间存在冲突,则会中止这些操作。冲突的一个例子可能是尝试向表中插入或上传无效数据。数据库会识别出数据无效并拒绝它。
约束可以是列级别的,即规则适用于特定列;也可以是表级别的。例如,可以使用外键约束来防止破坏表之间链接的操作。我们将在后续课程中更详细地演示这一点。
两种最常用的数据库约束包括:
NOT NULL:一种防止字段为空值的方法。DEFAULT:一种分配默认值的方法。




NOT NULL 约束
上一节我们介绍了约束的基本概念,本节中我们来看看 NOT NULL 约束的具体作用。


NOT NULL SQL约束用于确保数据字段始终被填写,永远不会留空。
让我们用一个在线商店的表示例来探索这个概念,该表记录客户的ID和姓名。该表在其 customer_id 和 customer_name 列中记录这些数据。这些列必须始终包含数据。如果没有数据或值插入到这些列中的任何一列,则新客户记录的创建将被中止。
NOT NULL 约束是通过SQL语句实现的。一个典型的 NOT NULL SQL语句从在数据库中创建一个基本表开始。

以下是创建该表的SQL语句示例:

CREATE TABLE customer (
customer_id INT NOT NULL,
customer_name VARCHAR(255) NOT NULL
);
在这个语句中:
- 使用
CREATE TABLE子句,后跟customer来定义表名。 - 在一对括号内,添加两列:
customer_id和customer_name。 - 为每列定义相关的数据类型:
INT用于存储数值的customer_id,VARCHAR用于存储字符串值的customer_name。 - 最后,为每列声明一个
NOT NULL约束。这确保了两列都不会接受空值。
现在,任何试图在这些列中放置空值的操作(如插入或更新数据)都将失败。
DEFAULT 约束

了解了如何强制字段不为空后,接下来我们看看 DEFAULT 约束如何在表中工作。
DEFAULT 约束为列设置一个默认值,前提是没有指定其他值。这意味着,如果没有为列中的特定字段输入数据,那么表将自动插入一个默认值。

为了更好地理解默认值,让我们看一个存储足球俱乐部数据库球员记录的表。该表名为 player_table,包含两列。第一列是 player_name,列出球队中每位球员的姓名;第二列是 city,列出每位球员来自哪个城市。
该俱乐部的大多数球员都来自巴塞罗那,因此我可以将 city 列的默认值指定为 Barcelona。这意味着我不必为每位新球员在 city 字段中重复输入 Barcelona。如果表中没有输入值,那么每个字段将自动填充默认值 Barcelona。
让我们看看 DEFAULT 命令是如何整合到SQL语句中的。
以下是创建该表的SQL语句:

CREATE TABLE player_table (
player_name VARCHAR(255) NOT NULL,
city VARCHAR(255) DEFAULT 'Barcelona'
);
在这个语句中:
- 首先,使用
CREATE TABLE命令创建一个表,并将其命名为player_table。 - 然后,在一对括号内,输入列名,为每列分配字符串数据类型。
- 为
name列分配NOT NULL约束。 - 最后,为
city列添加DEFAULT关键字语句,后跟默认值'Barcelona'。
现在,当我向表中添加新球员的数据时,对于来自巴塞罗那的球员,我不需要输入 Barcelona,它会自动插入。

课程总结

本节课中,我们一起学习了数据库约束的重要性。你现在应该能够解释数据库约束是在列或表级别强制执行规则的方法。具体来说,我们掌握了:
NOT NULL约束:确保关键字段(如ID和姓名)永远不会为空,保障了数据的完整性。DEFAULT约束:为常用值设置默认项,简化了数据输入过程,提高了效率。
熟练运用这些约束是设计健壮、可靠数据库的基础。
入门 17:创建和删除数据库 🗄️
在本节课中,我们将学习如何使用SQL语句来创建和删除数据库。这是管理数据存储空间的基础操作,对于构建和维护任何应用程序都至关重要。
你刚刚被一家在线书店聘用,负责构建和维护能够存储数百万本书籍和客户信息的数据库。
但我们该如何开始创建和修改那些存储不断扩展的信息、或处理来自全球数百万订单的数据库呢?
这些问题的答案在于SQL的创建和删除命令。在本视频中,你将学习如何使用SQL语法创建数据库,同时也会了解如何删除一个数据库。
然而,在创建数据库之前,你首先需要明确它的目的。例如,如果你正在为一家在线书店构建数据库,那么你的数据库需要记录诸如书名、作者、客户和销售等数据。
这些主题的数据必须被存储并组织在数据库的相关表中。

之后,用户可以根据需要访问、检索和更新这些数据。


如何创建数据库? ➕

那么,如何使用SQL语法创建数据库呢?要创建一个数据库,只需输入 CREATE DATABASE 关键字,然后跟上你的数据库名称。
以下是创建数据库的基本语法:
CREATE DATABASE database_name;
如何删除数据库? ➖

关于移除或删除数据库呢?要删除一个数据库,只需输入关键字 DROP DATABASE,然后跟上你想要删除的数据库名称。
以下是删除数据库的基本语法:
DROP DATABASE database_name;

实战演示 🛠️
上一节我们介绍了创建和删除数据库的基本语法,本节中我们来看看这些命令的实际操作。
为了演示,让我们使用SQL语法创建第二个书店数据库。首先,我输入关键字 CREATE DATABASE,然后跟上我的新数据库名称。在这个例子中,数据库被命名为 bookstore2_DB。
在创建新数据库时,我总是使用有意义且相关的名称,这有助于使我的工作文档更清晰。数据库名称必须是唯一的,并且最多只能有63个字符。如果我的数据库名称不符合这些要求,将会出现错误信息。最后,我在语句末尾添加一个分号,然后运行该语句。


于是,新的数据库 bookstore_DB2 出现在左侧边栏中。这样,我就创建了第二个数据库。
我也可以使用SQL语句删除数据库。


首先,我选择SQL选项卡,然后在出现的代码框中输入我的查询。我输入关键字 DROP DATABASE,然后跟上我想要删除的数据库名称,在这个例子中是 bookstore_DB。

现在我运行查询,SQL就会删除该数据库。



总结 📝
本节课中我们一起学习了如何使用SQL语法创建和删除数据库。你掌握了 CREATE DATABASE 和 DROP DATABASE 这两个核心命令,并了解了在命名数据库时需要注意的唯一性和长度限制。这是管理数据库生命周期的基础,为后续学习创建表、插入数据等更复杂的操作打下了坚实的基础。
入门 18:创建表语句 📝
在本节课中,我们将学习如何使用SQL语句在数据库中创建表。创建表是组织和管理数据的基础步骤,通过定义表的结构,我们可以有效地存储和检索信息。
概述
构建数据库涉及处理大量数据。如何组织数据以便准确找到所需信息并理解其含义?使用SQL,可以在数据库中创建表来保存和组织数据。本节将介绍如何使用SQL语法在数据库管理系统中创建表。
SQL创建表语句语法
首先,我们来看SQL创建表语句的基本语法。语句以关键字CREATE TABLE开始,告知SQL需要创建新表。接着添加要创建的表名。最后,添加一对括号。在括号内,键入表中必须包含的每个列名及其相应的数据类型。

语法示例:
CREATE TABLE table_name (
column1 datatype,
column2 datatype,
...
);
创建表的前提条件
在熟悉语法后,我们来看实际操作。请注意,在创建表之前,服务器上必须已存在数据库。换句话说,如果没有数据库,就无法在其中创建表。
假设在本示例中,我们已经有一个准备使用的数据库。我将在书店数据库中创建一个客户表,用于存储客户数据,如姓名和电话号码。

创建客户表示例
以下是创建客户表的步骤。首先,编写包含CREATE TABLE命令的SQL语句,后跟表名(本例中为customers),然后添加一个开括号。在括号内,我们需要定义列。
步骤详解:
- 定义第一列:列名为
customer_name,数据类型为VARCHAR。VARCHAR表示该列可以存储任何类型的字符数据。在括号内添加一个数值,指定最大字符长度。 - 定义第二列:添加逗号,然后写入第二列名
phone_number。数据类型为INT,表示该列只能存储整数。 - 结束语句:添加闭括号和分号。
完整SQL语句:
CREATE TABLE customers (
customer_name VARCHAR(100),
phone_number INT
);
执行语句

最后,执行该SQL语句。客户表现在已存储在数据库中。

总结
本节课中,我们一起学习了如何使用SQL语法在数据库中创建表。通过定义表名、列名和数据类型,可以有效地组织数据,为后续的数据操作和管理奠定基础。
入门 19:ALTER TABLE语句 🛠️
在本节课中,我们将要学习如何使用SQL的ALTER TABLE语句来修改数据库表的结构。你将学会如何为现有表添加新列、删除不需要的列,以及修改列的数据类型或约束。
概述
上一节我们介绍了如何创建数据库和表。本节中我们来看看如何修改已存在的表。数据库表的结构并非一成不变,开发者经常需要根据需求调整表的设计,例如添加新字段或删除旧字段。SQL提供了ALTER TABLE语句来完成这些任务。
ALTER TABLE 语句基础
ALTER TABLE语句的基本语法用于告知数据库需要修改哪个表。其核心结构如下:
ALTER TABLE table_name
ADD column_name data_type;
ALTER TABLE是关键字,表示要修改表。table_name是要修改的表的名称。ADD是关键字,表示要添加内容(此处为列)。你也可以使用其他关键字如DROP或MODIFY。column_name data_type定义了要添加的新列的名称及其数据类型。

实践示例:添加新列
在开始修改表之前,你需要确保已有一个包含数据的数据库和表。在本例中,我们有一个名为 college 的数据库,其中包含一个 students 表,该表目前有 id、name 和 email 三列。
现在,我们需要为 students 表添加三个新列:age、nationality 和 country。
以下是添加这些列的SQL语句:
ALTER TABLE students
ADD (age INT, country VARCHAR(50), nationality VARCHAR(255));
- 我们首先指定要修改的表是
students。 - 使用
ADD关键字,并在括号内列出要添加的列及其定义。 age INT表示添加一个名为age、数据类型为整数(INT)的列。country VARCHAR(50)表示添加一个名为country、可变字符类型(VARCHAR)且最大长度为50的列。nationality VARCHAR(255)同理,最大长度设为255。
执行此语句后,students 表就新增了这三列。
实践示例:删除列
添加列后,我们发现 nationality(国籍)和 country(国家)两列信息可能重复。为了简化表结构,我们可以删除 nationality 列。

以下是删除列的SQL语句:
ALTER TABLE students
DROP COLUMN nationality;

- 语句开头同样是
ALTER TABLE students。 - 使用
DROP COLUMN关键字,后接要删除的列名nationality。 - 执行时,数据库通常会请求确认,确认后该列即被永久删除。
实践示例:修改列定义
上一节我们删除了冗余的列。本节中我们来看看如何修改现有列的定义。例如,我们觉得 country 列的50字符长度限制可能不够,希望将其扩展到100字符。


以下是修改列定义的SQL语句:

ALTER TABLE students
MODIFY country VARCHAR(100);
- 我们使用
MODIFY关键字来修改已有列的定义。 - 其后指定要修改的列名
country以及新的数据类型和约束VARCHAR(100)。 - 执行此查询后,
country列的最大字符长度就更新为100了。
总结

本节课中我们一起学习了如何使用 ALTER TABLE 语句来动态调整数据库表的结构。我们掌握了三个核心操作:
- 使用
ADD关键字为表添加新列。 - 使用
DROP COLUMN关键字删除表中现有的列。 - 使用
MODIFY关键字修改现有列的数据类型或约束。
通过掌握这些技能,你可以灵活地维护和优化数据库表,使其更好地适应不断变化的应用需求。
入门 20:INSERT语句 📝
在本节课中,我们将学习如何使用SQL的INSERT语句向数据库表中添加新数据。这是管理数据库时最基础且频繁的操作之一。
概述
当操作数据库时,经常需要向现有表中添加新的行和列,甚至从头创建新表。例如,如果你管理一个大学数据库,就需要为每一位新学生添加一行新记录。使用SQL,你可以通过INSERT语句快速完成这些任务。本节结束后,你将能够识别和理解INSERT语句的语法,并使用INSERT INTO子句向表中插入数据。
INSERT INTO 语法解析
上一节我们介绍了INSERT语句的作用,本节中我们来看看它的具体语法结构。
要编写一个INSERT语句,首先需要写出INSERT INTO子句。然后指定表名,后面跟着一个包含在圆括号内、用逗号分隔的列名列表。接着使用VALUES关键字,并在另一对圆括号内写出对应的值列表。
核心概念:每个值都对应一个特定的列,因此必须反映相同的数据类型和顺序。其基本语法结构如下:

INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);
你还可以一次性向表中添加多行数据。首先,像之前一样编写INSERT INTO子句和表名。然后使用VALUES关键字并添加多行值,只需确保每一新行数据都用逗号与前一行分隔开。
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1a, value2a, value3a, ...),
(value1b, value2b, value3b, ...);
INSERT 语句示例
理解了基本语法后,让我们通过一些例子来实践INSERT语句的使用。
在本例中,我将使用一个体育俱乐部数据库中的名为Players的表。我想向这个表中插入新球员的数据。
以下是插入单行数据的步骤:
- 首先,我编写
INSERT INTO命令,后跟表名Players。 - 然后,我在一对圆括号内添加列名。这些列必须包含俱乐部需要的每位球员的基本信息,所以我将列命名为
ID、name、age和start_date。 - 接着,我插入
VALUES关键字,然后在一对圆括号内添加要分配给每列的值。 - 我开始为一位名叫
Uil、年龄25岁、ID为1、入职日期为2020-10-15的新球员添加数据。
重要提示:在表中输入日期时,必须使用正确的年-月-日格式,否则会出现错误信息。所有非数值类型的值都应放在引号内,就像本例中的‘Uil’和日期值一样。
INSERT INTO Players (ID, name, age, start_date)
VALUES (1, ‘Uil’, 25, ‘2020-10-15’);
执行此语句后,输出显示了一行Uil的数据,正如代码所指示的那样。

插入多行数据
但是,如果我想一次性向表中插入多条数据记录呢?假设又有两名新球员加入了球队。
以下是插入多行数据的步骤:
- 第一名球员是
Mark,年龄27岁,ID为2,入职日期为2020-10-12。 - 第二名球员是
Carl,年龄26岁,ID为3,入职日期为2020-10-07。

正如之前所学,这是一个非常直接的任务。以下是具体操作:
INSERT INTO Players (ID, name, age, start_date)
VALUES (2, ‘Mark’, 27, ‘2020-10-12’),
(3, ‘Carl’, 26, ‘2020-10-07’);
最后,我运行或执行该语句。检查输出,结果显示现在表中共有三名球员。

查询现有数据
到目前为止,我们已经探索了如何向表中添加数据。但是,也可以通过执行以下SQL查询来显示Players表中的现有数据。

以下是查询所有数据的步骤:
- 首先,我输入
SELECT子句,后跟一个星号*。这个星号告诉SQL返回表中的所有列。 - 然后,我输入
FROM关键字和表名。

SELECT *
FROM Players;

执行该语句后,输出显示了Players表中所有可用的数据。

总结
在本节课中,我们一起学习了SQL INSERT语句的核心用法。你现在应该能够识别和理解INSERT语句的语法,并能够使用INSERT INTO子句向数据库表中插入新的数据。无论是添加单条记录还是批量插入多条记录,INSERT语句都是填充和维护数据库表内容的基础工具。
入门 21:SELECT语句 🗃️
在本节课中,我们将学习如何使用SQL中的SELECT语句从数据库表中查询数据。SELECT语句是SQL中最基础且最常用的命令之一,它允许你检索表中的特定列、所有列,甚至执行计算。
基本语法
上一节我们介绍了SELECT语句的重要性,本节中我们来看看它的基本语法结构。一个基础的SQL SELECT语句由以下部分组成:
SELECT column_name FROM table_name;
SELECT是用于检索数据的关键字。column_name是你需要查询的数据所在的列名。FROM是指定数据来源表的关键字。table_name是你要查询的表的名称。- 分号
;通常用于标记SQL语句的结束。
查询单列数据
理解了基本语法后,让我们通过一个具体例子来看看如何从表中查询一列数据。假设我们有一个名为 Players 的足球俱乐部球员表,其中包含 ID、name、age、level 等列。

如果我们只需要获取所有球员的姓名,可以使用以下语句:
SELECT name FROM Players;


执行此查询后,将返回一个结果集,其中单独列出 Players 表中 name 列的所有值,每个姓名占据一行。
查询多列数据
有时,我们需要从表中获取不止一列的信息。例如,我们想同时查看每位球员的姓名和技能等级。

以下是实现此目标的方法:
SELECT name, level FROM Players;
请注意,在 SELECT 关键字后列出多个列名时,必须用逗号 , 将它们分隔开,这样SQL才能识别它们是不同的列。执行此查询将返回来自 name 和 level 两列的数据。

查询所有列数据
如果需要检索表中的所有数据,也有两种方法可以实现。

第一种方法是列出所有列名:
SELECT ID, name, age, level FROM Players;

同样,每个列名之间需要用逗号分隔。


第二种方法是使用星号 * 作为通配符,这是一种快捷方式:
SELECT * FROM Players;

使用 SELECT * 会返回指定表中所有列的所有数据,其结果与显式列出所有列名相同。

本节课中我们一起学习了SQL SELECT 语句的核心用法。你现在已经掌握了如何从数据库表中查询单列、多列以及所有列的数据。下次当你需要从数据库中检索信息时,就可以根据需求选择合适的方法了。
入门 22:INSERT INTO SELECT语句
在本节课中,我们将要学习如何使用 INSERT INTO SELECT 语句,从一个或多个表中查询数据,并将结果插入到另一个目标表中。这是一种高效的数据迁移和填充方法。
理解 INSERT INTO SELECT 语句

上一节我们介绍了数据操作的基本概念,本节中我们来看看 INSERT INTO SELECT 语句的具体作用。
本质上,INSERT INTO SELECT 语句用于从源表的列中查询数据,并将查询结果放入目标表的列中。

例如,你可以使用 INSERT INTO SELECT 语句查询源表中 column C 的数据,并将查询结果放入目标表的 column B 中。
语句语法结构

了解了其作用后,我们来看看它的语法结构。以下是 INSERT INTO SELECT 语句的基本语法示例:
INSERT INTO target_table (target_column)
SELECT source_column
FROM source_table;
以下是语法的分步说明:
- 首先输入
INSERT INTO子句,后跟目标表的名称以及要插入数据的列名。 - 然后输入
SELECT关键字,后跟要从源表中提取数据的列名。 - 最后输入
FROM关键字以及包含该列或源数据的源表名称。

实战演练:填充国家数据
现在,我们通过一个具体的例子来演示如何使用 INSERT INTO SELECT 语句。我们将使用一个足球俱乐部数据库中的表。
在开始查询之前,我们先快速了解一下这些表。该数据库中有一个名为 Players 的表,它保存了球队中四名不同球员的记录。
此外,还有一个名为 Country 的表,用于保存这些球员所属国家的信息。但目前 Country 表中缺少国家名称数据,即它是空的。我可以使用 INSERT INTO SELECT 语句执行 SQL 查询来填充这些缺失的数据。

还记得本节开头提到的源表和目标表的例子吗?在这个实例中,Players 表是我需要查询的源表,而 Country 表是 SQL 将放置我查询结果的目标表。
为了从源表查询数据并用它填充目标表,我需要编写一个 INSERT INTO SELECT 语句。请注意,为了演示方便,我已经将 Players 表中的球员数据按照其在 Country 表中必须出现的顺序进行了组织。
以下是执行此任务的具体步骤:
- 首先,点击 SQL 标签页打开代码编辑器。
- 然后,编写
INSERT INTO命令,后跟我的目标表名称,即Country表。 - 接着,在一对括号内声明查询数据必须插入到的列名。在这个例子中,该列名为
country_name。 - 下一步,输入
SELECT关键字,并声明我要在源表中查询的列,即country。 - 最后,输入
FROM关键字,并声明我要从中查询数据的源表名称,即Players表。 - 在查询语句末尾添加分号,然后运行它。
执行查询后,我从数据库中选择 Country 表(我的目标表),并检查 country_name 列是否已填充了正确的数据。

总结


本节课中我们一起学习了 INSERT INTO SELECT 语句。你现在已经知道如何查询源表中的数据,并将其插入到目标表中,从而高效地填充或迁移数据。
入门 23:更新数据 📝
在本节课中,我们将学习如何使用 SQL 的 UPDATE 语句来修改数据库表中已有的数据。我们将通过具体的例子,演示如何更新单个学生的信息,以及如何批量更新多个学生的记录。
概述
UPDATE 语句是 SQL 中用于修改表中现有记录的核心命令。通过结合 SET 子句指定要更改的列和新值,并使用 WHERE 子句精确选择要更新的行,我们可以灵活地管理数据。
更新单个学生的记录
上一节我们介绍了 UPDATE 语句的基本概念。本节中,我们来看看如何更新表中特定学生的信息。
假设我们有一个名为 StudentTable 的表,包含以下字段:Id、FirstName、LastName、HomeAddress、CollegeAddress、ContactNumber 和 Department。
现在,我们需要更新 Id 为 3 的学生的家庭住址和联系电话。
以下是执行此操作的 SQL 语法步骤:
- 使用
UPDATE子句,后跟要更新的表名。 - 使用
SET子句,指定要更新的列及其新值。 - 使用
WHERE子句,精确指定要更新的记录。
对应的 SQL 代码如下:
UPDATE StudentTable
SET HomeAddress = '123 New Street',
ContactNumber = '555-0123'
WHERE Id = 3;
执行此语句后,数据库会返回确认消息。检查表格,可以看到 Id 为 3 的学生的 HomeAddress 和 ContactNumber 字段已更新为新值。
批量更新多个学生的记录
学会了更新单条记录后,我们进一步探讨如何批量更新满足特定条件的多条记录。
例如,假设学校的工程系已将课程迁至校园内的新地点“Harper Building”。我们需要为所有工程系的学生更新 CollegeAddress 字段。
以下是批量更新的 SQL 语法:
UPDATE StudentTable
SET CollegeAddress = 'Harper Building'
WHERE Department = 'Engineering';
此语句会将 Department 列为 ‘Engineering’ 的所有学生的 CollegeAddress 更新为 ‘Harper Building’。
同时更新多个字段
UPDATE 语句的强大之处在于,它可以一次性更新多个列。
例如,如果我们想同时更新工程系学生的学院地址和家庭地址,可以在 SET 子句中添加多个“列-值”对。
以下是更新多个字段的语法示例:
UPDATE StudentTable
SET CollegeAddress = 'Harper Building',
HomeAddress = '456 Maple Ave'
WHERE Department = 'Engineering';
在这个例子中,我们用一个 UPDATE 语句更新了两列数据。
关键点:在 SET 子句中,多个“列=值”配对之间必须用逗号分隔。
总结

本节课中我们一起学习了 SQL UPDATE 语句的用法。
- 我们掌握了如何使用
UPDATE ... SET ... WHERE ...语法来更新表中的特定记录。 - 我们实践了更新单个学生信息的方法。
- 我们学习了如何通过
WHERE子句筛选条件,来批量更新多个学生的记录。 - 最后,我们了解了如何在一个语句中同时更新多个字段的值。

正确使用 UPDATE 语句是管理和维护数据库数据准确性的关键技能。
入门 24:删除数据 📝
在本节课中,我们将学习如何使用 SQL 的 DELETE 语句从数据库表中删除数据。我们将通过三个具体示例,分别演示如何删除单条记录、多条记录以及表中的所有记录。理解 DELETE 语句的正确用法对于管理数据库内容至关重要。
删除单条记录示例
上一节我们概述了本节课的目标,本节中我们来看看如何从表中删除单条特定记录。
我将使用大学数据库中的学生表,目标是删除姓氏为 Miller 的学生记录。
我进入 phpMyAdmin 的 SQL 选项卡,编写一个以关键字 DELETE FROM 开头的删除语句。
然后我指定表名为 student_table。我添加一个 WHERE 子句和条件来指定要删除的数据。
我需要数据库扫描学生列表,识别出姓氏值为 Miller 的记录。
然后将该记录从表中删除。因此我输入 WHERE,后跟 last_name = 'Miller'。
我随后按下“执行”按钮来运行这条语句。
我收到一条确认信息,表明 Miller 的记录已从数据库中删除。
我然后可以在左侧面板访问学生表,以确保 Miller 的记录或实例已被移除。
删除多条记录示例
了解了单条记录的删除后,现在我们来探索另一个例子,这次从学生表中删除多条记录。
现在我想删除工程系两名学生的记录。
语句的开头部分与上一个示例相同。
我以 DELETE FROM 关键字开始,后跟我正在使用的表名,即 student_table。
WHERE 子句是本例的关键区别。
我输入 WHERE,后跟 department = 'Engineering'。
这指示 SQL 识别 department 列中值为 Engineering 的所有记录。
并将这些行从表中移除。但我需要小心。
如果我未正确指定 WHERE 子句,那么表中的所有记录都将被删除。
现在我已经完成了语句的编写,我选择“执行”来运行它。
我然后通过点击左侧面板中的表来检查它。
并确认两名工程系学生的记录已从表中删除。
删除所有记录示例
最后,让我们快速了解如何删除表中的所有记录。在这个任务中,语法与前几个示例大体相同。
关键区别在于我去掉了 WHERE 子句,因此现在我的语法只是声明 DELETE FROM student_table。
我去掉了 WHERE 子句,所以现在我的语法只是声明 DELETE FROM student_table。
换句话说,我指示数据库删除学生表中的所有记录。然后我点击“执行”。
并确认删除操作。一旦删除被确认,我检查学生表。

该表现在是空的。

我现在知道所有记录都已被删除。
核心语法总结
以下是本节课涉及的 DELETE 语句核心语法:
- 删除特定记录:使用
DELETE FROM结合WHERE子句来指定条件。DELETE FROM table_name WHERE condition; - 删除所有记录:仅使用
DELETE FROM语句,不包含WHERE子句。DELETE FROM table_name;

重要提示:DELETE 操作是不可逆的。在执行不带 WHERE 子句的 DELETE 语句前务必谨慎,因为它会清空整个表。

课程总结
本节课中我们一起学习了 SQL DELETE 语句的使用。我们通过三个循序渐进的示例,掌握了如何删除单条记录、根据条件删除多条记录以及清空整个表。请始终牢记,在执行删除操作,尤其是批量删除时,仔细核对 WHERE 条件至关重要,以避免意外数据丢失。
入门 25:模块小结 - CRUD操作 📊
在本节课中,我们将回顾整个模块的核心内容,即数据库的CRUD操作。我们将总结如何创建、读取、更新和删除数据,并回顾SQL数据类型等关键概念。通过本小结,你将巩固已学技能,为成为数据库工程师打下坚实基础。
模块内容回顾
本模块中,你学习了如何在数据库中进行创建、读取、更新和删除数据。你还研究了不同的SQL数据类型,例如数值型、字符串型和默认值。
现在,我们来回顾你学到的关键主题和掌握的技能。
SQL数据类型介绍
模块开始时,我们介绍了SQL数据类型。
完成第一课后,你现在能够识别和理解数值数据类型,以便将数据以数字形式存储在数据库中,在数据库中使用数值数据类型,并区分整数和小数数据类型,从而存储不同大小的数值,包括正数和负数。

以下是数值数据类型的核心概念:



- 整数类型:用于存储没有小数部分的数字,例如
INT。 - 小数类型:用于存储包含小数部分的数字,例如
DECIMAL(10, 2)。
在探索了数值数据类型之后,我们接着研究了字符串数据类型。

在研究过程中,你学会了如何识别和理解数据库中的字符串数据类型。
以下是字符串数据类型的核心概念:

- 固定长度字符串:使用
CHAR(n)定义,始终占用n个字符的空间。 - 可变长度字符串:使用
VARCHAR(n)定义,最多占用n个字符的空间,实际占用空间根据数据长度变化。
本课学习的最后一个概念是默认值。

现在你已经完成了关于默认值的课程,你能够演示对数据库中约束概念的理解(使用SQL语法),并识别用于在表中设置默认值的默认约束。


默认值的核心语法是:
CREATE TABLE table_name (
column_name data_type DEFAULT default_value
);
作为本课的一部分,你还完成了一系列专注于SQL数据类型的练习。
成功完成这些练习后,你现在能够展示使用数值数据类型、字符串数据类型和默认值的能力,并概述如何为你的数据选择正确的数据类型。


创建和读取数据

完成SQL数据类型的学习后,我们接着探索了在数据库中创建和读取数据的主题。
现在你已经完成了这一课,你能够创建数据库和表,修改数据库表结构,以及删除数据库。

创建数据库和表的核心命令如下:
CREATE DATABASE db_name;
CREATE TABLE table_name (...);
ALTER TABLE table_name ...;
DROP DATABASE db_name;

你还可以演示如何使用SQL语法在数据库中创建表,使用SQL的ALTER TABLE语句修改表结构,以及使用SQL的INSERT语句向表中插入或添加数据。
插入数据的核心语法是:
INSERT INTO table_name (column1, column2) VALUES (value1, value2);



除了这些新技能,你还学会了如何使用SQL的SELECT语句从表中检索数据,以及如何使用INSERT INTO ... SELECT语句将一个或多个表中的查询数据插入到另一个目标表中。
数据检索与插入的核心语法:
SELECT * FROM table_name;
INSERT INTO target_table SELECT * FROM source_table;


你也有机会通过一系列练习来展示这些新技能。
在这些练习中,你证明了你有能力创建数据库和表,然后向表中填充数据,并使用SELECT和INSERT INTO ... SELECT语句管理表中的数据。
更新和删除数据
接着,我们进入了最后一课,探索如何更新和删除数据。


完成本课后,你现在能够演示对SQLUPDATE语句的了解,并利用UPDATE语句更新记录的单字段和多字段值。
更新数据的核心语法是:
UPDATE table_name SET column1 = value1 WHERE condition;
最后,你还通过完成一个从表中删除记录的练习,证明了你在这些新技能方面的能力。
删除数据的核心语法是:
DELETE FROM table_name WHERE condition;



总结 🎯
本节课中,我们一起学习了数据库的核心CRUD操作。你现在已经熟悉了创建、读取、更新和删除操作,并且熟练掌握了SQL数据类型的使用。
你正在成为一名数据库工程师的道路上稳步前进。
入门 26:SQL算术运算符 🧮
在本节课中,我们将要学习SQL中的算术运算符。这些运算符能帮助我们在数据库中执行数学计算,例如计算员工薪资调整或津贴变化。通过掌握它们,你可以高效且准确地处理数据。
什么是SQL运算符?
上一节我们介绍了算术运算符的应用场景,本节中我们来看看运算符本身是什么。

运算符是SQL中特定的单词或字符,用于在数据库中执行各种操作。它们类似于造句时使用的连词,或者计算器上用于执行计算的按键。
为什么需要了解运算符?

当处理数据库中的数据时,你经常需要出于不同目的来查询和操作数据。SQL运算符使你能够根据需要操作数据,以执行这些不同的活动。
例如,你可以使用算术运算来计算员工剩余的年假天数,或者比较员工是否达到了公司目标。
SQL运算符的类型

SQL中有多种类型的运算符,每种都有不同的功能。让我们先重点探索算术运算符。
算术运算符在计算机语言中常用于执行计算并返回结果。与数学中的常见算术运算符类似,你可以在SQL中使用算术运算符在数据库中进行数学运算。
以下是SQL算术运算符及其符号:
- 加号 (+) 用于加法。
- 减号 (-) 用于减法。
- 星号 (*) 用于乘法。
- 正斜杠 (/) 用于除法。
- 百分号 (%) 用于取模(返回除法运算的余数)。


SQL算术运算如何工作?
在执行计算时,一个运算符作用于两个操作数并返回结果。

例如,一个加法运算符可以取两个操作数 5 和 5,并返回结果 10。用公式表示就是:5 + 5 = 10。

在SQL中,你可以通过使用 SELECT 命令来应用相同的概念。

让我们用加法运算符来说明这个概念。你可以使用 SELECT 命令,后跟第一个操作数、加法运算符和第二个操作数。就像前面的例子一样,SQL会计算两个操作数并产生结果。
SELECT 5 + 5;
你可以用其他算术运算符重复这个SQL语法:
- 使用减法运算符
SELECT 5 - 5;,输出结果是0。 - 乘法运算符
SELECT 5 * 5;返回结果25。 - 除法运算符
SELECT 5 / 5;计算结果为1。 - 取模运算符
SELECT 5 % 5;的结果是0,因为5除以5等于1,没有余数。

在SQL中使用算术运算符
现在,让我们更仔细地看看如何在SQL中使用这些算术运算符。我将演示如何使用算术运算符来执行基本的数学运算。

首先,让我们尝试一个加法运算来将两个数字相加。
- 我使用
SELECT命令。 - 然后输入数字
10和15,用加号运算符+分隔。 - 最后跟一个分号
;。虽然在这种情况下分号是可选的,但我仍然倾向于使用它,因为它代表一个SQL语句的结束。
SELECT 命令会检索 10 加 15 的和这个值,并将其显示在屏幕上。
SELECT 10 + 15;
运行此查询,查询会生成示例加法运算的结果,即 25。


正如我执行这个加法操作一样,我同样可以使用减法、乘法、除法和取模运算符。
- 我可以使用减号
-进行减法。 - 使用星号
*进行乘法。 - 使用正斜杠
/进行除法。 - 使用百分号
%进行取模。

例如,我可以输入:
SELECT 100 % 10;
这将 100 除以 10,并给我除法运算的余数。在这种情况下,余数是 0,因为 100 除以 10 等于 10,没有余数。运行查询后,余数 0 就会显示出来。

这就是你如何在SQL中使用运算符符号进行不同基本运算的方法。

总结
本节课中我们一起学习了SQL算术运算符以及如何在SQL中使用它们执行基本运算。你现在已经了解了加法 (+)、减法 (-)、乘法 (*)、除法 (/) 和取模 (%) 运算符的用法。接下来,你已经准备好学习如何以更实际的方式应用这些算术运算符了。
入门 27:运算符应用 🧮
在本节课中,我们将学习如何在数据库的实际操作中应用SQL算术运算符。我们将通过一个员工数据表的例子,演示如何使用加、减、乘、除和取模运算符来执行各种计算,从而从数据中提取有价值的信息。
上一节我们介绍了SQL算术运算符的基本概念,本节中我们来看看如何将它们应用到真实的数据表上。
使用加法运算符
假设雇主想给团队中的每位员工发放500美元的奖金,并希望先查看加上奖金后每位员工的薪水情况。
以下是实现此目标的SQL查询语句:
SELECT salary + 500 FROM employee;
此SELECT命令从employee表中检索每位员工的薪水值,然后为每个值加上500美元。执行此查询后,结果将显示每位员工增加了500美元后的薪水。
使用减法运算符
接下来,假设雇主想从每位员工的薪水中扣除500美元。
以下是相应的SQL查询:
SELECT salary - 500 FROM employee;
这里同样使用SELECT命令检索薪水值,但这次使用减号(-)从每位员工的薪水中减去500美元。执行查询后,数据库将返回扣除后的薪水结果。
使用乘法运算符
现在,考虑一个场景:雇主希望通过将当前年薪翻倍来增加员工薪水。
以下是完成此计算的SQL语句:
SELECT salary * 2 FROM employee;
该语句使用乘号(*)将每位员工的薪水值乘以2。执行查询将生成薪水翻倍后的输出结果。
使用除法运算符
假设雇主需要确定每位员工的月薪。我们可以将年薪除以12个月来计算。
以下是相应的查询语句:
SELECT salary / 12 FROM employee;
SELECT命令检索年薪值,然后除号(/)将其除以12。执行后,输出结果即为每位员工的月薪。
使用取模运算符
在最后一个例子中,雇主想知道每位员工的ID是偶数还是奇数。我们可以使用取模运算符来完成此任务。
以下是使用的SQL语句:
SELECT ID % 2 FROM employee;
此语句将每位员工的ID除以2,并返回除法运算的余数。余数为0表示ID是偶数(因为所有偶数都能被2整除,没有余数)。根据结果,可以判断出有三个奇数ID和两个偶数ID。


本节课中我们一起学习了如何在实际数据库操作中应用SQL的算术运算符。我们通过具体的员工表示例,演示了如何使用+、-、*、/和%运算符来执行薪资调整、月薪计算以及数据奇偶性判断等任务。掌握这些运算符的应用是进行有效数据查询和计算的基础。
入门 28:SQL比较运算符 🔍
在本节课中,我们将要学习SQL比较运算符的概念及其在数据库中的实际应用。比较运算符是SQL查询中用于筛选数据的重要工具,通过它们可以精确地检索出满足特定条件的记录。
什么是SQL比较运算符? 🤔
上一节我们介绍了课程目标,本节中我们来看看比较运算符的定义。比较运算符用于比较两个值或表达式,其比较结果可以是真(True)或假(False)。

它们主要用于过滤数据,以包含或排除特定的数据集。

SQL中的比较运算符 📊
SQL使用常见的数学比较运算符,通过符号来表示。以下是SQL中可用的主要比较运算符:
以下是SQL中常用的比较运算符列表:

- 等于:
= - 小于:
< - 大于:
> - 小于或等于:
<= - 大于或等于:
>= - 不等于:
<>或!=
实践:在数据库中使用比较运算符 💻
现在,让我们通过一个实际的数据库例子来探索如何使用这些比较运算符及其符号。
为了演示SQL比较运算符的用法,我将使用一个公司数据库中的员工表(employee)作为例子。该表包含每位员工的ID、姓名和薪资信息。
假设雇主需要从员工表中提取关于员工薪资的相关数据用于不同目的,每种数据提取情况都需要使用不同的比较运算符。
示例一:查找薪资等于特定值的员工

在第一个例子中,雇主希望找出所有年薪等于$18,000的员工。我可以使用等于(=)运算符来识别这些员工。
首先,在主菜单中点击SQL标签页,然后编写以下SQL语句:
SELECT * FROM employee WHERE salary = 18000;
让我们分解这个SQL语句:SELECT命令用于检索数据,星号(*)表示选择所有列的数据,FROM关键字和表名指定了数据的来源,然后我使用WHERE子句来定义条件。
在这个例子中,条件使用等于符号来检查表中每条记录的薪资值是否等于$18,000。如果结果为真,则检索该数据。执行查询后,会生成输出结果。

此查询的输出结果是:员工Carl和John的年薪为$18,000。

示例二:查找薪资低于特定值的员工
我们可以用类似的方式应用其他比较运算符来执行不同的功能。让我们看另一个例子来了解更多。
在下一个例子中,雇主需要知道哪些员工的年薪低于$24,000。这个任务需要使用不同的运算符。为了找到这个信息,我可以编写:
SELECT * FROM employee WHERE salary < 24000;
这条SQL语句利用了小于(<)符号来检查薪资列中每个字段存储的值是否小于$24,000。

再次点击执行按钮来运行查询并生成输出。

此查询的输出是:员工Carl和John的薪资低于$24,000。
示例三:查找薪资小于或等于特定值的员工
让我们再看一个例子,雇主需要确定哪些员工的年薪小于或等于$24,000。在这种情况下,我需要编写以下查询:
SELECT * FROM employee WHERE salary <= 24000;
这条语句与上一个例子唯一改变的地方就是运算符符号。

这个小于或等于(<=)符号告诉SQL语句去检查薪资列中每个字段存储的值是否小于或等于$24,000。
点击执行按钮来运行查询。输出结果显示,有四名员工的年薪小于或等于$24,000。

示例四:查找薪资大于或等于特定值的员工
如果雇主想知道哪些员工的年薪大于或等于$24,000呢?
为了生成这些结果,我可以在SQL语句中使用大于或等于(>=)运算符。因此,我编写以下SQL查询:
SELECT * FROM employee WHERE salary >= 24000;

这次,使用大于或等于符号来检查薪资列中每个字段存储的值是否大于或等于$24,000。点击执行来运行查询,输出显示有三名员工的年薪达到或超过$24,000。

示例五:查找薪资不等于特定值的员工
SQL中最后一个可用的比较运算符是不等于运算符。
在最后一个例子中,雇主想知道哪些员工的年薪不等于$24,000。我可以使用以下SQL代码来确定:
SELECT * FROM employee WHERE salary <> 24000;
与之前的运算符一样,SQL语句利用该运算符来检查薪资列中每个字段存储的值。在这种情况下,它检查的是不等于$24,000的值。

此查询的输出结果显示,有三名员工的薪资不等于$24,000。

总结 📝
本节课中我们一起学习了SQL比较运算符。你现在应该能够描述比较运算符的概念,并在SQL数据库中运用它们。具体来说,我们掌握了如何使用=、<、>、<=、>=和<>这些运算符,通过WHERE子句来过滤和检索满足特定条件的数据记录。恭喜你掌握了这项重要的数据库技能!
入门 29:ORDER BY子句 📊
在本节课中,我们将要学习SQL中一个非常实用的子句——ORDER BY。它用于对数据库表中的数据进行排序。通过本课,你将能够理解ORDER BY子句的用途,掌握其基本语法,并学会如何使用它对单列或多列数据进行升序或降序排列。
探索ORDER BY子句的用途 🎯
上一节我们介绍了SQL的基本查询结构,本节中我们来看看如何对查询结果进行排序。ORDER BY子句是一个可选子句,可以附加在SELECT语句之后。它的主要目的是帮助数据按升序或降序进行排序。例如,你可以将一个学生姓名列表按字母顺序从A到Z排序,或者反之。

理解ORDER BY子句的语法 📝
为了更好地理解ORDER BY子句的工作原理,让我们先来探索其语法结构。
在其最基本的形式中,ORDER BY子句的语法如下:

SELECT column1, column2, ...
FROM table_name
ORDER BY column1 [ASC|DESC];
它以一个SELECT语句开始。然后是要排序的列名列表,每列之间用逗号分隔。接着是FROM关键字,后跟要排序的表名。最后,添加ORDER BY子句,后跟要排序的列名。在列名末尾,指定你希望数据排序的方式,可以通过指定ASC表示升序,或DESC表示降序。
但ORDER BY子句并不局限于单列排序。你也可以使用以下语法对多列数据进行排序。
以下是排序多列的语法示例:
SELECT column1, column2, ...
FROM table_name
ORDER BY column1 [ASC|DESC], column2 [ASC|DESC], ...;
与单列排序的关键区别在于,你必须在ORDER BY子句后键入每个列的名称。只需确保用逗号分隔每个列,并指定你希望每列是按升序还是降序排序。
你也可以通过在SELECT关键字后使用星号*来指定所有列。

SELECT *
FROM table_name
ORDER BY column1 [ASC|DESC];
这比逐一列出所有列要简便得多。
最后,同样重要的是要注意,表中数据的类型会影响其排序方式。如果列是数值数据类型,记录将按升序或降序的数值顺序排序。如果列是基于文本或字符串数据类型,则将按升序或降序的字母顺序排序。

ORDER BY子句应用示例 💻
接下来,让我们探索一些在SQL语句中使用ORDER BY子句的示例。
按单列排序数据

让我们从一个按单列排序数据的示例开始。在这个例子中,我将使用一个列出大学学生详细信息的表。我需要按每个学生的国籍升序来排序或整理这些数据。因此,在这种情况下,ORDER BY的列必须是每个学生的国籍。每个学生的国籍列在表的第五列。
以下是实现此排序的SQL语句:
SELECT id, first_name, last_name, nationality
FROM student_table
ORDER BY nationality ASC;
我首先编写一个SELECT语句,后跟结果中想要的列名:id、first_name、last_name和nationality。然后我写上FROM关键字,后跟表名student_table。接着,我键入ORDER BY子句。然后我指定要按其排序数据的列名,即nationality。最后,我键入ASC,以便数据按升序排序。然后我执行该语句。
表现在已根据国籍按升序对所有学生进行了排序。请注意,即使我从代码末尾省略ASC,我仍然会得到相同的结果。这是因为ORDER BY子句默认按升序对所有数据进行排序。

让我们运行相同的语句,但这次使用DESC(降序)而不是ASC。


SELECT id, first_name, last_name, nationality
FROM student_table
ORDER BY nationality DESC;
表现在已第二次按国籍对学生进行了排序,但这次是按降序或反向字母顺序排序的。

按多列排序数据
最后,让我们探索一个按多列排序数据的示例。在这个例子中,我将按国籍和出生日期对学生进行排序。
以下是实现此排序的SQL语句:
SELECT id, first_name, last_name, date_of_birth, nationality
FROM student_table
ORDER BY nationality ASC, date_of_birth DESC;
首先,我编写SELECT语句。然后写上结果中想要的列名:id、first_name、last_name、date_of_birth和nationality。接着,我写上FROM关键字和表名student_table。然后,我键入ORDER BY子句,并指定要按其排序数据的列名,即nationality和date_of_birth。我在nationality后添加ASC,以便数据按国籍升序排序。我在date_of_birth后添加DESC,以便该列的数据将按降序排序。然后我运行该语句。

这将返回我的表,其中指定列的数据按照指示进行组织:国籍按字母顺序,出生日期从最年轻到最年长(降序)。
总结 ✨
本节课中我们一起学习了SQL的ORDER BY子句。你现在可以演示ORDER BY子句用于排序数据的目的,并且可以解释使用ORDER BY子句排序数据的不同形式。我们还通过示例练习了如何对单列和多列进行升序及降序排序。掌握ORDER BY是有效组织和分析查询结果的关键一步。
入门 30:WHERE子句 📊
在本节课中,我们将学习SQL中WHERE子句的用途与使用方法。WHERE子句用于从数据库表中筛选出满足特定条件的记录,是数据查询中不可或缺的部分。
什么是WHERE子句? 🔍

WHERE子句用于过滤数据。具体来说,它用于筛选并提取满足指定条件的记录。

为了更好地理解WHERE子句的用法,我们可以先分解其在SQL SELECT语句中的语法结构。
WHERE子句的语法结构 📝

SQL SELECT语句的标准语法以SELECT关键字开始,后跟要查询的列名。接着是FROM子句,指定表名。然后可以引入WHERE子句。在WHERE子句之后,可以指定具体的筛选条件。
您可能想知道条件的作用是什么。条件使得从表中筛选并获取所需记录成为可能。您可以将条件视为筛选标准。

只有满足条件的记录才会被检索出来。例如,您可以使用条件来检查目标列的值是否等于某个特定值。
在列名和值之间,您可以放置一个运算符。

运算符与操作数 🔧

正如您刚刚了解到的,运算符后面跟着操作数。让我们更详细地了解一下。操作数可以是文本值或数值,这完全取决于表列或字段的数据类型。

为了演示,我们来看一个例子:student_id = 1。在这个例子中,条件被指示去筛选一个数值,因此它作为一个筛选标准。

一旦您运行这个SQL SELECT语句,它就会按照指示检索出记录。

让我们看另一个例子:first_name = 'John',这是一个文本值。所有文本值都必须用一对单引号括起来。

再次,您只需运行SQL SELECT语句,它就会筛选出所需的记录。
可用的运算符类型 📚

为了指定您的筛选条件,您可以使用多种运算符。您刚刚回顾了等号运算符的例子,其他运算符您可能在前面的课程中已经遇到过。
让我们快速回顾一下这些其他运算符。SQL比较运算符包括:
- 等于 (
=) - 小于 (
<) - 大于 (
>) - 小于或等于 (
<=) - 大于或等于 (
>=) - 不等于 (
<>或!=)
除了这些符号,WHERE子句还可以使用BETWEEN、LIKE和IN运算符。
- 使用
BETWEEN运算符,您可以筛选特定数值或时间日期范围内的记录。 LIKE运算符用于在WHERE子句的筛选条件中指定一个模式。IN运算符用于为列指定多个可能的值。

WHERE子句实践示例 💻
现在,让我们探索一些在SELECT语句中使用WHERE子句的例子。

回想一下管理系希望为其工程和科学专业学生创建报告的场景。我可以使用WHERE子句来筛选出属于工程学院的学生的详细信息。
在这种情况下,我需要从学生表中检索所有详细信息(所有列),所以我写SELECT * FROM student_table。接着,我输入WHERE,后跟筛选条件。条件写为faculty = 'Engineering'。文本值'Engineering'需要用单引号括起来。这样,我就指示我的SQL只获取隶属于工程学院的学生详细信息。

然后我运行查询。

根据筛选条件,它确实检索出了学生表中列出的三位工程学院学生的记录。请注意,我本可以用其他运算符,如大于、小于、小于或等于、大于或等于、不等于,用法与这个WHERE子句条件中的等号运算符相同。
您可以将这些运算符中的任何一个与数值或操作数一起使用。

现在让我们回顾一些在WHERE子句条件中使用BETWEEN、LIKE和IN运算符的例子。
使用 BETWEEN 运算符
学院有一个针对特定年龄学生的财政援助计划,资助部门希望只通知符合条件的学生。我可以在WHERE子句条件中使用BETWEEN运算符来筛选学生表中的记录。
和之前一样,我输入SELECT * FROM student_table,后跟WHERE。在WHERE关键字之后,我指定筛选列为DOB(出生日期)。然后我插入BETWEEN运算符。最后,我给出日期范围'2010-01-01' AND '2010-06-30'。

运行此查询会检索出四位出生日期落在指定日期范围内的学生的记录。

请注意,我在这里可以使用任何数值范围,不仅仅是日期。
使用 LIKE 运算符
对于下一个例子,假设管理部门需要科学学院学生的详细信息。我可以用LIKE运算符来实现,当您想在WHERE子句筛选条件中指定一个模式时,可以使用它。
在SELECT语句中,WHERE关键字之后,我输入faculty(学院列),然后是LIKE运算符,接着是'Sci%'(用单引号括起来)。模式中的百分号%是一个通配符,代表零个、一个或多个字符。下划线_也可以用来代表一个单一字符。
在这个例子中,我的WHERE子句要求我的SQL搜索并筛选faculty列中以'Sci'开头,后跟任意数量字符的值。所以我运行该语句,它筛选出了五位学院列值为'Science'的学生记录,即以'Sci'模式开头。
使用 IN 运算符

在最后一个例子中,管理部门需要了解在特定地点学习的学生的详细信息。


您可以在WHERE条件中使用IN运算符来检索相关的学生记录。请记住,IN运算符用于为列指定多个可能的值。

在SELECT语句中,WHERE关键字之后,我输入列名country,然后是IN运算符,接着是一对开括号。在括号内,我放置值'USA'和'UK',每个都用单引号括起来。我的SELECT查询将筛选出country列值为'USA'或'UK'的所有学生记录。

运行此查询返回四条记录,两位来自美国的学生和两位来自英国的学生。
因此,IN运算符在country列中搜索多个可能的值,并基于它们进行筛选。

请注意,尽管本视频中的示例着眼于SELECT语句中的WHERE子句,但它也可以用于其他语句,例如UPDATE和DELETE。

总结 📋

在本节课中,我们一起学习了什么是WHERE子句。您现在应该知道如何使用它来过滤数据,以及如何使用不同的运算符。
出色的工作。
入门 31:SELECT DISTINCT子句 🎯
在本节课中,我们将要学习SQL中的SELECT DISTINCT子句。这个子句用于从数据库表中检索唯一不重复的值,是处理包含重复数据时非常有用的工具。我们将通过具体的例子来理解它的基本用法、在多列上的应用,以及它如何处理NULL值。
什么是SELECT DISTINCT? 🤔

SELECT DISTINCT语句的核心功能是返回唯一不同的值。顾名思义,它从查询结果中消除所有重复的行,只保留每条不同的记录。

其基本语法结构如下:
SELECT DISTINCT column_name
FROM table_name;
处理单列中的重复值

假设你有一个包含全球大学生记录的数据表。作为年度报告的一部分,你需要列出这些学生所属的所有不同国家。很可能许多学生来自同一个国家,那么如何检索出没有重复的结果呢?

以下是一个学生表的示例,其中country列包含重复值:


| 学生姓名 | 国家 |
|---|---|
| 学生A | 澳大利亚 |
| 学生B | 美国 |
| 学生C | 英国 |
| 学生D | 澳大利亚 |
| 学生E | 美国 |
| 学生F | 加拿大 |
| 学生G | 英国 |
如果使用普通的SELECT语句:
SELECT country FROM students;
你将得到7条记录,其中“澳大利亚”和“美国”会出现多次。

为了消除这些重复项并获取唯一的结果集,你需要使用SELECT DISTINCT语句:
SELECT DISTINCT country FROM students;
运行此语句后,结果中的每个国家将只出现一次,所有重复项都已被移除。

在多列上使用SELECT DISTINCT
上一节我们介绍了如何在单列上使用DISTINCT来获取唯一值。本节中我们来看看当DISTINCT应用于多列时会发生什么。
假设我们想确定不同院系(faculty)中分别有哪些国家的学生。我们可以同时指定faculty和country列:
SELECT DISTINCT faculty, country FROM students;
这条语句会返回faculty和country列的每一种唯一组合。例如,“科学院”可能有来自三个不同国家的学生,“工程学院”也可能如此。DISTINCT会将这些组合视为独立的记录,只返回不重复的组合。

SELECT DISTINCT与NULL值
现在,让我们探讨SELECT DISTINCT如何处理包含NULL值的列。

假设表中新增了一名来自美国的学生“Julia Smith”,但她尚未被分配院系,因此其faculty列的值为NULL。
当我们再次运行之前的多列DISTINCT查询时:
SELECT DISTINCT faculty, country FROM students;
查询结果将包含一条记录,其faculty为NULL,country为“美国”。这是因为DISTINCT子句将NULL视为一个唯一值。因此,(NULL, ‘USA’)被作为一个独特的院系与国家组合输出。

总结 📝

本节课中我们一起学习了SELECT DISTINCT子句的用法。我们了解到:
SELECT DISTINCT用于从查询结果中消除重复行。- 它可以应用于单列,以返回该列的所有唯一值。
- 当应用于多列时,它返回这些列值的所有唯一组合。
DISTINCT将NULL视为一个有效的唯一值,并将其包含在结果集中。
掌握SELECT DISTINCT能帮助你更高效地分析和汇总数据,尤其是在需要获取不重复列表或进行初步数据探查时。
入门 32:模块小结 - SQL运算符以及对数据进行排序和筛选 📊
在本节课中,我们将一起回顾和总结SQL运算符、数据排序与筛选的核心知识。你将学习如何运用算术与比较运算符处理数据,如何使用WHERE和ORDER BY子句来筛选和排序数据,以及如何使用SELECT DISTINCT来消除重复值。
你已经完成了SQL运算符以及数据排序和筛选部分的学习。
在数据库中存储大量数据固然重要,但理解这些数据的意义更为关键。

因此,掌握使用SQL来操作数据成为了一项备受追捧的技能。你可能还记得,SQL运算符可以完成诸如算术运算和比较等任务。

数据可以使用WHERE子句进行筛选,并使用ORDER BY子句进行排序。
最后,让我们来回顾一下本模块的要点。


在本模块结束时,你现在应该能够演示SQL算术运算符在表中的使用。
演示SQL比较运算符在数据库中的使用,描述ORDER BY子句的用途,并演示基于单列和多列的升序与降序排序。

在关于数据筛选的视频中,WHERE子句与SQL SELECT语句结合使用来过滤记录。
对于WHERE子句,你现在应该能够解释其用途,描述它如何用于筛选数据,并演示如何将SQL WHERE子句与比较运算符结合使用。


最后,你还探索了SELECT DISTINCT子句。
完成这部分后,你现在应该能够解释SELECT DISTINCT的用途,描述它如何用于消除重复值,并演示在单列、多列以及包含NULL值的情况下使用SELECT DISTINCT。
完成本模块后,你现在应该能够对数据库中的数据执行一些SQL操作。


这是赋予数据真正价值的第一步。凭借你的SQL技能,数据库现在不再仅仅是一个存储仓库,它还是一个你可以深入探究并从中得出结论的工具。

总结 📝
本节课中我们一起学习了SQL的核心操作技能。我们回顾了如何使用算术和比较运算符处理数据,掌握了通过WHERE子句筛选特定记录,以及使用ORDER BY子句对结果进行排序。此外,我们还了解了SELECT DISTINCT在消除查询结果中重复值方面的应用。这些技能是将原始数据转化为有价值信息的基础,使你能够有效地分析和利用数据库内容。
入门 33:数据库模式 🗂️
在本节课中,我们将要学习数据库模式的概念。数据库模式是数据库设计的蓝图,它定义了数据的组织方式和相互关系。理解模式对于规划和构建高效、安全的数据库至关重要。
什么是数据库模式? 🧩

在开发数据库或软件应用程序之前,首先需要规划如何组织数据。这个规划被称为模式。它本质上是数据外观的蓝图。
上一节我们介绍了模式的基本定义,本节中我们来看看不同数据库系统对“模式”一词的具体解释。
不同数据库系统中的模式含义 🔄

“模式”的一般含义是信息的组织或分组以及它们之间的关系。然而,该术语在不同数据库系统中的定义有所不同。
以下是几种主要数据库系统中“模式”的含义:

- 在MySQL中:模式意味着数据结构的集合,或数据在数据库中存储方式的抽象设计。本质上,在MySQL中,模式(schema)和数据库(database)是可互换的术语。模式定义了数据在数据库中的组织方式以及与其他数据的关系。
- 在SQL Server中:数据库模式是不同组件(如表、字段、数据类型和键)的集合。
- 在PostgreSQL中:数据库模式是一个命名空间,其中包含命名数据库对象,如视图、索引和函数。
- 在Oracle中:系统为每个用户分配一个单一的模式。Oracle甚至以相应用户的名字来命名每个模式。
无论遇到哪种类型的数据库,在处理模式时需要理解的两个最重要的概念是相同的:以表形式组织数据,以及表之间的关系。

数据库模式的组成部分 🧱
现在我们已经了解了模式的含义,接下来详细看看它的构成部分。以SQL Server为例,一个模式由所谓的模式对象组成。
以下是构成数据库模式的主要组件:

- 表(Tables):存储数据的基本单元。
- 列(Columns):表中的字段,定义了数据的属性。
- 关系(Relationships):表与表之间的连接。
- 数据类型(Data Types):定义列中可以存储的数据种类,例如
INT、VARCHAR(255)、DATE。 - 键(Keys):用于唯一标识记录(主键)或建立表间关系(外键)。

一个SQL数据库模式的例子可以是一个音乐数据库,其中包含艺术家、专辑和流派的数据,它们都存储在不同的表中。然而,这些表仍然可以通过各种键相互关联。
换句话说,该数据库中的数据被组织在独立的表或实体中,但这些表彼此相关。本质上,一个数据库模式由所有重要的数据及其关系、所有条目和数据库的唯一键,以及表中每一列的名称和数据类型组成。

数据库模式的优势 ✨

既然你已经熟悉了什么是数据库模式,让我们继续探讨使用数据库模式的优势。
以下是数据库模式提供的主要优势:

- 提供逻辑分组:模式为数据库对象(如表、视图)提供了逻辑分组,使管理更加清晰。
- 便于访问和操作:与其他可用方法相比,模式使得访问和操作这些数据库对象更加容易。
- 增强数据库安全性:可以根据用户的访问权限,授予、分离和保护数据库对象的权限,从而提高安全性。
- 支持所有权转移:可以在用户和其他模式之间转移模式及其对象的所有权。

总结 📝
本节课中我们一起学习了数据库模式的核心知识。我们了解到,数据库模式是一种表示数据库中数据存储方式的结构。你也明白了“模式”一词的含义如何在不同数据库系统中变化。最后,我们探讨了数据库模式在逻辑分组、易用性、安全性和管理灵活性方面带来的优势。掌握这些概念是成为一名合格数据库工程师的重要基础。
入门 34:模式应用 🛒
在本节课中,我们将学习如何使用SQL创建一个简单的数据库模式。我们将通过构建一个包含三个表的购物车数据库模式来完成这个任务。
创建数据库
首先,我们需要创建一个新的数据库。我们将其命名为 ShoppingCartDB。
以下是创建数据库的SQL语句:
CREATE DATABASE ShoppingCartDB;
执行这条语句后,ShoppingCartDB 数据库将出现在左侧的资源管理器中。
创建数据表
现在,我们可以在新创建的数据库中创建所需的表。我们将创建三个表:customer、product 和 cart_order。
客户表
首先,我们创建 customer 表,它用于存储每位客户的以下信息:客户ID、姓名、地址、电子邮件和电话号码。
以下是创建客户表的SQL语句:
CREATE TABLE customer (
customer_id INT PRIMARY KEY,
name VARCHAR(100),
address VARCHAR(255),
email VARCHAR(100),
phone VARCHAR(10)
);
在这条语句中,customer_id 的数据类型是整数,并被指定为 主键。其他字段均为可变字符类型,并设置了相应的字符长度限制。
产品表
接下来,我们创建 product 表,它用于存储产品ID、名称、价格和描述信息。
以下是创建产品表的SQL语句:
CREATE TABLE product (
product_id INT PRIMARY KEY,
name VARCHAR(100),
price NUMERIC(8, 2),
description VARCHAR(255)
);
这里,product_id 是整数类型的主键。price 字段使用了 NUMERIC(8,2) 类型,表示总共8位数,其中2位是小数。
购物车订单表
最后,我们创建 cart_order 表,它用于存储订单ID、客户ID、产品ID、数量、订单日期和状态。
以下是创建购物车订单表的SQL语句:
CREATE TABLE cart_order (
order_id INT PRIMARY KEY,
customer_id INT,
product_id INT,
quantity INT,
order_date DATE,
status VARCHAR(100)
);
order_id 被设置为此表的主键。然而,这个表引入了新的概念:外键。
理解主键与外键
在继续之前,让我们快速了解一下主键和外键是什么。
你可能已经注意到,cart_order 表中包含了 customer_id 和 product_id 字段,这两个字段也出现在另外两个表中。这是因为 cart_order 表中的这些字段直接链接到对应表中的相同字段。
为了建立这种关系,每个表必须包含一个主键。引用表则使用外键来指向外部源表(即被引用的表)。我们将在后续课程中更详细地学习主键和外键。
现在,让我们回到购物车数据库的例子。所有主键已经设置完毕,接下来需要为 cart_order 表设置外键。
添加外键约束
以下是添加外键约束的SQL语句:
-- 添加指向客户表的外键
ALTER TABLE cart_order
ADD FOREIGN KEY (customer_id) REFERENCES customer(customer_id);
-- 添加指向产品表的外键
ALTER TABLE cart_order
ADD FOREIGN KEY (product_id) REFERENCES product(product_id);
第一条语句创建了一个外键,将 cart_order 表的 customer_id 列链接到 customer 表的 customer_id 主键。
第二条语句类似,将 cart_order 表的 product_id 列链接到 product 表的 product_id 主键。

执行这些语句后,这些表将嵌套显示在左侧资源管理器的 ShoppingCartDB 数据库下方。
总结

本节课中,我们一起学习了使用SQL创建简单数据库模式的步骤。我们创建了一个名为 ShoppingCartDB 的数据库,并在其中定义了 customer、product 和 cart_order 三个表。我们了解了如何为表设置主键以唯一标识每条记录,以及如何使用外键在不同的表之间建立关系。这个过程对于创建小型或大型数据库都是适用的核心方法。
入门 35:数据库模式类型 📊
在本节课中,我们将学习数据库模式的不同类型,理解逻辑模式与物理模式的区别,并了解它们如何共同构成数据库应用的基础。
创建数据库时,需要能够区分不同类型的数据库模式。换句话说,需要回答“哪种数据库最适合我的项目”这个问题。接下来,我们将探讨几种不同的数据库模式类型。通过本视频的学习,你将能够解释逻辑数据库模式的概念,并概述物理数据库模式的概念。

探索逻辑数据库模式 🧠

首先,我们来探索逻辑数据库模式。逻辑数据库模式是指数据在表格层面的组织方式。换句话说,它展示了数据库中应该有哪些表格,并解释了不同表格的属性是如何关联在一起的。

创建逻辑数据库模式意味着描绘数据各组成部分之间的关系。这也被称为实体关系建模。
它具体说明了实体类型之间的关系。让我们以一个简单的ER模型为例,它展示了一个订单应用程序的逻辑模式。该模型演示了订单、运送该订单的货运单以及分配给该订单的快递员之间的关系。

在每个表格中,ID属性是各自实体的主键。它为实体中的每个条目、行或记录提供了唯一标识符。在订单实体中,to_shi_id和courier_id被称为外键,但实际上,它们也分别是货运单和快递员实体的主键。这就在这些实体与订单表之间建立了关系,而订单表又有自己的ID作为其主键。
理解物理数据库模式 💾

上一节我们介绍了逻辑模式如何描述数据关系,本节中我们来看看物理模式。物理模式是指数据在磁盘上的存储方式。换句话说,这涉及到使用代码创建数据库的实际结构。
在MySQL和其他关系型数据库中,开发者使用SQL来创建数据库、表格以及其他数据库对象。

例如,你可以通过编写SQL语句来为在线商店数据库创建物理模式,这些语句用于创建客户、产品和交易等表格。然而,不同数据库系统之间的物理模式创建可能略有不同。

总结 📝
本节课中,我们一起学习了数据库模式的核心概念。数据库模式在数据库创建过程中至关重要,它们构成了应用程序的基础。
你现在应该能够描述逻辑数据库模式如何指代数据和表格的组织方式,并且知道使用ER模型来指定实体之间的关系。同时,你现在也应该知道,可以通过编写SQL语句创建物理模式来控制数据在磁盘上的物理存储方式。
入门 36:表关系 📊
在本节课中,我们将要学习关系型数据库中表与表之间的关系。理解这些关系对于设计数据库结构以及高效地从中提取信息至关重要。我们将探讨关系模型的基础知识,识别表之间的不同关系类型,并解释实体关系图的基本概念。
在课程的这个阶段,你已经花了一些时间探索数据库的关系模型。然而,正确理解关系模型如何影响数据库的设计和结构,以及它如何帮助建立表之间的关系,是至关重要的。
一旦你理解了数据库的结构,你就能确定如何最好地从中提取信息。在接下来的几分钟里,你将学习如何概述关系模型的基础知识,识别表之间的不同关系,并解释实体关系图的基础。

为了理解关系模型如何影响我们的数据库,让我们以大学数据库中的两个表为例。
第一个表显示了学生列表,以及分配的学生ID和课程ID。

第二个表列出了学生可以学习的课程,以及每门课程的ID和所属院系。

那么,在这个例子中的核心问题是:哪个学生正在学习哪门课程?以及每个学生是学习一门还是多门课程?
这些例子说明了为什么正确构建和连接表非常重要。
在关系型数据库中,任意两个表之间存在三种类型的关系:一对多、一对一和多对多。

一对多关系

让我们从探索一对多关系开始。在一对多关系中,一个表中某一行的一条数据记录,与另一个表中不同行的多条记录相关联。

在学生表中,ID为1的学生在课程表中注册了两门课程。因此,可以在这些表之间建立一对多关系。
这种关系也可以用基本的实体关系图来描绘。使用形状和符号,可以表示一个学生注册了多门课程。
该图将“学生”和“课程”两个实体用矩形表示,用菱形表示“注册”关系,并使用鸦足符号表示“多”的一方。

这种关系也可以用更复杂的实体关系图来说明,该图描绘了键。学生表中的“课程ID”是一个外键,它引用了课程表中存在的主键“课程ID”列。

一对一关系
接下来,让我们看看一对一关系。在一对一关系中,一个表中的一条单一记录与另一个表中的一条单一记录相关联。
为了演示这种关系,我使用了两个新表。一个表概述了每个学院院系的关键人员信息,另一个是院系位置表,记录了校园内每个院系位置的关键数据。
在这个例子中,每个系主任都位于校园内的一栋系楼里。因此,院系人员表中的每位成员都与院系表中的一条记录相关联。
这些关系也可以在实体关系图中描绘为:一个系主任领导一个院系。

多对多关系

最后,还存在多对多关系。这种类型的关系将一张表的一条记录与另一张表的多条记录相关联,并且同样的关系在反方向也成立。
在这个例子中,学生Ma Doyle正在进行两个研究项目,每个项目由不同的教职员工指导。

同样地,一位教职员工可以指导或与多名学生在他们的研究项目上进行合作。
这些关系也可以在实体关系图中描绘为:多名学生由多名教职员工指导。



总结
本节课中,我们一起学习了关系型数据库模型中表之间存在的不同关系。你现在应该能够概述一对多、一对一和多对多关系的基本概念及其在实体关系图中的表示方法。理解这些关系是设计高效、结构清晰的数据库的基础。
入门 37:主键 🔑
在本节课中,我们将要学习主键在数据库中的作用。你将了解如何为数据库表选择合适的主键,包括单列主键和复合主键,并理解它们在不同场景下的应用。
查询特定记录的挑战

到目前为止,你可能已经熟悉了在数据库表中查询值或记录。但如果表中的数据存在重复,你该如何查询特定的记录和值呢?
当遇到此类障碍时,你可以使用“键”作为解决方案。
主键的作用
在本课程中,你可能已经遇到过几个主键的例子。在这些例子中,主键被用作唯一标识一条记录并防止重复的方法。
让我们以一个学生表为例,该表包含五个属性:ID、name、date of birth、email 和 grade。我们如何识别特定的学生来录入其成绩呢?
例如,第二行名为 Mary 的学生。你需要做的就是找到 Mary 的唯一 ID 来标识她的数据记录。

然而,在这个例子中,你不能使用学生姓名列,因为表中有两个学生都叫 Mary。你也不能使用出生日期列,因为另一个叫 Dan 的学生与 Mary 的生日相同。

这些记录对 Mary 而言都不是唯一的,那么最佳方法是什么?
候选键与主键的选择
解决方案是定位一个“候选键”。这是一个对表中每一行都唯一的属性,并且它不能有空值,换句话说,它不能为空。

在这个例子中,有两个可能的候选键:student ID 和 student email。两列都包含每个学生的唯一值。因此,任何一列都可以被用作主键。
让我们将 student ID 指定为主键。未被选为主键的那一列则成为“备用键”或“次键”。在这个例子中,email 列就是次键。

复合主键的应用
但是,如果你在表中找不到唯一的列怎么办?也许所有行都有重复的值。在这种情况下,你可以创建一个“复合主键”。
这种键是两个或更多属性的组合。
让我们以一个在线商店的配送部门为例。他们有一个配送表,用于跟踪客户的配送订单。然而,表中没有哪一列在每一行都有唯一值。因此,没有哪一列可以被视为主键。
在这种情况下,最佳方法是将 customer ID 和 product code 列组合起来,为每条特定的数据记录创建一个唯一值。通过这两列,你可以确定哪位客户订购了哪种产品。因此,这两列共同构成了复合主键。这个键可以用来跟踪每位客户的配送状态。

总结
本节课中,我们一起学习了单列主键和复合主键。你现在应该能够识别在何种情况下使用哪一种主键最为合适。
入门 38:外键 🔗
在本节课中,我们将要学习外键的概念。外键是关系型数据库中用于连接不同表、建立数据关联的核心机制。通过理解外键,你将能够设计出结构清晰、数据关联明确的数据库。
什么是外键? 🤔
上一节我们介绍了外键的基本概念,本节中我们来看看它的具体定义。

想象一个场景:一家书店的数据库包含两个表。一个Customer表用于追踪客户信息,一个Order表用于追踪客户订单。但如何确定哪个订单属于哪个客户呢?解决方案是在订单表中添加一个客户ID列作为外键。
那么,外键究竟是什么?


外键是一个或多个用于连接两个表的列,目的是在它们之间建立交叉引用。“外”意味着外部,因此一个表中的外键会引用另一个表中的外部列。

外键如何工作? ⚙️
了解了外键的定义后,我们通过一个在线商店的数据库示例来深入理解其工作原理。

商店的Customer表包含客户的姓名和地址信息。


而Order表则包含每个客户的订单日期和状态信息。问题在于:如何连接这两个表,以确保每个订单都能关联到正确的客户?

建立这种连接非常重要,以便你能将订单处理和配送给正确的客户、更新订单详情或在需要时取消订单。

外键是建立表之间关系以实现上述任务的绝佳方法。
但在学习如何使用外键之前,让我们花点时间更详细地探讨这个概念。
外键关系的细节 🔍
为了更深入了解外键的工作原理,我们以两个通用实体表的关系为例。这两个表称为表1(T1)和表2(T2)。连接这些表的目的是将两个表中存在的数据记录相互关联起来。

以下是外键关系的关键点:
- T1中的外键应指向T2中的相关列。
- 在这种情况下,T1中外键列的值必须与T2参考列中已有的值相对应。
- 并且,T2中的参考列在每一行数据中必须包含唯一值。这很可能是T2的主键。
- 此外,被引用的表T2被称为父表,而引用的表T1被称为子表。

如果这一切听起来有点复杂,别担心。让我们通过之前客户和订单表的实体关系图来简化理解。

实体关系图示例 📊
在这个图中,Order表通过包含CustomerID属性并将其定义为外键,从而与Customer表建立关联。


这两个表之间的关系是一对多。你可能在之前的视频中遇到过这种关系类型。一对多意味着每个客户可能有多个订单,但每个订单必须只引用一个客户。

这意味着,在生成任何订单之前,Customer表中必须已存在相应的客户记录。但是,创建一个新客户后,并不一定需要立即有订单。因此,Customer表代表父表,Order表代表子表。这意味着父表可以独立存在,而子表可能不存在。但相反的情况(子表存在而父表不存在)则不能发生。
在这个例子中,Order表中存在的CustomerID值可以用来获取特定客户的记录,以确定是谁下了订单,例如用于生成发票或将订单配送到客户地址。


多外键与多父表 👨👩👧
一个表也可以拥有多个外键。每个外键都用于将引用表(子表)与其他被引用表(父表)连接起来。在这种情况下,同一个子表可以有多个父表。
让我们在前面的图中添加一个新表Product表来更详细地解释这一点。现在,Order表有两个外键:一个通过CustomerID将其与Customer表链接,另一个通过ProductID将其与Product表链接。


这些表之间的关系是一对一。每个订单必须与一个特定的产品记录相关联,而每个产品可能与一个订单记录相关联,但并非必须。


例如,你的库存中可能收到一个新产品,但还没有客户订购它。如果这个产品没有被订购,那么它就还没有与任何订单关联。
那么,问题来了:谁是父表,谁是子表?是Customer、Order还是Product?答案是:现在有两个父表,即Customer表和Product表;有一个子表,即Order表。


总结 📝
本节课中我们一起学习了外键。你现在应该理解了外键的用途,并且能够演示如何使用它来连接关系型数据库中的表。外键通过建立表之间的引用关系(如一对多或一对一),确保了数据的完整性和关联性,其中子表引用父表的主键。掌握外键是设计高效、可靠数据库模式的关键一步。
入门 39:查找实体 🔍
在本节课中,我们将要学习关系型数据库设计中的一个核心概念:实体。我们将了解实体的定义,并学习如何区分不同类型的属性。掌握这些知识是构建有效、实用数据库的第一步。

什么是实体?
上一节我们介绍了数据库设计的基本目标,本节中我们来看看构成数据库的基本元素——实体。

实体可以被描述为一个具有属性来定义其特性的对象。在数据库中,实体可以是任何代表单个对象的事物,例如一个地点或一个人。
在关系型数据库系统中,项目中的每个重要对象都可以被视为一个实体,例如一位客户或一个个体。在诸如MySQL这样的数据库管理系统中,一个实体以表的形式存在,由行和列组成。
让我们通过一个电子商务商店的数据库例子来更深入地探讨这个概念。假设有一个存放配送记录的表。
- 表名代表实体名称,例如
deliveries(配送)。 - 每一列代表与该实体相关的属性。
该系统存储与客户(实体)相关的属性,例如 ID(标识符)、name(姓名)和 delivery_status(配送状态)。这些属性保存着关于表实体的相关数据。因此,在这个电商系统中,客户实体的每个实例都包含一条关于每位客户的数据记录。

代码示例:一个“客户”实体表
CREATE TABLE customers (
customer_id INT PRIMARY KEY, -- 关键属性
first_name VARCHAR(50), -- 简单属性
last_name VARCHAR(50), -- 简单属性
email VARCHAR(100) -- 单值属性
);

属性的类型
理解了实体的基本构成后,我们来看看定义实体的细节——属性。属性并非千篇一律,它们有不同的类型。
在关系型数据库系统中,存在多种类型的属性,包括:简单属性、复合属性、单值属性、多值属性、派生属性和关键属性。
以下是这些属性的详细说明,我们以一个学生表为例:
- 简单属性:指无法进一步分类的属性。在学生记录的例子中,
grade(成绩)的值就无法再细分。 - 复合属性:指可以拆分为不同组成部分的属性。例如,每位学生的
name(姓名)值可以拆分为first_name(名)和last_name(姓)这样的子属性。 - 单值属性:指一个字段只能存储一个值的属性。在学生表示例中,
date_of_birth(出生日期)列每位学生只能包含一个值,因此可定义为单值属性。 - 多值属性:指一个字段可以存储多个值的属性。例如,
student_email(学生邮箱)列可以为每位学生保存多个邮箱地址(如学校邮箱和个人邮箱)。但请注意,在关系型数据库中应避免这种设计实践,通常需要通过规范化拆分成新的表。 - 派生属性:指其值可以从另一个属性推导出来的属性。在学生表中,每位学生的
age(年龄)可以从他们各自的date_of_birth(出生日期)派生出来。 - 关键属性:这是一个包含唯一值的字段,用于标识唯一的实体记录。一个很好的例子是
student_id(学号)列中的值。每个ID都是一个唯一值,可用于获取特定学生的数据。
公式与代码示例:属性类型
- 派生属性公式:
年龄 = 当前年份 - 出生年份 - 关键属性代码:在SQL中通常使用
PRIMARY KEY约束来定义。ALTER TABLE students ADD PRIMARY KEY (student_id);
设计的实用性考量
认识了各种实体和属性后,我们需要思考一个关键问题:如何取舍?
请记住,考虑那些在你的项目中不会被使用的实体或属性是没有意义的。你只需要在数据库系统中捕获那些能帮助系统用户完成特定任务和活动的数据。设计应始终以实际需求为导向。

总结
本节课中我们一起学习了关系型数据库中的核心概念。我们首先定义了实体是拥有属性的独立对象,并以表的形式存在。接着,我们详细区分了六种属性类型:简单属性、复合属性、单值属性、多值属性、派生属性和关键属性,并通过学生表示例加深理解。最后,我们强调了数据库设计应注重实用性,只包含必要的数据以支持用户任务。掌握这些基础知识是进行有效数据库设计的关键一步。
入门 40:什么是数据库规范化 📊
在本节课中,我们将要学习数据库规范化的概念。规范化是数据库设计中的一个核心过程,它通过优化表的结构来解决数据冗余、更新复杂和查询困难等问题。我们将通过一个具体的例子来理解什么是插入异常、更新异常和删除异常,并了解规范化如何帮助我们解决这些问题。
规范化简介
上一节我们介绍了创建数据库表的基本过程。本节中我们来看看,当表设计不当时会遇到哪些问题,以及如何通过规范化来解决。

规范化是数据库系统中使用的一个重要过程。它通过减少数据重复、避免数据修改的连锁影响以及简化数据查询,来构建表结构,从而最小化各种挑战。
公式表示规范化的目标:
规范化 = 减少数据冗余 + 避免更新异常 + 简化查询操作

为了更好地理解规范化及其解决的问题,让我们先探索一个未规范化的表例子。
未规范化表示例
在这个例子中,我将使用一个大学选课表。😊 这个表有多个用途:它提供了大学生、课程和院系的列表,并概述了学生、课程和院系之间的关系或关联,还包含了每个院系负责人的姓名和联系方式。

创建这种服务于多个目的的表会给数据库系统带来严重的挑战和问题。最常见的挑战包括插入异常、更新异常和删除异常。

以下是这三种异常的简要介绍:

- 插入异常:当向表中插入新数据时,需要同时插入额外的、可能不相关的数据。
- 更新异常:更新表中的一条记录时,发现需要在表的多个地方进行相同的更新。
- 删除异常:删除一条数据记录时,会导致数据库中其他所需的数据集也被意外删除。
深入理解异常
现在,让我们逐一详细探讨这些异常。

插入异常
插入异常发生在向表中插入新数据时,需要同时插入额外的数据。

我将使用大学选课表来演示一个例子。在选课表中,学生ID列是主键。在可以向表中其他列添加新记录之前,主键列中的每个字段都必须包含数据。
例如,我可以在表中输入一个新的课程名称,但在没有招收新学生并为其分配ID之前,我无法添加任何新记录。而ID列不能包含空字段。因此,除非我插入新的学生数据,否则无法插入新课程。这就遇到了插入异常问题。
代码示例说明主键约束:
-- 假设 StudentID 是主键,不能为 NULL
INSERT INTO CollegeEnrollment (CourseName, Department) VALUES ('新课程', '新院系');
-- 上述操作会失败,因为未提供 StudentID
更新异常
更新异常发生在你尝试更新表列中的一条记录时,却发现这会导致表中多处需要进行更新。

让我们再次回到大学选课表,以理解更新异常是如何发生的。在选课表中,课程和院系信息为选修该课程的每个学生重复或复制。这种重复增加了数据库存储量,并使数据变更的维护变得更加困难。
我通过一个场景来演示:计算系的主任琼斯博士离职,由另一位主任接替。现在,我需要用新主任的名字更新表中所有出现琼斯博士的地方。我还需要更新该系所有注册学生的记录。这带来了重大挑战,因为如果我漏掉任何学生,那么表中就会包含不准确或不一致的信息。这就是更新异常问题的典型例子。
删除异常


删除异常是指删除一条数据记录时,会导致数据库中多组所需的数据被删除。

例如,ID为4的学生罗斯决定退课。所以我需要删除她的数据。但是,删除罗斯的数据会导致设计院的记录丢失,因为这些记录依赖于她的ID。这就是删除异常问题的一个例子。删除一个数据记录实例会导致其他记录被删除。
解决方案:数据库规范化
那么,如何解决这些问题呢?正如你之前学到的,答案在于数据库规范化。规范化通过为每个表创建单一用途来优化数据库设计。

为了规范化大学选课表,我需要重新设计它。正如你之前发现的,该表当前的设计服务于三个不同的目的。因此,解决方案是将该表一分为三,实质上为每个目的创建一个单独的表。
这意味着我现在有了:
- 一个包含每个学生信息的学生表。
- 一个包含每门课程记录的课程表。
- 一个包含每个院系信息的院系表。

😊


这种信息的分离有助于修复异常挑战,也使编写SQL查询以搜索、排序和分析数据变得更加容易。
总结
本节课中我们一起学习了数据库规范化的核心概念。我们了解到,不当的表设计会导致插入异常、更新异常和删除异常。规范化通过将具有多重功能的表拆分为多个单一用途的表,有效地解决了这些问题,从而确保了数据的一致性、完整性和查询效率。记住,规范化的目标是减少冗余、防止异常和简化操作。
入门 41:第一范式(1NF) 🗂️
在本节课中,我们将学习数据库设计中的一个核心概念——第一范式。你将了解如何通过遵循原子性规则和消除重复数据组,来设计符合第一范式的数据库表,从而解决数据冗余和不一致的问题。
第一范式简介
作为数据库工程师,你经常会遇到表中某些列充满了重复数据或多个值的情况。这会使数据的查看、搜索和排序变得相当困难。然而,通过正确地实施规范化,可以应对这一挑战。
在本视频结束时,你将能够:
- 演示如何设计符合第一范式的数据库。
- 识别原子性规则及其执行方法。
- 分析消除数据集中重复数据组问题的有效方法。
规范化与第一范式
正如你可能从本课程之前的视频中了解到的,规范化过程使工程师执行基本数据库任务变得更简单、更高效。它对于帮助修复众所周知的插入、删除和更新异常尤其有用。
然而,为了实现数据库规范化,你首先需要完成三个基本的规范化形式。数据库规范化形式包括:
- 第一范式
- 第二范式
- 第三范式

本节视频重点介绍如何设计符合第一范式规则的数据库。这些规则强制执行数据原子性,并消除数据库表中不必要的重复数据组。
第一范式的核心规则

第一范式主要包含两条核心规则:
1. 数据原子性
数据原子性意味着表的任何字段中,列属性必须只有一个单一的实例值。换句话说,你的表中每个字段应该只包含一个值。

2. 消除重复数据组
通过消除重复的数据组,可以避免在数据库中不必要地重复数据。重复数据的实例会导致数据冗余和不一致。

为了更好地理解这一点,让我们来探索一个例子。
案例分析:违反原子性的表

为了演示数据原子性,我在一个学院数据库中构建了一个名为 CourseTable 的非规范化表。它包含了学院计算课程的信息,以及课程导师的姓名和联系方式。CourseID 列是表的主键。
然而,在 ContactNumber 列的每一行中都有多个值。每一行包含每位导师的两个联系方式:一个手机号码和一个座机号码。

这个表不符合第一范式。它在一个字段中包含多个值,违反了原子性规则。
初步尝试与问题
我可以尝试为每个号码创建新行来修复这个问题,这解决了我的数据原子性问题。


表现在每个字段中只有一个值,但这个解决方案也带来了另一个问题。😊

主键不再唯一,因为现在多行具有相同的课程ID。


另一种尝试及其局限性
另一种在保留主键的同时解决原子性问题的方法,是为联系方式创建两个列。


一个列用于手机,第二个列用于座机号码。
但我仍然有不必要的重复数据组问题。Mary Evans 是两门课程的指定导师,因此她的姓名在表中出现了两次,她的联系方式也是如此。如果她被分配教授更多课程,这些数据实例将继续重复出现。并且我们的详细信息很可能出现在数据库系统中的其他表中。这意味着我可能会有更多的重复数据组。
这带来了另一个问题:如果这位导师更改了任何详细信息,那么我将不得不更新此表以及出现该信息的其他所有表中的详细信息。如果我遗漏了其中任何一个表,那么我的数据库系统中就会出现不一致和无效的数据。😊
符合第一范式的解决方案
为了解决这个问题,我可以重新设计我的表以符合第一范式。
以下是实现步骤:
第一步:识别重复数据组
在本例中,重复数据组是导师的姓名和联系方式。
第二步:识别涉及的实体
我处理的实体是课程和导师。

第三步:拆分表
然后我拆分课程表,现在每个实体都有一个表。
- 一个
Course表,包含课程信息。 - 一个
Tutor表,维护每位导师的姓名和联系方式。

第四步:分配主键和外键
现在我需要为 Tutor 表分配一个主键,所以我选择 TutorID 列。我已经解决了数据原子性问题。但我还需要在两个表之间建立联系。
我可以通过使用外键来连接两个表。我只需将 TutorID 列添加到 Course 表中,现在两个表就链接起来了。

最终成果
我现在已经实现了数据原子性,并消除了不必要的重复数据组。


总结
本节课中,我们一起学习了第一范式。你现在应该熟悉了第一范式以及为避免违反它而应应用的规则。通过确保每个字段的原子性和消除重复数据组,我们可以设计出更高效、更一致且易于维护的数据库结构。干得好!
入门 42:第二范式 (2NF) 🗂️
在本节课中,我们将学习数据库设计中的第二范式。我们将探讨如何通过规范化设计来减少数据冗余,并理解功能依赖和部分依赖这两个核心概念。
上一节我们介绍了第一范式,数据库规范化是一个渐进的过程。本节中,我们来看看如何将数据库设计提升到第二范式。
概述
作为数据库工程师,你经常会遇到表中某些列充满了重复数据或多个值的情况。这会使数据的查看、搜索和排序变得相当困难。然而,通过正确实施规范化,可以应对这一挑战。在本视频结束时,你将能够解释如何设计一个符合第二范式的数据库,概述功能依赖的概念,并定义部分依赖的概念。
在开始之前,请确保你已经观看了关于第一范式的视频。数据库规范化是一个渐进的过程,因此你必须熟悉第一范式,才能实施第二范式。

那么,为什么数据库开发者需要数据库规范化?如果你要存储内容,你的目标应该是拥有尽可能最佳的数据库。


“最佳”意味着它具有适当的结构,可以减少重复,并最终为准确的数据分析和数据检索提供支持。

为了获得最佳结果,工程师会以优化数据库结构的方式来构建表。本视频重点介绍如何在关系数据库中设计表以满足第二范式的标准。但在学习如何做到这一点之前,你需要理解功能依赖和部分依赖这两个术语的含义。

功能依赖
功能依赖指的是表中两个属性之间的关系。关系中某一列的唯一值决定了另一列的值。


为了演示这个概念,我们以名为 R 的表为例。该表包含两列,分别称为 X 和 Y。X 是一列具有一组唯一值的列,这些值在表中其他地方没有重复,例如主键。Y 是一列没有唯一值集合的列,例如非主键。R 是包含列 X 和 Y 的表或关系。Y 作为具有重复值的非主键,依赖于 X;这是因为 X 是表的主键,因为它只包含唯一值。

如果你还不完全理解这个概念,请不要担心。我将更详细地演示功能依赖。
我们以名为 Student 的表为例,该表保存了学院学生的关键信息。该表包含三列:学生ID列、姓名列和出生日期列。我需要使用此表来查找特定学生的出生日期。我不能使用姓名列,因为它有重复值。有两个名叫 Tony 的学生。如果我查询此列,只会收到两个 Tony 的实例。我也不能使用出生日期列,因为有两个学生共享相同的出生日期。但我可以通过使用学生ID列来完成此任务。此列中的所有值都是唯一的,因此它被指定为表的主键。并且这个主键列的值决定了其他列的信息。这意味着表中的每一列在功能上都依赖于学生ID列。

它是唯一可用于返回特定数据的列。
现在你已经探索了功能依赖的概念,让我们看看部分依赖。

部分依赖


部分依赖指的是具有复合主键的表。复合主键是由两列或更多列组合而成的键。



为了演示,我们以显示医院数据库中患者疫苗接种状态的表为例。

该表显示了两名患者 David 和 Kate 的疫苗接种状态。它还显示了患者ID、疫苗ID和疫苗名称。没有哪一列在每一行中都有唯一值,因此没有哪一列可以作为主键。因此,最好将患者ID和疫苗ID列组合为复合主键,以在每个记录中创建唯一值。
疫苗接种表必须满足第二范式。因此,所有非键属性(疫苗名称、患者姓名和状态)必须依赖于整个主键值(即患者ID和疫苗ID)。它不能只依赖于部分值,否则就会产生部分依赖。让我们应用此规则来检查它是否对每个非键列都成立。
那么,我如何检查ID为50的患者是否接种了疫苗1?我检查患者ID和疫苗ID键的值。组合值是返回特定患者疫苗接种状态值的唯一方式,这意味着状态值和主键值之间存在功能依赖关系。
但是,如果我只想找出疫苗名称,那么我不需要两个组合值,我返回疫苗名称所需的唯一信息是疫苗ID。正如你之前学到的,这称为部分依赖。在大多数情况下应避免这种情况,因为它违反了第二范式的规则。
同样,如果我想识别患者姓名,我不需要两个组合值,我只需使用患者ID即可返回患者姓名。
接下来,让我们看看如何将此表升级到第二范式。
升级到第二范式
首先,我需要使所有非键列都依赖于主键的所有组成部分。因此,我识别疫苗接种表中包含的实体。在本例中,有三个实体:疫苗接种状态(由状态列表示)、疫苗(由疫苗ID和疫苗名称列表示)以及患者(由患者姓名和患者ID列表示)。
然后,我将表分解为三个独立的表,如下所示:患者表、疫苗表和疫苗接种状态表。

现在,在这些新表中,所有非主键属性仅依赖于主键值。


我已经消除了疫苗接种表中疫苗和患者姓名所有不必要的重复。这三个表现在处于第二范式。


总结

本节课中,我们一起学习了第二范式的规则以及如何将表升级到第二范式。你现在应该熟悉了功能依赖和部分依赖的概念,并掌握了通过分解表来消除部分依赖、实现第二范式的数据库设计方法。
入门 43:第三范式(3NF) 🗂️
在本节课中,我们将要学习数据库设计的第三范式。我们将理解什么是传递依赖,并掌握如何通过消除传递依赖来使数据库符合第三范式的要求。
上一节我们介绍了第一范式和第二范式,本节中我们来看看数据库设计的更高标准——第三范式。
第三范式的前提条件

一个数据库必须首先满足第一范式和第二范式,才能进入第三范式。
除了满足前两个范式的规则外,第三范式还要求数据库不能包含任何传递依赖的实例。
理解传递依赖 🔗

在第三范式的语境下,传递依赖意味着一个非键属性不能函数依赖于另一个非键属性。换句话说,非键属性之间不能相互依赖。
在数据库中,键属性是帮助唯一标识表中一行数据的属性。
为了演示这个概念,我们来看一个包含三列(A、B、C)的基本表格示例。

传递依赖的概念意味着A的值决定了B的值。同样,B的值决定了C的值。这些表列之间的关系可以表示为:A -> B -> C。这意味着A通过B决定了C。
数据库工程师将这种关系称为传递依赖。
一个复杂的例子 📚
让我们通过一个更复杂的例子来看看这是如何运作的。
假设我有一个来自在线书店数据库的“欧洲畅销书”表格。该表根据五个属性组织书籍:ID、书名、作者姓名、作者语言和国家。
在这个表中,ID是表中唯一存在的键或主键。所有其他属性都是非键属性。但要确定这些非键属性的值,我必须使用畅销书的ID。这意味着,如果我想查找任何属性的具体信息,我需要使用ID属性值来找到目标属性值。
例如,如果我使用ID为3,那么我可以定位到作者Cormac McCarthy、语言英语、国家爱尔兰等等。
然而,也有可能根据语言来确定国家,或者根据国家来确定语言。而国家和语言都是非键属性。例如,在欧洲的语境下,如果语言是法语,总是可以确定国家是法国,反之亦然。

这意味着我在这组关系中存在一个传递依赖:一个非键属性依赖于另一个非键属性。

这种依赖关系可以表示如下:
- 语言决定国家。
- 国家决定语言。
其余属性是正常的,因为它们只依赖于ID主键。例如,你不能说作者姓名决定了书名,或者作者姓名决定了语言。作者Michelle Laurier就用两种不同的语言(法语和西班牙语)写了两本书。

解决传递依赖 🛠️
正如刚才指出的,这个例子中唯一存在的传递依赖是在语言和国家之间。那么,我该如何解决表中的这个传递依赖并消除数据的重复呢?

我可以将表格拆分成两个表,同时将它们连接起来,以符合第三范式的规则。
以下是具体步骤:
- 我保留“畅销书”表。
- 我将
国家和语言列拆分到一个名为国家的新表中。 - 我同时在“畅销书”表中保留
国家列,作为连接两个表的外键。
现在,国家表只包含四条记录,没有数据重复。在“畅销书”表中也不再需要语言列,陈述国家就足以确定语言。
最重要的是,每个表中的所有非键属性都仅由主键决定。这意味着我的表现在满足了第三范式的要求。

总结
本节课中我们一起学习了第三范式。你现在应该知道如何设计一个符合第三范式的数据库,并且能够解释传递依赖的概念。通过识别并消除非键属性之间的依赖关系,我们可以进一步优化数据库结构,减少数据冗余,确保数据的一致性。
入门 44:模块小结 🎯
在本节课中,我们将回顾数据库设计模块的核心知识点与技能,对所学内容进行系统性的总结。
你已经完成了本模块的学习,现在是时候回顾其中的关键要点和技能了。
数据库模式设计


本模块以数据库模式设计课程开始。你学习了正确设计的数据库是所有后续数据存储和分析的基础。掌握良好的数据库设计原则至关重要,因为设计不佳的数据库将难以甚至无法产生准确的信息。
完成本部分后,你现在应该能够:

- 定义术语“数据库模式”。
- 描述不同数据库系统的模式。
- 使用 SQL 创建基本的数据库模式。
- 列出两种主要的数据库模式类型。

关系型数据库设计

上一节我们介绍了数据库模式的基础,本节中我们来看看关系型数据库的具体设计。

在这部分课程中,你学习了如何设计关系型数据库。完成学习后,你现在应该能够:


- 描述关系模型。
- 列出不同类型的关系。
- 评估实体关系图(ERD)。
- 解释数据库表中主键的用途。
- 演示如何选择单一主键和复合主键。
- 描述外键的用途。
- 使用外键连接表。
- 总结关系数据库中实体的含义。
- 列出不同类型的属性。
- 识别实体及其属性。
- 在实体之间创建链接。
以下是关于键和实体的核心概念:
- 主键:唯一标识表中每条记录的字段或字段组合。例如,在
Students表中,student_id可以作为主键:PRIMARY KEY (student_id)。 - 外键:一个表中的字段,它是另一个表的主键,用于建立表间关系。例如,在
Orders表中,customer_id可以是引用Customers表主键的外键:FOREIGN KEY (customer_id) REFERENCES Customers(customer_id)。 - 实体:数据库中可以唯一识别的对象或概念,如“客户”、“产品”。


数据库规范化

最后一部分课程涵盖了数据库规范化。规范化是将一个大表拆分为多个小表以减少数据冗余的过程。
完成学习后,你现在应该能够:
- 解释数据库规范化。
- 识别插入、更新和删除异常。
- 解释原子性概念。
- 描述数据重复组问题。
- 设计符合第一、第二和第三范式的数据库。
- 解释函数依赖、部分依赖和传递依赖的概念。


以下是关于范式和依赖的核心概念:
- 第一范式(1NF):确保每列的原子性,即每列都是不可再分的基本数据项,且没有重复的列。
- 第二范式(2NF):在满足1NF的基础上,消除非主属性对主键的部分函数依赖。公式表示:若
A -> B且A是复合主键的一部分,则存在部分依赖。 - 第三范式(3NF):在满足2NF的基础上,消除非主属性对主键的传递函数依赖。公式表示:若
A -> B且B -> C,则存在传递依赖A -> C。


总结
本节课中我们一起学习了数据库设计的核心技能与概念。你现在应该熟悉了数据库设计的基本要素,并且能够创建一个规范化的关系型数据库结构。
这是你学习目标道路上取得的重要进展。
入门 45:课程回顾 📚
在本节课中,我们将对《数据库工程师》课程的核心内容进行回顾。我们将简要梳理从课程介绍到数据库设计等各个模块的关键知识点,帮助你巩固所学。
概述
课程开始时,我们首先对数据库工程领域进行了介绍,并探讨了作为一名数据库工程师可能从事的职业角色。同时,我们也回顾了如何成功学习本课程的一些建议,并讨论了期望学习到的内容。


模块一:SQL与数据库基础
在第一个模块中,我们学习了SQL(标准查询语言),这是用于与数据库交互的编程语法。最后,我们探讨了数据库的基本结构,并了解了它们所使用的不同类型的键。
以下是本模块的核心内容:
- SQL简介:学习了用于数据库交互的SQL语法。
- 数据库结构:了解了数据库的基本构成和不同类型的键。




模块二:SQL数据类型与CRUD操作

在模块二中,我们首先探索了SQL数据类型,学习了如何区分数值数据、字符串数据和默认值。


我们还完成了多项练习,学习了如何在数据库项目中使用这些不同的数据类型。


接着,我们继续探索了CRUD操作,即创建、读取、更新和删除。


我们学习了如何创建数据库和表,并向其中填充数据。我们探索了如何更新和删除数据,并通过完成创建和管理数据的练习,展示了我们在CRUD操作方面的能力。



模块三:SQL运算符与数据排序过滤
在第三个模块中,我们回顾了SQL运算符,学习了如何对数据进行排序和过滤。模块以关于SQL运算符的课程开始,在其中我们探讨了在数据库中部署SQL算术和比较运算符的语法和步骤。


接下来,我们学习了如何使用子句对数据进行排序和过滤。
以下是本模块涉及的关键子句:
- ORDER BY子句:用于对查询结果进行排序。
- WHERE子句:用于过滤记录,只返回满足指定条件的记录。
- SELECT DISTINCT子句:用于返回唯一不同的值。
我们还概述了每个子句如何用于对数据库中的数据进行排序和过滤,并进行了这些子句的演示,同时有机会亲自尝试它们。


模块四:数据库设计
在模块四中,我们学习了数据库设计。在第一课中,我们概述了如何设计数据库模式,探索了模式等基本数据库设计概念,并了解了不同类型的模式。


下一课的重点是关系型数据库设计。


在这节课中,我们研究了如何使用键在数据库的表之间建立关系。我们还学习了关系型数据库设计中使用的不同类型的键,例如主键、备用键、候选键和外键。
以下是关键键类型:
- 主键 (Primary Key):唯一标识表中每条记录。
- 外键 (Foreign Key):用于建立表与表之间的链接。
- 候选键 (Candidate Key):能唯一标识记录的最小属性集。
- 备用键 (Alternate Key):除主键外的候选键。


最后,我们学习了一节关于数据库规范化的课程。在这节课中,我们研究了数据库规范化的关键概念。接着,我们学习了范式的概念,以及第一范式、第二范式和第三范式。


总结
本节课中,我们一起回顾了《数据库工程师》课程的核心知识体系,从SQL基础语法、数据类型、CRUD操作,到数据查询的排序过滤,最后深入探讨了数据库模式设计与规范化理论。完成本次回顾后,是时候在分级评估中尝试运用你所学的知识了。祝你顺利!
入门 46:课程总结与后续步骤 🎉
在本节课中,我们将对《数据库介绍》课程进行总结,回顾已掌握的核心技能,并了解完成整个Meta数据库工程师专项认证的后续步骤与价值。
课程总结 🏁
恭喜您完成了Meta数据库工程师专项认证中的《数据库介绍》课程。您付出了辛勤努力,并在课程期间掌握了许多新技能。您的数据库学习之旅已经有了一个良好的开端,现在您应该对数据库和数据有了透彻的理解。

在项目实验环节,您通过创建和查询数据库,展示了部分学习成果以及实用的数据库技能集。

完成这门Meta数据库工程师的首门课程后,您现在应能:
- 展示对不同数据库模式的理解。
- 解释关系型数据库设计和表规范化。
- 执行数据库操作,例如创建、读取、更新和删除(即
CRUD操作)。 - 通过排序和筛选数据来演示SQL命令。

课程的核心技能评估衡量了您以下几方面的能力:
- 展示对不同数据库模式的理解。
- 解释关系型数据库设计和表规范化。
- 执行诸如创建、读取、更新、删除等数据库操作。
- 通过排序和筛选数据来演示SQL命令。
后续步骤与展望 🚀
那么,接下来该做什么呢?

这是Meta数据库工程师专项认证的第一门课程,它为您初步介绍了几个关键领域。您可能已经意识到,还有更多知识需要学习。如果您觉得本课程有帮助并希望了解更多,何不注册学习第二门课程呢?
在每一门Meta数据库工程师课程中,您都将持续发展您的技能集。在最终的实验项目中,您将运用所学的一切知识,创建属于自己的全功能数据库系统。
无论您是刚起步的技术专业人士、学生还是业务用户,课程结束时的项目都能证明您对数据库系统价值和能力的理解。该实验项目通过实际应用来巩固您的技能。
此外,实验项目还带来另一个重要益处:它意味着您拥有了一个可以放入作品集、完全可运行的数据库。这有助于向潜在雇主展示您的技能。它不仅向雇主表明您具备自我驱动力和创新能力,也充分展现了您作为个人以及您新获得的知识。
一旦您完成了此专项认证中的所有课程,您将获得Meta数据库工程师认证。该认证也可作为进阶获取其他Meta认证的途径。根据您的目标,在获得此认证后,您可以选择深入学习高级的、基于角色的认证,或学习其他基础课程。
Meta认证为您的技术技能提供了全球认可且受行业背书的证明。
感谢您。很高兴能与您一同踏上这段探索之旅。祝您未来一切顺利!

本节课中,我们一起学习了《数据库介绍》课程的总结,回顾了包括数据库模式、关系设计、CRUD操作和SQL命令在内的核心技能,并明确了获得Meta数据库工程师认证的路径及其职业价值。
入门 47:课程介绍 📚
在本节课中,我们将要学习版本控制的基础概念及其在软件开发中的重要性。课程将介绍版本控制系统如何工作,以及如何使用像 Git 和 GitHub 这样的工具来管理项目文件的变化。我们还会探讨命令行操作,特别是 Unix 命令,并了解如何通过课程资源有效地学习。
你是否曾经在设备上意外删除了某些内容,并希望能够撤销这个错误。




虽然人类尚无法进行时间旅行,但从事项目工作的程序员可以做到类似的事情。


他们使用一个称为版本控制的系统来实现这一点。作为一名程序员,你将在项目中处理许多文件,跟踪所做的更改非常重要。版本控制系统会记录所有文件的更改和修改,以便进行追踪,这对你的日常开发活动至关重要。

在本课程中,你将熟悉版本控制及其与开发的关系。学习结束时,你将理解什么是版本控制、它如何工作以及如何使用它。既有集中式也有分布式的控制系统,你将审视不同类型的工作流程。冲突解决是版本控制的一个重要方面,因为它帮助用户管理文件和版本冲突问题。
你将探索使用 Git 和 GitHub 等版本控制技术进行版本跟踪的流行方法,并学习如何在 GitHub 中创建和克隆仓库。此外,你将熟悉 Git 的概念,例如 add、commit、push 和 pull、分支与分叉、diff 和 blame。



除了专注于版本控制,本课程还探讨了命令行的使用,重点在于 Unix 命令。课程中有许多视频将逐步引导你实现目标。观看、暂停、回放和重看视频,直到你对自己的技能充满信心。然后,你可以通过查阅课程读物来巩固知识,并在课程练习中将技能付诸实践。在学习过程中,你会遇到几个知识测验,可以自我检查进度。

考虑从事网络开发职业的人不止你一个,课程讨论提示使你能够与同学联系。这是一个分享知识、讨论困难和结交新朋友的好方法。为了帮助你在课程中取得成功,承诺采用规律且自律的学习方法是一个好主意。
你需要尽可能认真地对待学习,如果可能的话,制定一个学习计划,标明你可以投入课程的日期和时间。当然,这是一个在线自定进度的课程,你可以在适合你生活方式的时间、地点进行学习。然而,将你的学习视为定期出勤,就像在实体教育机构可能必须做的那样,可能会有所帮助。


你可能在本视频中遇到了新的技术词汇和术语。如果你现在不完全理解所有这些术语,请不要担心,学习过程中将涵盖所有你需要的内容。总之,本课程为你提供了版本控制的完整介绍,并且是引导你走向软件开发职业生涯的一系列课程的一部分。

本节课中我们一起学习了版本控制的基本概念、其重要性以及 Git 和 GitHub 等工具的基础操作。我们还了解了如何通过课程视频、练习和社区互动来有效地学习。掌握这些知识是成为一名高效开发者的重要第一步。
入门 48:开发人员如何在现实中进行协作 💬
在本节课中,我们将学习软件开发中至关重要的协作技能。我们将探讨有效沟通、优先级管理、时间估算以及如何适应不同团队环境,这些是确保项目成功和团队高效运作的核心。
概述
沟通是与他人协作时最重要的技能。它能确保在构建产品时大家目标一致,并让团队成员能相互跟进时间线,对产品需求的理解保持一致。
协作的重要性与对象
上一节我们了解了沟通的核心地位,本节中我们来看看协作的具体场景。有效的协作对于在大型项目中与拥有不同技能的人协同工作至关重要。

以下是工程师需要协作的主要对象:
- 与其他工程师协作:在共同构建功能时,我们必须并行工作,为用户设计最佳功能。
- 与非工程师角色协作:例如,在构建 Instagram Live 功能时,我们需要:
- 与产品经理合作,确定应该构建什么。
- 与用户研究员合作,确定应关注哪些领域以打造最佳产品。
- 与设计师合作,确定产品的外观和感觉。
- 作为工程师,共同确定在既定时间线内实际可以构建的内容。

关键协作技能
了解了协作对象后,我们来看看作为开发者需要掌握哪些具体技能。沟通是与其他开发者合作最重要的技能之一,此外还有几项关键能力。
- 提供恰当背景信息:学习如何为其他开发者提供他们工作所需的适量背景信息。
- 无情地确定工作优先级:作为软件工程师,总有无数可以改进产品的事情。学会区分哪些事情对解除他人或自己的阻碍最为重要,这是一项关键技能。这可以用一个简单的公式表示:
优先级 = 影响力 / 所需努力。 - 准确估算时间:对于软件开发者来说,准确估算产品开发时间非常重要。刚开始时可能有些棘手,但学会预估项目时长并能解释其中的权衡取舍至关重要。
不同公司环境的协作差异
掌握了核心技能后,需要注意的是,这些技能的应用会因公司环境而异。软件开发者所需的技能因公司不同而略有差异。

- 大公司(如 Meta):工程师更加专业化。需要学会为他人提供恰好适量的背景信息,因为与你合作的人可能对你所做的工作了解有限。
- 初创公司:人们通常对你正在做的工作有更多了解,但他们可能不是该领域的专家。因此,你可能需要做更多解释,但提供的背景信息可以相对少一些。
协作中的挑战与个人发展
适应不同环境会带来挑战,同时也推动个人成长。我在学习协作时遇到的一些挑战是,必须学会根据不同人的工作偏好来调整我的工作方式。
- 有些同事是视觉型学习者,因此我学会了在交谈时使用白板。
- 有些同事喜欢先思考再发言,因此我学会了在交谈时更有耐心地倾听他们。


一项我正在学习、以推动自身职业发展的技能是移动开发。我是一名后端工程师,每天与移动工程师合作。为了更好地为他们构建产品,了解他们的工作方式和代码库结构对我们共同构建更好的产品很有帮助。
为了学习移动开发,我参加了 Meta 为有兴趣学习移动开发的后端工程师提供的 Android 训练营课程。完成课程后,我团队中的 Android 工程师给了我一些小任务和项目来主导,以便我能更多地了解他们的工作方式。
有效协作的工具与益处
个人技能的提升需要好的工具来支撑。实践有效的版本控制能带来更好的协作,因为它能帮助你理解某些更改的原因(例如查看提交记录 git commit -m "描述"),也有助于你在处理不同功能或项目时理清上下文关联。
有效的协作在我最近的一个项目中带来了更好的结果。我是一名后端工程师,负责主导团队一个关键项目的后端部分。我不得不意外休假,但由于我在 Git 中为代码更改保留了清晰的提交记录,并为团队准备了大量文档,他们能够轻松接手我的工作,最终项目得以按计划推进。

总结与鼓励
回顾本节课,我们一起学习了软件开发中现实协作的多个方面。你应该继续学习如何与他人协作,因为与越多的人合作,你就能获得关于所构建产品的不同视角,从而打造出更好的产品。
这是有回报的,因为与你合作的人越多,你能学习的人就越多。最终,你构建的产品会更好,因为它将融入更多不同的意见和视角。
入门 49:什么是版本控制 📚
在本节课中,我们将要学习版本控制的核心概念、主要功能及其带来的诸多好处。版本控制是软件开发中不可或缺的工具,它帮助开发者高效地管理代码变更,并促进团队协作。
你是否曾经在编辑文档时,修改了内容,几天后又希望能回到最初的版本?你是否还记得那种希望时光倒流的感觉?对于开发者而言,这种“时光机”是存在的,它被称为版本控制。



版本控制的核心概念 🔍
上一节我们引出了版本控制的概念,本节中我们来看看它的具体定义和核心目标。
版本控制系统是一种为了追踪目的而记录文件所有变更和修改的系统。开发者有时也使用“源代码控制”或“源代码管理”这些术语。任何版本控制系统的主要目标都是追踪变更。

它通过允许开发者访问完整的变更历史来实现这一目标,开发者可以回退或回滚到之前的状态或时间点。变更的类型多种多样,例如添加新文件、修改或更新文件,以及删除文件。
版本控制系统是所有代码、资产乃至团队本身的单一事实来源。
版本控制的类比与重要性 💡
理解了基本概念后,我们通过一个熟悉的例子来加深理解,并探讨其对开发者的重要性。
让我举一个我们都熟悉的例子。在文字处理应用程序中,版本控制功能以“自动保存文档”的安全网形式提供给用户。应用程序在每次自动保存时创建一个还原点,用户可以在需要时回退到该点。
编码项目的版本控制系统往往更复杂一些,但其底层功能遵循相同的过程。作为一名开发者,你需要熟悉许多不同的工具,而版本控制就是其中之一。
对于开发者,尤其是在团队中工作的开发者,版本控制带来了许多好处。
以下是版本控制的主要优势:
- 修订历史:提供项目中所有变更的记录。它使开发者能够在代码编辑引发问题或错误时,有能力回退到一个稳定的时间点。回滚到特定版本或时间的能力让团队工作更快,交付代码更有信心。
- 身份标识:记录变更固然很好,但如果你不知道谁负责添加或更改了记录,其价值就大打折扣。所有做出的变更都会与做出更改的用户身份一同被记录。将此功能与修订历史结合,团队不仅能查看变更发生的时间,还能知道是谁做出了更改。团队还可以分析控制系统上文件的编辑、创建和删除情况。
- 协作:作为软件开发人员,你经常需要与团队合作以实现共同目标。这可能是在现有项目中添加新功能,或是创建全新的服务。在所有情况下,版本控制系统都允许团队提交代码,并跟踪需要进行的任何更改。版本控制系统的另一个重要方面是同行评审。处理任务的开发者在代码准备好接受检查时会创建一个同行评审。同行评审旨在让团队中的其他开发人员审查代码并在必要时提供反馈。
- 自动化与效率:大规模创建和交付代码的能力是复杂且耗时的。版本控制有助于跟踪所有变更。它在开发运维(DevOps)的普及中扮演着不可或缺的角色。DevOps 是一套实践、理念和工具,旨在提高组织高质量、高速度交付应用程序或服务的能力。版本控制是此过程中的关键工具,它不仅用于跟踪所有变更,还有助于软件质量、发布和部署。你和你的团队需要高效才能使项目成功。你和你的团队可能会使用敏捷方法论中的流程。在敏捷流程中,团队通常会计划并执行两周的工作来完成,这被称为一个迭代。每个迭代都有一份要在两周结束前完成的任务列表。这些任务在某些情况下可能很复杂,但通过使用版本控制可以得到帮助。在每个引入的任务上进行测试并建立一定程度的自动化,可以使团队更高效。这也确保了团队更有信心,任何新引入的功能都不会破坏现有的流程。
总结与展望 🎯
本节课中,我们一起学习了版本控制是什么。现在你已经更好地理解了版本控制的目标和好处,为开始学习如何使用它做好了准备。

版本控制是开发者工具箱中的基石,它不仅是管理代码历史的工具,更是现代团队协作和高效交付的保障。掌握它将为你的开发之旅奠定坚实的基础。
入门 50:案例研究 - Meta工程师如何协作 👥
在本节课中,我们将通过Meta工程师Leila Rizby的分享,了解在Meta公司内部工程师如何进行高效协作,以及版本控制(如Git)在大型项目中的独特应用和实践。这对于理解现代软件工程团队的工作方式至关重要。
概述
Meta公司的一个显著特点是,工程师在项目中扮演着核心驱动角色。他们负责与产品经理、数据科学家和研究人员协调,共同决定构建什么以及项目的时间线。这与许多其他公司由产品经理或领导层主导项目的方式有所不同。
工程师的日常协作
上一节我们介绍了工程师在Meta的核心地位,本节中我们来看看他们日常是如何进行协作的。
Leila Rizby是Instagram通话功能的后端软件工程师。在她的角色中,协作是日常工作的重要组成部分。
以下是Leila日常协作的主要对象和方式:
- 与部门内移动工程师协作:为了共同构建最佳产品,她需要与同部门的其他移动工程师进行日常协作。
- 与Instagram消息团队协作:因为通话功能与消息功能紧密相连,所以需要频繁与消息团队合作。
- 与非工程师角色协作:她还需要定期与产品经理、数据科学家等非工程师角色合作。
为了进行有效协作,团队会根据具体情况选择合适的沟通工具:


- 即时消息:当需要快速解决问题或解除阻碍时,他们会通过聊天工具互相发送消息。
- 会议:当某些事项需要深入讨论时,他们会安排会议。
- 文档协作:当需要详细规划或记录时,他们会共同在文档上协作,通过添加评论和留言进行交流。

Meta的版本控制实践
了解了日常协作模式后,我们来看看支撑这种协作的技术基础——版本控制系统。在Meta,版本控制的使用有其独特之处。
Instagram的版本控制很有趣,因为所有后端代码都存放在一个巨大的单体代码仓库中。这意味着,每当Leila进行代码修改时,她所写的代码会与所有其他Instagram团队共享。
这种模式有其利弊:
- 风险:在某种程度上存在风险,因为改动会影响所有团队。
- 优势:好处是工程师可以方便地复用其他团队的代码。
Meta版本控制的另一个特点是,任何工程师都可以审核(approve)任何代码变更。Meta非常推崇“在Meta,没有问题是别人的问题”这一理念,这意味着工程师可以自由地参与他们想要进行的任何变更工作。
与其他公司版本控制策略的对比
上一节我们介绍了Meta独特的版本控制模式,本节中我们将其与其他常见模式进行对比,以加深理解。
Meta的版本控制与许多其他公司有所不同。

- Meta模式:使用一个巨大的单体代码仓库,并持续发布代码。
- 其他常见模式:许多公司采用微服务架构,每个团队拥有自己独立的、更小的代码仓库。团队在自己的代码库中工作,使用分支(branch)来开发功能,最后再合并(merge)回主分支。
代码示例:常见的分支操作
# 创建并切换到一个新分支进行功能开发
git checkout -b feature-new-login
# 开发完成后,将分支合并回主分支(如main)
git checkout main
git merge feature-new-login
微服务模式对于小团队有其优点,但也存在缺点,例如可能会遇到大量的合并冲突。
在Meta,由于工程师数量庞大,如果每个团队都使用独立分支,将会产生难以管理的合并冲突。因此,他们采用了不同的策略来应对协作挑战。
应对协作与版本控制的挑战
既然Meta采用了独特的代码管理方式,那么他们如何应对由此带来的挑战呢?本节将探讨他们的解决方案。
对于Leila的团队来说,使用单体仓库的一个主要挑战是合并冲突经常发生。团队采取了一些策略来应对:

- 编写小型变更:尽量使每次代码提交的改动范围较小,这样在需要时可以轻松回退。
- 设置守门员(Gatekeepers):部署到Instagram生产环境时,会添加许多“开关”,以便在出现问题时能立即关闭新功能,而无需等待漫长的回滚流程。
- 编写大量测试:因为代码与Messenger通话功能共享,所以必须添加大量测试,以确保更改不会破坏Messenger的服务。

核心工具:Git Blame
在应对挑战的过程中,一个名为 git blame 的工具显得尤为重要。它帮助工程师理解代码历史和进行有效协作。
git blame 是一个用于查看文件修订历史的工具。它非常有用,例如:
- 当Leila看到一行不理解的代码时,她可以使用
git blame找出是谁编写了这行代码,然后联系对方。 - 她还可以通过查看提交信息,了解作者当时试图实现什么功能。
- 当需要回退某个变更时,这个工具也能帮助她确定需要回退哪些修改。
公式/命令表示核心功能:
git blame <file_name> - 显示指定文件的每一行最后一次修改的提交信息和作者。
Leila每天都会使用这个工具。在Meta这样拥有大量工程师的公司,她经常需要联系不认识的代码作者,而 git blame 为她提供了直接的联系人(Point of Contact),极大地提升了协作效率。
总结
本节课中,我们一起学习了Meta工程师高效协作的实践。我们了解到,在Meta,工程师驱动项目,并与多方角色紧密协作。技术层面,他们采用独特的单体代码仓库模式进行版本控制,并通过编写小变更、添加“开关”和大量测试来应对挑战。工具方面,git blame 是理解代码历史和联系作者的关键。

掌握如何有效协作以及高效使用版本控制,对于在Meta取得成功至关重要。汇集关于功能构建、目标用户、需求定义或改进方向的多元化视角,非常有帮助。最终,这些努力会使你的项目和成果变得更好。
入门 51:版本控制系统和工具 🛠️
在本节课中,我们将要学习版本控制系统的基本概念、类型及其工作原理。这对于团队协作开发至关重要。
概述
作为在团队中工作的开发者,你会持续地编写、修改或更新现有的源代码。当你正在开发一个新功能时,团队中的另一位开发者可能正在修复一个无关的错误。当多位开发者都在同一个代码库上工作时,跟踪所有这些更新可能会变得很困难。幸运的是,版本控制系统能够解决这类问题。在本视频中,你将发现不同类型的版本控制系统,学习它们如何运作,并了解它们的相似之处与差异。
版本控制系统的类型
有许多不同的版本控制系统可用,例如 Subversion、Perforce、AWS Code Commit、Mercurial 和 Git 等。
版本控制系统可以分为两种类型或类别:集中式版本控制系统 和 分布式版本控制系统。这两种类型非常相似,但也存在一些关键差异,使它们彼此区分开来。让我们从集中式版本控制系统开始。
集中式版本控制系统 (CVCS) 🖥️
集中式版本控制系统(简称 CVCS)包含一个服务器和一个客户端。服务器包含主仓库,其中存放着代码的完整版本历史。使用集中式系统进行项目开发的开发者需要从服务器将代码拉取到他们的本地机器上。这为用户提供了他们自己的代码库工作副本。
- 服务器:保存所有变更的完整历史。
- 客户端:拥有最新的代码,但每个操作都需要与服务器本身建立连接。
在集中式版本控制系统中,服务器是项目的中心副本。在对代码进行更改后,开发者需要将更改推送到中央服务器,以便其他开发者可以看到它们。这本质上意味着,查看变更历史需要你连接到服务器才能检索和查看它们。
分布式版本控制系统 (DVCS) 💻
上一节我们介绍了集中式版本控制系统,本节中我们来看看分布式版本控制系统是如何工作的。分布式版本控制系统(简称 DVCS)与集中式模型相似,你仍然需要从服务器拉取代码以查看最新更改。
关键区别在于,每个用户本质上都是一个服务器,而不是客户端。这意味着每次你从分布式模型中拉取代码时,你的本地系统上就拥有了完整的变更历史。
优缺点比较
现在你对 CVCS 和 DVCS 有了一些了解,让我们探讨一下它们各自的优缺点。
以下是集中式版本控制系统 (CVCS) 的优缺点:
- 优点:被认为比分布式版本控制系统更容易学习。它们也为用户提供了更多的访问控制。
- 缺点:由于需要建立与服务器的连接才能执行任何操作,因此速度可能较慢。
以下是分布式版本控制系统 (DVCS) 的优缺点:

- 优点:你不需要连接到服务器来添加你的更改或查看文件历史。它就像你直接连接到服务器一样工作,但在你自己的本地机器上。你只需要在拉取最新更改或推送自己的更改时才需要连接到服务器,这本质上允许用户在离线状态下工作。速度和性能也优于其 CVCS 对应物。
- 缺点:学习曲线可能比 CVCS 稍陡峭。
DVCS 是改进开发者操作和软件开发生命周期的关键因素。你将在本课程后面学到更多关于 DVCS 的知识。
总结

本节课中我们一起学习了集中式和分布式版本控制系统之间的区别。你也学习了它们如何运作以及它们各自的优势。作为一名有抱负的开发者,我相信你现在能够理解版本控制系统的重要性。做得好!
入门 52:修订历史记录 📜
在本节课中,我们将要学习版本控制系统中的修订历史记录功能。你将了解开发者如何利用修订历史来追踪代码变更、解决团队协作中的冲突,并确保代码库有一个清晰、可追溯的“单一事实来源”。
回想一下,你是否曾因为工作被覆盖或删除而感到丢失了劳动成果。正如之前所学,版本控制和版本控制系统能帮助开发者追踪代码并与所有变更保持同步。
在本视频中,你将体会开发者如何使用版本控制来追踪变更,并在与开发团队协作时解决代码冲突。
修订历史的重要性 🔍

对于代码库而言,拥有一个记录所有历史变更的“单一事实来源”至关重要。版本控制系统通过提供添加到其仓库中的每个文件的完整变更历史,在这一过程中扮演着不可或缺的角色。



它使团队协作变得更加容易,并有助于朝着共同目标努力。无论是添加新功能并追踪其实现流程,还是发现潜在问题可能被引入的位置,能够准确 pinpoint 谁、何时、做了什么变更都至关重要。


修订历史将记录这些关键数据点,因此任何开发者或团队成员都可以从头到尾浏览整个项目。项目中发生的每一次变更,都应该能通过简单命令或集成到开发者的 IDE 中轻松访问。

团队协作与沟通标准 🤝

对于组织而言,定义开发者如何沟通其所作变更的标准非常重要。开发者在查看代码之前,需要了解主导开发者的目标是什么。信息越详细越好,这能创造一个更透明、更开放的强大团队环境。

实战示例:电商应用开发 🛒
现在,我将通过一个典型开发团队在电商应用上工作的例子来引导你。
假设你与另外三名开发者在一个团队中工作,目标是发布一个新功能。你的任务是创建一个新功能,以支持在网站上进行实验。这将允许市场部门测试用户行为。


每日会生成一份报告,对每个实验的有效性进行排名。这些报告将提供每个实验进展情况的洞察,然后给出哪个实验最成功以及总体优胜者的结果。

代码提交与同行评审 🔄
完成所有代码变更后,开发者会将其更改推送到仓库,并创建一个称为 拉取请求(Pull Request) 的东西。

随后,其他开发者将对拉取请求进行同行评审,以批准、请求更改或拒绝。
处理变更交叉与合并冲突 ⚙️


在单个项目上工作时,开发者之间通常存在某种程度的变更交叉。当这种情况发生时,修订历史可以帮助开发者查看已发生变更的完整生命周期。
这对于合并冲突也至关重要,即多名开发者所做的更改可能需要在代码获得批准之前进行解决。

历史记录将显示:谁出于什么原因做出了更改、代码本身及其变更,以及变更发生的日期和时间。
通常,在新项目中,你会遇到一项任务中的变更可能导致与另一项任务产生潜在问题或冲突的情况。修订历史将使团队能够管理和合并这些变更,并及时实现业务目标。

总结 📝
本节课中,我们一起学习了修订历史记录。记住,建立一个系统来记录代码库的所有变更至关重要,这在与其他开发者团队协作时尤为关键。现在,你应该能够描述开发者如何使用版本控制来解决生产过程中可能出现的任何冲突。
入门 53:模块小结 软件协作 🎯
在本节课中,我们将回顾并总结软件协作入门模块所涵盖的核心知识。

模块概述
本模块从一个关于全球软件工程师如何协作而不破坏彼此代码的案例研究开始。我们随后深入探讨了“什么是版本控制”这一问题。
核心概念回顾
上一节我们介绍了模块的起点,本节中我们来系统回顾学到的关键内容。
以下是本模块涵盖的主要知识点列表:
- 版本控制的定义与历史:你学会了描述现代软件团队如何协作并处理同一代码库。版本控制早在互联网普及之前就已投入使用。
- 版本控制系统与方法论:你了解了不同的版本控制系统(VCS)和不同的版本控制方法论,并探索了软件开发工作流。
- 冲突解决与重要性:你探索了冲突解决,并认识到版本控制在软件开发过程中的关键作用。
- 常用工具与策略:你学习了开发者用于实施版本控制的一些常用工具和策略,例如工作流、持续集成(CI)、持续交付(CD) 和持续部署。


预发布与生产环境



接下来,我们来看看软件开发中两个至关重要的环境:预发布环境和生产环境。
我们探讨了预发布(Staging)与生产(Production)环境之间的区别。你了解到,预发布环境应尽可能模拟生产环境。
以下是创建预发布环境带来的诸多益处:
- 新功能测试
- 全面测试
- 数据迁移验证
- 配置变更检查
核心原则是:任何问题都应在预发布环境中被发现和修复,然后才能上线到生产环境。此外,你还探讨了与生产环境相关的停机时间、安全漏洞和声誉风险。

总结


本节课中,我们一起学习了软件协作的基础——版本控制。你现在应该对版本控制的概念、工具、实践以及预发布/生产环境的管理有了基本的熟悉。


做得好!你的学习之旅正在稳步前进。🚀
入门 54:命令行入门 🖥️
在本节课中,我们将要学习如何通过命令行与计算机进行交互。你将了解到什么是命令行,它为何强大,并掌握一些基础命令来开始你的实践。
什么是人机交互?
当你第一次使用计算机时,最先学会的操作之一就是使用鼠标和键盘。起初可能很慢,但随着你越来越熟练,你就能与计算机顺畅交互,并让它按你的意愿响应。
在计算机使用语境中,“交互”一词简单来说就是交换信息,或者说,发送和接收信息。本质上,计算机向你发送数据,你接收它;反过来,你也向计算机发送数据,计算机接收它。
交互的方式:输入与输出设备
我们提到了鼠标和键盘,但你能想到其他与计算机交互的方式吗?计算机有多种输入和输出设备。输入设备包括键盘、鼠标、麦克风、摄像头、触摸感应设备等。输出设备则包括扬声器、显示器、耳机和触觉设备等。
你使用所有这些设备向计算机发送数据,并从它那里接收数据。但还有另一种东西支持着与设备的通信,那就是图形用户界面(GUI),它促进了你的交互。GUI之所以流行,是因为它几乎不需要培训就能使用。
超越GUI:命令行的力量

GUI提供了一种与设备交互的简单方式,但它也在一定程度上限制了人机交互的范围。作为GUI和麦克风等输入设备的替代方案,你将学习通过命令行与计算机交互。

命令行是一个非常强大的替代方案,因为它允许开发者更快地执行任务,并且随着经验积累,出错的潜在可能性更低。要有效使用这个强大工具,你需要具备一定水平的知识。你可能会觉得命令行的学习曲线有点陡峭,但请相信我,回报绝对是值得的。只需学习几个命令,你就能执行各种任务。
以下是使用命令行可以完成的一些基础任务:
- 创建新目录。
- 创建新文件。
- 合并目录。
- 在不同目录间复制和移动文件。
- 使用各种条件和关键字搜索文件。
命令行的进阶应用
随着你更熟练地使用命令行,你将能够执行更高级的任务,例如:
- 跟踪软件。
- 访问和控制远程服务器。
- 使用特定条件搜索文件。
- 解压归档文件。
- 访问软件手册并在命令行中显示。
- 安装、升级和卸载软件。
- 挂载和卸载计算机驱动器,或检查磁盘空间等。
这听起来很高级,不是吗?但列表还不止于此,你还可以:
- 编写脚本来自动化各种任务。
- 控制用户对文件和程序的访问。
- 停止、启动和重启程序。
- 创建仅几个字符长的别名来启动非常长的命令。
- 从互联网下载文件。
- 运行各种软件。
- 最后,运行和控制自包含的虚拟软件,这也被称为容器化。

基础命令入门
使用命令行的方式有很多,但现在我将指导你学习一些基本命令来入门。
首先,是 cd 命令,它代表“更改目录”。这用于将我们的命令行指向特定的目录,例如某个文件夹。例如,在Linux上,如果我输入 cd ~/Desktop,我将把命令行指向我计算机的桌面。当你输入 cd .. 时,你将移出当前目录并返回其父目录。
接下来是 touch 命令,它可以创建你指定的任何类型的新文件。例如,要创建一个全新的文件,你可以运行 touch 后跟新文件的名称,例如 example.txt。请注意,新创建的文件将是空的。
你还可以使用 mkdir 命令创建新文件夹。例如,mkdir 后跟你想给新文件夹起的标题。

要查看最近输入命令的历史记录,你可以使用 history 命令。
实践场景示例
还有很多其他命令可以使用,但仅凭我刚才介绍的这些,你已经可以做很多事情了。我将带你快速浏览一个示例场景。


假设你想将命令行指向桌面目录,然后在那里创建一个名为 MyJSProject 的新文件夹。接着,你想将命令行指向 MyJSProject 目录,并创建一个名为 example.js 的新文件。最后,你想在 VS Code 中打开这个 example.js 文件。
要完成所有这些操作,你需要运行以下命令:
cd ~/Desktopmkdir MyJSProjectcd MyJSProjecttouch example.jscode example.js

第一个操作是使用更改目录或 cd 命令。然后,你想使用 mkdir 命令来创建新文件夹。要进入新文件夹目录,你再次使用 cd 命令,然后使用 touch 命令创建文件。最后的命令是 code 命令,它将在 VS Code 中打开文件。

如果你正确运行了所有这些命令,你最终会在桌面上得到一个 MyJSProject 目录,里面包含 example.js 文件,并且该 example.js 文件会在 VS Code 中打开,随时可以编辑。
总结
本节课中,我们一起学习了如何通过命令行与计算机进行更高级的交互。你现在对命令行允许你执行哪些高级任务有了更好的了解,并且也准备好尝试一些基本命令了。我鼓励你开始练习其中一些命令,就像你曾经在打字和用鼠标移动光标方面越来越熟练一样。我向你保证,通过练习,你很快就能像专业人士一样使用命令行。
入门 55:什么是Unix命令 🖥️
在本节课中,我们将要学习Unix命令的基础知识。你将了解什么是Unix命令,它们与图形用户界面的关系,以及为什么掌握这些命令对软件开发人员至关重要。

概述
我们每天使用手机和电脑进行各种活动,例如发送消息、在线购物和观看视频。我们通过点击屏幕、滚动和滑动来与设备交互。这种交互是通过图形用户界面实现的,它位于底层命令之上,负责告诉设备该做什么。
然而,开发者需要知道如何使用特定的命令来执行各种任务。例如,在桌面上创建一个新文件夹,你可以右键单击并选择“新建文件夹”。而在命令行中,你需要使用特定的命令 mkdir 来达到相同的结果。掌握Unix命令是当今软件开发世界中的一项重要技能。
Unix与Linux的历史渊源


你可能会想,既然本视频的主题是Unix命令,为什么我要讨论Linux?要回答这个问题,让我们先探索一些历史。
Unix 先于Linux出现,由Ken Thompson、Dennis Ritchie和AT&T实验室的团队于1969年开发。Linux 出现得晚得多,最初是Linus Torvalds作为业余爱好开发的,因此得名Linux。

你在本视频中将要探索的命令起源于Unix平台。如今,你可以在大多数运行某种Linux变体的现代环境中使用它们。

命令行与图形界面
起初,使用命令行可能看起来有点令人生畏,但你很快就会了解到,Unix命令只不过是诸如打开文件目录或重命名文件等常规操作之下的一层。
例如,Windows 之所以成为主导的桌面操作系统,主要归功于其易于使用的图形用户界面。它允许非技术用户无需学习一系列命令即可执行任务。但作为一名有抱负的开发者,你将学习使用Unix命令来执行任务。

命令帮助与标志
在深入探讨一些最常见的命令之前,重要的是要注意每个命令都有一组帮助指令。这些帮助程序提供了关于如何运行命令以及如何传递我们称之为“标志”的详细说明。
其中一个帮助程序是 man 命令。man 是“manual”的缩写,当针对某个命令调用时,它会显示该命令的详细使用手册。

例如,命令 man ls 将显示ls列表命令的详细使用手册。
你还可以将所谓的标志与Unix命令结合使用。标志用于修改命令的行为,可以将它们视为可以改变或扩展给定命令功能的选项。
接下来,你将了解一些最常用的Unix命令,在下一个视频中,你将看到其中一些命令的实际应用。
常用Unix命令简介
以下是几个最基础且常用的Unix命令及其简要说明。
cd:cd或“更改目录”命令用于在文件系统的不同目录之间移动。你可以在本课末尾的补充阅读中了解更多关于使用相对路径和绝对路径的信息。ls:ls用于显示当前工作目录的内容。ls命令可以接受许多不同类型的标志,这些标志会改变返回的响应内容。例如,ls -l以列表顺序列出文件,并显示读写权限、所有者和所属组。而ls -a则会列出所有文件和目录,包括隐藏文件。pwd:pwd或“打印工作目录”命令显示当前工作目录的完整路径。cp:cp或“复制”命令,将文件或文件夹从一个位置复制到另一个位置。mv:mv或“移动”命令,将文件从一个目录移动到另一个目录。
总结

本节课中,我们一起学习了Unix命令的基础概念。我们了解了Unix命令是位于图形用户界面之下的底层指令,是开发者与计算机系统高效交互的重要工具。我们还回顾了Unix与Linux的历史联系,并介绍了一些最常用的命令,如 cd、ls、pwd、cp 和 mv。
下次你使用设备时,不妨思考一下,在图形用户界面之下,是哪些命令在运行以完成你正在执行的任务。掌握这些命令将为你打开通往更高效、更强大的软件开发世界的大门。
入门 56:在Windows上使用Bash 🖥️

在本节课中,我们将学习如何在Windows环境下使用Bash终端,包括如何导航目录、查看和编辑配置文件,以及如何创建并运行一个简单的Bash脚本。这些技能是管理数据库和进行开发工作的基础。
导航与查看文件
首先,我们打开终端窗口并导航到主目录。使用 cd ~ 命令可以快速返回主目录。
执行 cd ~ 命令后,我们使用 ls -la 命令来列出当前目录下的所有文件,包括隐藏文件。
以下是 ls -la 命令的输出示例:
- 请注意两个文件:
.bashrc和.bash_profile。
理解配置文件
上一节我们查看了目录内容,本节中我们来看看这两个配置文件的作用。首先,我们关注 .bashrc 文件。
使用 less .bashrc 命令可以查看该文件的内容。.bashrc 文件主要用于配置。它本质上是一个脚本文件,在你首次打开终端窗口时执行。其中的内容是对Shell本身的配置,例如使用的颜色类型。你也可以在其中添加关于Shell历史的设置,比如希望存储多少条历史命令记录。任何放在这里的配置选项都将在终端会话开始时执行。
按 Q 键可以退出 less 查看环境。
另一个文件是 .bash_profile 文件。我们可以再次运行 less 命令,这次查看 .profile 文件。这个文件通常用于设置环境变量。例如,你可以用它来设置 JAVA_HOME 或 PYTHON_HOME 等开发所需的环境变量。
再次按 Q 键退出。
创建Bash脚本
了解了配置文件后,现在我们来动手创建一个简单的Shell脚本。在这个例子中,我将使用 Vim 编辑器。
输入 vim testhello.sh 并按回车键,这将创建一个名为 testhello.sh 的新文件。
在文件顶部,我们需要声明这是一个什么类型的文件。这里,它将是一个Bash脚本。按键盘上的 I 键进入插入模式。
然后输入以下内容:
#!/bin/bash
这行代码(称为shebang)让操作系统知道这是一个Bash脚本。
接下来,我们编写一个非常简单的脚本:在屏幕上打印一段文本。我们使用 echo 命令。
在文件中继续输入:
echo "Hello World"
按 Esc 键退出插入模式。然后输入 :wq! 并按回车键来保存文件。
现在,如果我们查看目录,会注意到多了一个名为 testhello.sh 的文件。但需要注意的是,这个文件目前还不能运行。换句话说,它不可执行,只是一个可读写的文件。
设置脚本权限并执行
为了让脚本可执行,我们需要为其设置“执行(x)”权限。这需要使用另一个命令:chmod。
使用以下命令为文件添加权限:
chmod 755 testhello.sh
命令中的 755 表示我们想要的权限类型。执行后,如果我们再次使用 ls -la 命令,会注意到该文件现在已变为可执行文件。
这意味着我们现在可以从命令行运行这个文件了。要运行文件,请输入:
./testhello.sh
按回车键后,你会看到屏幕上打印出了“Hello World”字样。这就是在Bash中创建简单脚本并使其可执行的方法。


本节课中我们一起学习了在Windows Bash环境下的基本操作。我们首先导航到主目录并查看了包含隐藏文件在内的所有文件。接着,我们探讨了两个重要的配置文件:.bashrc(用于Shell配置)和 .bash_profile(用于环境变量)。最后,我们动手实践,使用Vim创建了一个Bash脚本,通过 chmod 命令赋予其执行权限,并成功运行了该脚本,输出了“Hello World”。这些是掌握命令行操作和自动化任务的基础步骤。
入门 57:命令行目录操作指南 🗂️
在本节课中,我们将学习如何在命令行界面中查看当前所在位置、列出目录内容以及在不同目录之间进行切换。这些是使用命令行管理文件和目录的基础技能。
查看当前目录
首先,我们需要知道当前位于哪个目录。为此,我们使用 pwd 命令。
pwd 是 “print working directory”(打印工作目录)的缩写。在命令行中输入 pwd 并按下回车键,系统会返回一个路径。例如,返回一个正斜杠 /,这表示您当前位于根目录。根目录是操作系统中的顶级目录。
列出目录内容

上一节我们介绍了如何确认当前位置,本节中我们来看看如何查看当前目录下包含哪些文件和子目录。
要检查根目录的内容,我们运行另一个名为 ls 的命令,它是 “list”(列表)的缩写。输入 ls 并按下回车键,您会看到根目录下不同目录名称的列表。
为了获取每个目录更详细的信息,我们可以使用一个叫做 标志(flag) 的选项。标志用于设置您运行命令的选项。我们可以将 ls 命令与一个名为 -l 的标志一起使用,这表示结果应以列表格式打印。
以下是使用 ls -l 命令的示例:
ls -l
按下回车后,结果将以列表结构返回。
理解列表输出
现在,让我们聚焦于列表中的一些项目。首先,您需要了解链接文件、目录和标准文件之间的区别。
- 链接文件:总是由字母
l表示,并且会出现在输出行的最开头。例如,lrwxrwxrwx ... tp -> tmp表示tp是指向实际目录tmp的链接。 - 目录:由字母
d表示。例如,drwxr-xr-x ... bin表示bin是一个标准目录。您可以使用cd命令进入该目录并检查其内容。 - 标准文件:例如文本文件或配置文件,由连字符
-表示。例如,-rw-r--r-- ... resolve.conf。
理解这些不同的符号和命名约定对于查找特定文件非常重要。列表中还会显示文件的所有者和所属组信息。
更改目录
了解了如何查看内容后,接下来我们学习如何在目录之间移动。
要更改当前目录,请使用 cd 命令。例如,要切换到 etc 目录,请输入 cd etc 并按下回车。然后输入 ls 来检查该目录的内容。您会发现 etc 目录下的内容与根目录完全不同。
要确认您确实在 etc 目录中,可以再次运行 pwd 命令,它会确认您当前位于 /etc。
返回上级目录
当您需要从当前目录返回时,有两种方法。
- 使用相对路径:输入
cd ..。两个点..表示上一级父目录。按下回车后,您就回到了父目录。您可以运行pwd来确认。 - 使用绝对路径:输入
cd /。正斜杠/代表根目录。按下回车后,您将直接回到根目录。
要进入多级子目录,过程是相同的。例如,从根目录进入 etc 下的 ssh 目录:
cd etc
cd ssh
然后使用 ls 检查 ssh 目录的内容。
要从 ssh 目录逐步返回,可以连续使用 cd ..。第一次 cd .. 会让您回到 etc 目录,再次使用 cd .. 则会返回到根目录。最后,您可以通过 pwd 命令确认自己回到了根目录。
总结
本节课中,我们一起学习了命令行中目录操作的核心命令:
- 使用
pwd命令查看当前工作目录。 - 使用
ls命令列出目录内容,并通过ls -l获取详细列表格式。 - 使用
cd命令更改目录,并通过cd ..返回上级目录或cd /直接返回根目录。 - 理解了列表输出中
d(目录)、-(文件)和l(链接)等符号的含义。


您现在已经掌握了如何在命令行中导航和更改目录的基本方法。
入门 58:创建和移动目录和文件 📁

在本节课中,我们将学习如何在命令行界面中创建目录和文件,以及如何移动它们。这些是文件系统管理的基础操作,对于后续的数据库环境搭建和文件管理至关重要。
概述
我们将从检查当前工作目录开始,然后逐步学习创建新目录、进入目录、创建文件,最后学习如何将整个目录移动到另一个位置。每个步骤都会使用具体的命令进行演示。
检查当前目录
首先,我们需要确认自己当前位于文件系统的哪个位置。这可以通过 pwd 命令来实现。
运行 pwd 命令后,终端会显示当前所在的目录路径。例如,输出 / 表示位于根目录。
查看目录内容
在确认位置后,我们可以查看当前目录下有哪些文件和子目录。
使用 ls -l 命令可以列出当前目录的详细内容。例如,你可能会看到一个名为 projects 的目录。
创建新目录
接下来,我们将创建一个新的目录。创建目录使用 mkdir 命令。
以下是创建目录的步骤:
- 输入命令
mkdir submissions。 - 按下回车键执行命令。
- 再次使用
ls -l命令,确认名为submissions的新目录已经创建成功。
进入目录
创建目录后,我们可以进入这个新目录进行操作。
使用 cd submissions 命令可以进入名为 submissions 的目录。进入后,使用 ls 命令查看,会发现该目录目前是空的。
创建文件
在一个空目录中,我们可以创建新的文件。创建空文件可以使用 touch 命令。
以下是创建文件的步骤:
- 输入命令
touch test1.txt创建第一个文件。 - 输入命令
touch test2.txt创建第二个文件。 - 使用
ls -l命令,可以看到两个文本文件已成功创建并列出。
返回上级目录
完成文件创建后,我们可能需要返回到之前的目录层级。
使用 cd .. 命令可以返回上一级目录。在本例中,执行后会回到根目录。再次运行 ls -l,可以看到 projects 和 submissions 两个目录。
创建另一个目录并移动
现在,我们将在根目录下创建另一个目录,并练习移动操作。
首先,使用 mkdir archive 命令创建一个名为 archive 的新目录。使用 ls -l 确认 archive、projects、submissions 三个目录均已存在。
为了界面清晰,可以使用 clear 命令清空终端屏幕,然后再次用 ls -l 查看。
假设我们需要将 submissions 目录移动到 archive 目录内,这需要使用 mv(move)命令。
移动目录的命令格式是:mv [要移动的目录] [目标目录]。
因此,我们输入命令 mv submissions archive/ 并执行。执行后,使用 ls -l 检查,会发现根目录下的 submissions 目录消失了。
验证移动结果
为了确认移动是否成功,我们需要进入目标目录进行查看。
使用 cd archive 进入 archive 目录,然后运行 ls -l。这时可以看到 submissions 目录已经存在于 archive 之中。
之前我们在 submissions 目录内创建的文件也随目录一同移动了。使用 cd submissions 进入该目录,再运行 ls -l,即可看到 test1.txt 和 test2.txt 两个文件完好无损。

总结

本节课中,我们一起学习了命令行下的基础文件操作。我们掌握了使用 pwd 查看当前路径,使用 ls 列出目录内容,使用 mkdir 创建目录,使用 touch 创建文件,以及使用 mv 移动目录。这些命令是管理数据库相关文件和目录结构的基础,请务必熟练掌握。
入门 59:管道操作
概述

在本节课中,我们将学习命令行中的管道操作。管道是一种强大的工具,它允许你将一个命令的输出作为另一个命令的输入,从而组合多个命令来完成复杂的任务。我们将通过具体的例子来演示如何使用管道,并理解其在文件操作和数据处理中的应用。
探索目录与文件
首先,我们打开终端并运行 ls 命令来查看当前目录的内容。
ls
该命令显示当前目录下有两个文件夹:archive 和 projects。
接下来,我们可以使用 cd 命令切换到 archive 目录。
cd archive
进入 archive 目录后,再次运行 ls 命令查看其内容。
ls
结果显示有一个名为 submissions 的文件夹。我们使用 cd 命令进入这个文件夹。
cd submissions
现在,我们位于 submissions 文件夹内。再次运行 ls 命令来查看其中的文件。
ls
命令返回两个文件:file1.txt 和 file2.txt。每个文件内部都包含一些文本内容。

查看文件内容与字数统计
要查看文件的内容,我们可以使用 cat 命令。例如,查看 file1.txt 的内容:
cat file1.txt
该命令会输出 file1.txt 文件中的所有文本。
另一个有用的命令是 wc,即“字数统计”命令。使用 -w 标志可以统计文件中的单词数。
wc -w file1.txt
运行此命令后,终端会显示 file1.txt 文件中包含 181 个单词。
引入管道操作
上一节我们介绍了单独使用命令查看内容和统计字数。本节中,我们来看看如何通过管道将命令连接起来。
管道操作使用竖线字符 | 实现。它允许你将一个命令的输出直接传递给另一个命令作为输入。
例如,我们先对当前目录执行 ls 命令,它会输出两个文件名。
ls
现在,我们使用管道将 ls 的输出传递给 wc -w 命令。
ls | wc -w
这个组合命令会返回数字 2,因为 ls 列出了两个文件,wc -w 统计了这个输出中的“单词”(即文件名)数量。
使用管道统计文件字数
那么,如何使用管道来统计一个文件的实际单词数呢?

我们可以将 cat 命令和 wc 命令通过管道结合。cat file1.txt 会输出文件内容,然后管道将其传递给 wc -w 进行统计。
cat file1.txt | wc -w
执行此命令,同样会得到 181 这个结果,即 file1.txt 中的单词总数。
组合多个文件进行统计
管道的力量不仅限于单个文件。你可以轻松地组合多个文件的数据进行统一处理。
例如,如果我们想同时获取 file1.txt 和 file2.txt 两个文件的总单词数,可以这样做:
cat file1.txt file2.txt | wc -w
在这个命令中:
cat file1.txt file2.txt会按顺序输出两个文件的全部内容。- 管道
|将这些内容传递给wc -w命令。 wc -w统计接收到的所有文本中的单词总数。
命令执行后,返回的总单词数是 362。
总结

本节课中,我们一起学习了命令行中强大的管道操作。我们了解到:
- 管道符号
|用于连接命令,将前一个命令的输出作为后一个命令的输入。 - 我们实践了如何使用
ls | wc -w统计文件数量,以及使用cat <文件名> | wc -w统计文件内容单词数。 - 最后,我们还看到了如何通过
cat组合多个文件,并利用管道一次性统计它们的总单词数。
掌握管道是高效使用命令行进行数据流处理的关键一步,它能将简单的命令组合成复杂而强大的工作流程。
入门 13:重定向 📥📤
在本节课中,我们将要学习Linux系统中的重定向概念。重定向允许我们改变命令输入和输出的默认来源与去向,是命令行操作中一项非常强大的功能。
概述
任何Linux命令的基本工作流程都是接收输入并产生输出。标准输入设备通常是键盘,标准输出设备通常是屏幕。通过重定向,我们可以改变这些标准输入和/或输出的目标。
重定向的类型
Linux Shell通过一个编号系统来追踪标准输入、输出和错误。以下是三种主要的输入/输出重定向类型:

- 0:代表标准输入。
- 1:代表标准输出。
- 2:代表标准错误。
上一节我们介绍了重定向的基本概念,本节中我们来看看第一种类型:标准输入。
标准输入 (<)

标准输入通常指用户从键盘键入信息。我们使用小于号 (<) 进行输入重定向。cat 命令可以用来接收用户输入并将其保存到文件中。
以下是使用 cat 命令将用户输入存储到文本文件的步骤:

- 在终端输入命令:
cat > input.txt并按下回车。 - 此时可以开始输入文本内容。
- 输入完成后,按下
Ctrl + D来告诉cat命令文件输入结束。 - 要输出文件的内容,请输入命令:
cat < input.txt。

标准输出 (>)
我们已经使用过的许多命令,例如 ls,都会将其输出发送到一个称为“标准输出”的特殊文件。输出重定向使用大于号 (>) 来处理。
在Unix/Linux系统中,一切皆文件。这意味着每次运行 ls 这样的命令时,其输出都会被发送到Linux中的一个标准输出文件。如果你想控制输出的去向,可以使用重定向。
以下是发送输出到文本文件的示例:

- 输入命令:
ls -l > output.txt并按下回车。output.txt文件将被创建(如果不存在)或覆盖。 - 要查看该文件的内容,使用命令:
cat output.txt。显示的内容与直接运行ls -l时在屏幕上看到的一致。


标准错误 (2>)
当操作出错时,就会产生错误。在使用重定向时,你也需要指定错误信息应被写入哪个文件。你可以通过在输出箭头前显式地设置数字 2 来实现这一点。
错误可能发生在向文本文件输出数据时。请注意,错误信息不会进入标准输出流,而是会切换到由数字 2 代表的错误流。
现在我们来演示这是如何工作的。假设我们尝试列出一个不存在的目录:
- 输入命令:
ls -l /bin/usr > error.txt。你会注意到错误信息“无法访问 /bin/usr: 没有那个文件或目录”仍然打印在控制台上,而不是写入error.txt。 - 要将错误信息重定向到文件,需要使用:
ls -l /bin/usr 2> error.txt。 - 使用
cat error.txt查看文件内容,可以看到错误信息已被写入。

组合输出与错误 (2>&1)
如果你想同时处理可能找到数据或可能找不到数据的情况,可以传递不同的重定向指令,以便同时处理输出和错误。
以下是同时将标准输出和标准错误重定向到同一个文件的示例:
- 输入命令:
ls -l /bin/usr > error_output.txt 2>&1。>将标准输出重定向到error_output.txt。2>&1表示将标准错误重定向到标准输出当前指向的地方(即同一个文件)。
- 使用
cat error_output.txt查看文件,可以看到错误信息被包含在该文件中。

总结

本节课中我们一起学习了Linux重定向的核心知识。你现在知道了什么是重定向,以及如何使用三种类型的输入/输出重定向:标准输入 (<)、标准输出 (>) 和 标准错误 (2>)。你还学会了如何将标准输出和标准错误合并重定向到同一个文件(2>&1)。掌握这些技巧将极大地增强你在命令行中处理数据流的能力。
入门 61:grep命令详解 🔍

在本节课中,我们将学习一个在文件和目录中搜索文本的强大工具——grep命令。我们将了解它的基本用法、常用选项以及如何通过管道与其他命令结合使用,以精确地查找所需信息。
什么是grep?
grep 代表 Global Regular Expression Print(全局正则表达式打印)。它是一个用于在文件和文件夹中,以及文件内容中进行搜索的命令行工具。

基本搜索操作
上一节我们介绍了grep的基本概念,本节中我们来看看它的具体使用方法。
首先,我们有一个名为 names.txt 的文件,它包含一系列未按字母顺序排列的名字。
ls
cat names.txt
为了查找以特定模式开头的名字,我们可以使用grep进行标准搜索。例如,查找所有以“Sam”开头的名字:
grep Sam names.txt
这个命令会返回所有以“Sam”开头的名字列表。需要注意的是,grep默认是区分大小写的。这意味着,如果我们使用小写的“sam”进行搜索,会得到完全不同的结果集,因为它无法匹配大写的“S”。
使用标志(Flags)改变搜索行为
为了克服大小写敏感的限制,我们可以向grep传递不同的标志(flags)来获得不同的结果。
以下是几个常用的grep标志及其作用:
-
-i(忽略大小写):此标志使搜索不区分大小写。grep -i sam names.txt执行此命令将返回所有包含“sam”(无论大小写)的名字,包括“Sam”开头或中间含有“sam”的名字。
-
-w(精确匹配单词):此标志确保只匹配完整的单词,忽略部分匹配。grep -w Sam names.txt执行此命令将只返回名字恰好是“Sam”的结果,而忽略那些包含“Sam”作为一部分的其他名字(如“Samuel”)。
结合管道(Pipe)进行高级搜索
grep的强大之处在于它可以与其他命令通过管道(|)结合使用,从而在复杂的输出中进行过滤。
例如,如果我们想在系统的 /bin 目录中查找所有包含“zip”的可执行文件:
- 首先,列出
/bin目录下的所有文件,这会得到一个很长的列表。ls /bin - 为了过滤这个列表,我们可以将
ls命令的输出通过管道传递给grep。
这样,我们就只得到了文件名中包含“zip”的文件的子集,结果更加精简。ls /bin | grep zip
如果需要进一步精确搜索,我们依然可以在管道后的grep命令上应用 -i、-w 等标志。
总结

本节课中我们一起学习了grep命令的核心用法。我们了解到:
grep是一个用于文本搜索的强力工具。- 通过使用
-i标志可以进行不区分大小写的搜索。 - 通过使用
-w标志可以确保进行精确的单词匹配。 - 通过管道符
|可以将grep与其他命令(如ls)结合,实现对命令输出结果的过滤,从而高效地定位信息。
入门 62:模块小结:命令行模块回顾 🎯
在本节课中,我们将回顾命令行模块所学的核心内容,总结关键命令与概念,帮助你巩固知识。
模块概述
在命令行模块中,我们学习了如何在Linux系统中使用命令行执行操作。我们介绍了用于浏览、创建、重命名和删除文件及目录的常用命令,并探讨了如何利用管道和重定向构建自动化工作流。
上一节我们介绍了具体的命令操作,本节中我们来对整个模块的知识进行系统性的总结。
核心学习成果
完成本模块后,你应该能够:
- 理解命令行的概念及其用途。
- 使用命令行浏览硬盘。
- 使用Unix命令在硬盘上创建、重命名和删除文件与文件夹。
- 使用管道和重定向。
关键命令与操作回顾
以下是本模块涵盖的核心命令及其功能摘要:
-
pwd- 功能:打印当前工作目录的路径。
- 公式/代码:
pwd
-
mkdir- 功能:创建新目录。
- 公式/代码:
mkdir <目录名>
-
cd- 功能:更改当前工作目录。
- 公式/代码:
cd <路径>
-
文件与目录操作
- 功能:包括创建、重命名、删除文件和目录。
- 涉及命令:
touch,mv,rm,rmdir
-
grep- 功能:在文件中搜索指定的文本模式。
- 公式/代码:
grep "<模式>" <文件名>

- 管道 (
|)- 功能:将一个命令的输出作为另一个命令的输入。
- 公式/代码:
命令1 | 命令2

- 重定向 (
>,>>)- 功能:将命令的输出重定向到文件(覆盖或追加)。
- 公式/代码:
命令 > 文件(覆盖)命令 >> 文件(追加)

实践能力总结
现在,你能够运用所学知识完成以下综合任务:
- 创建一个工作目录。
- 在该目录下创建两个子目录(例如
D1和D2)。 - 在
D1和D2中创建文件和目录。 - 使用
grep命令搜索文件、目录或文件内容。
总结
本节课中我们一起回顾了命令行模块的全部内容。你学习了命令行的基础概念、核心文件操作命令,以及通过管道和重定向组合命令以提升效率的技巧。你已熟悉命令行的基本使用,在你的学习旅程中取得了扎实的进展。

做得很好,请继续保持!
1.6:什么是Git和GitHub
在本节课中,我们将学习版本控制系统的基本概念,并重点介绍两个核心工具:Git和GitHub。我们将了解它们是什么、有何区别、为何对软件开发至关重要,以及它们各自带来的优势。
你是否熟悉版本控制或版本控制系统?
这里有一个简单的例子说明它们为何有用。你是否曾在手机上打开一个应用,并收到提示要求更新到新版本?
这些提示很可能会引导你前往应用商店,然后你下载最新版本。
当你下载新版本时,你可能会注意到软件中有了新的布局、按钮或功能。在软件和Web开发中,开发者使用版本控制来追踪不同版本之间的差异。一种流行的版本追踪方法是使用像Git和GitHub这样的版本控制技术。
在本视频中,你将发现“什么是Git和GitHub”这个问题的答案。你将学习Git和GitHub之间的区别,Web开发者如何利用它们,并探索这两项服务的益处和优势。
让我们从Git开始。Git是一个版本控制系统,旨在帮助用户追踪其项目中文件的更改。
Git的设计是为了解决其创建者Linus Torvalds在管理Linux内核(Linux的操作系统)开发时所遇到的挑战。
Linux有成千上万的贡献者,他们每天都会提交更改和更新。

Git的设计就是为了帮助应对追踪所有这些更改和更新的挑战。
除了帮助追踪更改,Git的设计还旨在解决其他版本控制系统的一些缺点。
Git相较于类似系统提供的优势包括更好的速度和性能、可靠性、免费和开源访问,以及易于理解的语法。

同样重要的是要注意,Git主要通过命令行使用。
开发者通常发现Git的语法和命令易于学习。

开发者常用的另一项服务是GitHub。GitHub是一个基于云的托管服务,让你可以通过用户界面管理Git仓库。
Git仓库用于追踪特定文件夹中所有文件的更改,并保留所有这些更改的历史记录。
它集成了Git的版本控制功能,并通过在其基础上提供自身功能来扩展这些功能。
其中一些最常见的功能包括访问控制、拉取请求和自动化。


你将在本课程后面学到更多关于这些功能的知识。
这些功能被划分到不同的定价模型中,以适应不同规模的团队和组织。
同样需要指出的是,GitHub在Web开发者中非常流行。
它就像一个社交网络。例如,项目可以是私有的或公开的;GitHub上的用户有自己的个人资料,其他用户可以关注;公开项目可以接受来自全球任何人的代码贡献。
它还包括其核心开发工具之外的多种功能,如文档、工单管理和项目管理功能。
现在你已经熟悉了Git和GitHub版本控制系统,以及它们提供的益处和优势。
这只是你使用Git和GitHub进行版本控制之旅的开始。做得好。
总结

本节课我们一起学习了版本控制的基本概念。我们了解到Git是一个强大的分布式版本控制系统,用于高效地追踪项目文件的更改历史。而GitHub则是一个基于云的平台,为Git仓库提供托管、协作和社交化功能。两者结合,为现代软件开发团队提供了管理代码、协作开发和维护项目历史的完整解决方案。理解它们是成为一名高效开发者的重要一步。
入门 64:创建与克隆存储库
在本节课中,我们将学习如何在GitHub上创建一个新的代码仓库(Repository),以及如何将其克隆(Clone)到你的本地计算机上。这是开始使用Git进行版本控制的第一步。
概述
我们将分步完成以下操作:首先在GitHub网站上创建一个新的仓库,然后通过命令行工具,使用Git命令将这个远程仓库完整地复制到本地环境中。
创建GitHub仓库
上一节我们介绍了GitHub的基本概念,本节中我们来看看如何创建一个新仓库。
登录GitHub网站后,点击绿色的“Create repository”按钮。
点击按钮后,页面会跳转到创建新仓库的界面,系统会提示选择仓库的所有者。
在此示例中,我选择我的个人账户作为所有者。
接下来,需要输入一个仓库名称。
我输入的名称是 my-first-repo。注意输入框旁边有一个绿色的对勾图标。
这只是GitHub在提示我这个名称可用,可以用于创建仓库。
如果名称不可用,我会看到一个“X”图标,并被提示重新命名。
现在,我需要为描述输入框填写内容。
我输入“Practice account for learning Git”。下一个需要了解的选项是选择仓库为公开(Public)或私有(Private)。
公开意味着互联网上的任何人都可以查看这个仓库。
我仍然控制着谁可以对它进行修改,只是在互联网上它是可见的。
下一个选项是私有,意味着任何人都无法看到它。我只能通过授权来允许他人访问这个仓库。
接下来的几个选项是关于初始化的。我可以选择用README文件、.gitignore文件和许可证(如果需要)来初始化一个仓库。
目前,我只选择README文件选项,然后点击“Create repository”按钮。
理解仓库内容
现在,一个仓库已经设置完成。我可以看到仓库中有一个名为README.md的单一文件。
.md是Markdown的缩写,这是一种创建文档的流行方法,因为它是创建HTML页面的简写形式。
这允许我执行诸如创建标题和文本、插入图像以及各种其他网页元素的操作。
请注意,主分支(main branch)也已经创建。需要知道的是,你创建的每个仓库在开始时都会有一个单一的主分支。
这也被称为主线(main line)。
仓库操作选项
接下来,界面上会显示一些额外的按钮选项。
第一个按钮标记为“Go to file”。然后是“Add file”,你可以通过用户界面(UI)使用它来添加新文件。
最后,是一个绿色的标记为“Code”的按钮。点击此按钮会为我提供克隆(Clone)此仓库的GitHub UI选项。
第一个是HTTPS选项,其中包含仓库的HTTPS URL。
我可以使用这个URL,通过git clone命令将仓库拉取(Pull)到本地。
下一个是SSH选项。但要使用它,我必须设置我的SSH密钥并将其分配给用户账户。
最后,在下方还有GitHub CLI选项。请注意,如果我愿意,还有适用于GitHub Desktop的额外选项。
最后,我还可以下载一个压缩的ZIP文件,其中包含此演示的所有文件和文件夹结构。
克隆仓库到本地
我将展示如何使用HTTPS开始。选择HTTPS选项,然后点击“Copy”按钮复制用于克隆的HTTPS URL。
现在我转到命令行界面,我将使用它来运行克隆仓库的命令。我当前在我的主目录(home directory)中。
我通常喜欢做的第一件事是为当前正在处理的所有仓库创建一个目录。
首先,我使用命令 mkdir 创建一个目录,然后输入我想要创建的目录名称,即 projects。
接下来,我可以使用 cd 命令进入该目录。现在,我可以运行命令将项目从GitHub UI克隆到本地。

为此,我输入命令 git clone 并粘贴我之前复制的HTTPS URL。
git clone https://github.com/your-username/my-first-repo.git
最后,我按下键盘上的回车键。注意,我收到一条消息,说明Git正在克隆到 my-first-repo 文件夹中。
然后它显示了所有已接收对象的消息。
它还显示了一个100%的状态消息。最后,是一条简单的“done”声明。
现在,我可以运行 ls -la 命令来列出目录,这意味着列出所有目录。
请注意,我有了我的仓库,我将其命名为 my-first-repo。
这就是我们在GitHub上设置的仓库名称。
最后,如果我使用 cd 命令进入该文件夹,我可以看到一个文件,即 README.md 文件。
如果我使用 ls -la 命令,还会列出另一个名为 .git 的文件。稍后当你探索如何将其用于源代码控制时,你会了解更多关于这个文件的信息。

总结

本节课中我们一起学习了Git与GitHub协作的起点:创建远程仓库与克隆到本地。我们完成了在GitHub上创建新仓库、理解其初始结构(如README.md和主分支),并通过git clone命令将远程仓库完整复制到本地工作目录的过程。这为后续的版本控制操作奠定了基础。
入门 65:Git的工作原理 🛠️
在本节课中,我们将学习Git的核心工作原理,包括其基本概念、工作流程以及如何在本地操作Git仓库。我们将通过简单的命令和示例,帮助你理解Git如何跟踪和管理文件的变化。

GitHub简介
正如你所知,GitHub是一个基于云的托管服务,它允许你通过用户界面管理Git仓库。它就像一个社交网络,你可以关注用户或接受来自世界任何地方的代码贡献。
本地仓库操作
在之前的视频中,你创建并将一个仓库克隆到了本地设备。现在,我将解释如何将仓库拉取到本地设备,并演示在Git Bash(Windows用户)或终端(Mac用户)中可以使用的命令。

命令行环境
这指的是输入命令的应用程序。让我们通过输入cd和目录名称来移动到目标目录。
cd my_first_repo

进入目录后,运行列出所有内容的命令。
ls -la
-la是“list all”的缩写,表示列出所有文件和文件夹,包括隐藏的。
目录内容分析
此目录中有四个项目。我将重点关注其中两个:.git项目和README.md项目。
让我们从README.md文件开始。这个项目是在GitHub上创建仓库时添加的。
另一个项目是一个名为.git的文件夹,这是一个用于跟踪所有更改的隐藏文件夹。在Linux中,任何以点开头的文件夹都是隐藏文件夹。
当你创建仓库时,这个文件夹会自动创建,你将在本课程后面了解更多关于它的信息。在我运行的命令中,我使用了-la参数,以便列出包括隐藏项在内的所有文件和文件夹。
.git文件夹是通过运行git init命令初始化的。由于仓库是在GitHub上创建的,我们不需要运行它。GitHub在其“创建新仓库”流程中处理了所有这些。

Git工作流程
现在让我们关注Git的工作流程。Git使用的工作流程可以分为三种状态:已修改、已暂存和已提交。
接下来,我将逐一介绍每种状态,然后提供一个向我的Git仓库添加新文件的示例来展示其实际运作。

已修改状态
在仓库内添加、删除或更新任何文件都被视为“已修改”状态。Git知道文件已更改,但尚未跟踪它。这就是“暂存”状态发挥作用的地方。
已暂存状态
为了让Git跟踪一个文件,需要将其放入“暂存区”。一旦添加,任何修改都会被跟踪,这为提交更改提供了一个安全网。
已提交状态
在Git中提交文件在很多方面就像一个保存点。Git将保存文件并拥有当前更改的快照。
工作流程示例
让我介绍一个清晰总结工作流程的例子。
假设你有一个包含刚才提到的三个阶段以及远程仓库的工作流程。
- 一个文件从工作目录添加到暂存区。
- 从那里,文件被提交。
- 然后被推送到远程仓库。
- 从远程仓库,文件现在可以被获取、检出或合并到工作目录。
你将在后面了解更多关于这方面的内容。
总结 🎯
在本节课中,我们一起学习了Git的基础知识。你现在知道了Git文件夹内部有什么,并理解了Git的工作流程。具体来说,我们介绍了:
- GitHub作为Git仓库托管服务的作用。
- 如何在命令行中导航和查看仓库内容。
- Git工作流的三个核心状态:已修改、已暂存和已提交。
- 通过一个简单的示例,了解了文件如何在这三个状态间移动,并最终与远程仓库同步。

干得不错!你已经掌握了一些Git的基础知识。
入门 66:添加与提交

概述
在本节课中,我们将学习Git版本控制系统中两个核心操作:git add与git commit。你将了解如何将新文件纳入Git的跟踪范围,以及如何将更改正式保存为一个版本记录。这是将本地工作成果转化为项目历史的关键步骤。
检查当前状态
在开始任何操作前,了解当前Git仓库的状态是良好的实践。
打开终端窗口,首先确认当前所在目录。可以使用pwd命令(print working directory的缩写)。假设当前位于my_first_repo目录中。
接下来,使用ls -l命令查看该目录下的内容。可以看到两个项目:一个README.md文件和一个名为.git的隐藏文件夹。
在添加文件或进行更改之前,最好先检查是否存在任何未提交的更改。这可以通过git status命令实现。
git status命令会显示当前所在的分支。在本例中,提示位于名为main的分支上,并且该分支与origin/main保持同步。这意味着本地机器上的所有最新文件与Github UI(即所有人提交到的服务器)上显示的内容完全一致。
git status还提示当前没有需要提交的内容,工作树是干净的。
创建并跟踪新文件
现在,我们来学习如何添加一个简单的文本文件。
使用touch test.txt命令创建一个名为test.txt的文件。
然后,再次运行git status命令。


此时,Git提示存在一个未跟踪的文件,即刚刚添加的test.txt文件。它还提示没有要添加到提交的内容,但存在未跟踪的文件,并建议使用git add命令来跟踪它们。
git add命令的目的是通知Git,你希望跟踪此文件,并将其包含在即将进行的提交中。
以下是添加文件到暂存区的步骤:
- 运行命令
git add test.txt。 - 再次运行
git status以确认该文件现在已被跟踪。
现在,通知显示分支是最新的,并且提示有已暂存的更改等待提交,即这个名为test.txt的新文件。
理解暂存区
上一节我们介绍了如何将文件添加到跟踪状态,本节中我们来深入理解“暂存区”的概念。
如果需要撤销暂存操作,可以使用git restore命令,配合--staged标志和文件名test.txt。
运行该命令将从提交中取消暂存该文件。
再次运行git status,可以看到文件恢复到了未跟踪状态。
然后,我们重新使用git add test.txt添加文件,并运行git status,确认文件回到了已跟踪(暂存)状态。
可以使用clear命令清屏。从现在起,所做的任何更改都将被跟踪,并在最后使用git commit命令提交。
暂存区非常重要,因为你本质上是在准备将所有希望作为当前工作特性一部分的文件和更改打包。基本上,你是在为提交准备所有相关内容。
必须记住,这仅发生在你的本地机器上。Git的分布式特性意味着,只有使用实际的push命令时,更改才会推送到服务器。你在此处所做的任何更改都仅针对你和你的本地机器。其他任何人从Github拉取项目时,只会获取远程服务器上可用的内容。
提交更改
在准备好所有更改后,下一步是将它们永久记录到项目历史中。
首先,输入git commit。可以传入-m标志(代表message),允许输入一条将附加到此次提交上的消息。
在本例中,消息是“adding a new file for testing”。
接下来,按键盘上的回车键。现在注意响应信息:一个文件被更改,零行插入,零行删除。还有一个关于文件test.txt的“create mode”声明。
最后,如果运行git status命令,响应会显示没有需要提交的内容,工作树是干净的。
但是,需要注意屏幕顶部的消息。该消息提示使用git push来发布本地提交。这与我之前提到的内容相关联:所有这些更改都在我的本地机器上,只有当我运行push命令时,它们才会被上传到远程服务器。你将在未来的课程中了解更多关于push和pull命令的内容。
总结


本节课中,我们一起学习了Git工作流中的关键环节:添加与提交。我们掌握了使用git add将新文件或更改放入暂存区,以及使用git commit -m “提交信息”将暂存区的内容创建为一个永久的版本记录。重要的是,我们理解了这些操作目前仅影响本地仓库,需要后续的git push命令才能与团队共享。通过实践git status来检查状态,你能够清晰地跟踪文件从“未跟踪”到“已暂存”再到“已提交”的整个生命周期。
入门 67:分支管理 🪵

在本节课中,我们将要学习Git中一个核心且强大的功能——分支。分支允许你在不影响主代码线的情况下开发新功能、修复错误或进行实验。我们将通过一个完整的流程,学习如何创建分支、在分支上工作、推送分支、创建拉取请求以及最终将更改合并回主分支。
概述
分支是Git版本控制系统的基石,它支持并行开发。通过创建独立的分支,团队成员可以在隔离的环境中工作,而不会干扰主分支的稳定性。完成工作后,可以通过拉取请求和代码审查流程,将更改安全地合并回主分支。
上一节我们介绍了Git的基本提交和工作流,本节中我们来看看如何利用分支进行更高效、更安全的协作开发。
创建新分支
首先,我们需要确保处于正确的项目目录中。可以使用 pwd 命令来确认当前工作目录。
pwd
接下来,执行 git status 命令是一个好习惯,它能确保当前工作区是干净的,没有未提交的更改。
git status
确认无误后,就可以创建新分支了。创建分支主要有两种等效的方法:
以下是两种创建分支的命令:
git checkout -b <branch-name>:此命令会创建一个新分支,并立即切换到该分支。git branch <branch-name>:此命令仅创建一个新分支,但不会自动切换过去。


在本例中,我们使用第一种方法,创建一个名为 feature/lessons 的分支。
git checkout -b feature/lessons
创建并切换后,可以使用 git branch 命令来验证。当前所在的分支前会有一个星号 (*) 标记。
git branch
现在,我们所做的任何修改都只会影响这个新的 feature/lessons 分支。主分支 (main) 完全感知不到这些更改,即使我们将代码推送到远程仓库也是如此,因为分支是独立存在的。
在分支上进行开发
要让主分支识别到特性分支上的更改,需要先将特性分支合并回去。在此之前,通常需要一个代码审查环节,这就是拉取请求的用武之地。
现在,我们在新分支上添加一些内容。首先,创建一个简单的文本文件。
touch test2.txt
然后,使用 git add 命令将新文件添加到暂存区。
git add test2.txt

接着,使用 git commit 命令提交这次更改。
git commit -m "Add test2.txt file in feature branch"
推送分支与创建拉取请求
提交完成后,需要将本地分支推送到远程仓库(如GitHub)。
git push -u origin feature/lessons
命令中的 -u (或 --set-upstream) 参数是良好的实践,它建立了本地分支与远程分支的追踪关系,简化了后续的推送和拉取操作。
推送成功后,GitHub会检测到新分支,并通常会提示你基于此分支“比较并创建拉取请求”。拉取请求的目的是让团队成员对分支上的更改进行同行评审,验证代码是否正确,并确保其符合团队的代码标准和测试要求(如单元测试、集成测试)。
接下来,我们打开GitHub的网页界面。在仓库页面,可以看到新推送的分支以及创建拉取请求的按钮。点击后,进入创建页面。
在拉取请求界面,可以看到我们正在将 feature/lessons 分支与 main 分支进行比较。差异部分清晰地显示了新增的 test2.txt 文件。填写必要的标题和描述后,点击“创建拉取请求”。
团队其他成员会收到通知,并可以审查代码、提出意见、批准或请求更改。这种方式比所有人直接在 main 分支上工作要清晰得多,尤其适用于功能紧密关联或可能被他人代码影响的场景。独立分支使项目管理更容易,并且你可以创建任意数量的分支。
合并更改与清理
由于这是一个演示项目,没有其他评审者,我们可以直接合并这个拉取请求。在GitHub的拉取请求页面,点击“合并拉取请求”并确认。
合并后,系统会询问是否删除远程的特性分支。在实际项目中,这取决于团队策略,你可以选择删除以保持仓库整洁,也可以保留。此处我们选择保留。
现在,test2.txt 文件中的更改已经合并到了远程的 main 分支中。
同步本地主分支
最后,我们需要回到本地的命令行环境,将远程主分支的最新更改拉取到本地。
首先,确认当前仍在特性分支,然后切换回主分支。
git checkout main
接着,执行 git pull 命令,获取并合并远程仓库的最新更改。
git pull

操作完成后,你可以使用 ls 命令列出目录文件,验证 test2.txt 文件已经成功出现在本地主分支中。
ls
总结


本节课中我们一起学习了Git分支管理的完整工作流。我们实践了从创建新分支 (git checkout -b)、在分支上提交更改,到推送分支 (git push -u)、在GitHub上创建拉取请求进行代码审查,最后将分支合并回主分支并同步本地仓库 (git checkout main, git pull) 的全过程。掌握这个工作流,是你与其他开发者进行高效、安全协作的关键。
入门 68:远程与本地仓库 🖥️➡️☁️
在本节课中,我们将要学习Git中本地与远程仓库的核心概念、区别以及它们之间如何协作。理解这两者对于团队高效协作至关重要。
概述
在互联网普及之前,为了备份和传输,将项目文件保存到不同的机器上是一个繁琐的过程。这需要手动地在机器之间逐个复制文件,导致团队工作效率低下。如今,云计算提供了一种更高效的方式来实现这一目标。本节视频将解释GitHub上远程与本地仓库的区别。
本地与远程仓库的概念
上一节我们介绍了Git工作流中的修改、暂存和提交。本节中,我们来看看如何将你的更改从本地推送到远程仓库。
- 远程:指的是开发者可以推送更改到的任何其他远程仓库。这可以是一个集中式的仓库,例如由GitHub提供的仓库,或者其他开发者设备上的仓库。
- 本地:指的是你的个人机器,可以是笔记本电脑、台式机甚至移动设备,并且只有你可以访问。
为了演示这两者的实际运作,假设我们有一个名为 CodingProject1 的项目,它位于GitHub上并拥有一个唯一的URL。换句话说,这个项目存储在远程服务器上。
克隆、拉取与推送
在本课中,你会听到一些新术语,如克隆、推送、拉取和仓库。别担心,这些很快都会得到解释。
当用户想要将此项目复制到其本地设备时,他们需要执行以下操作之一:如果是第一次,则进行克隆;或者拉取以获取最新的更改。
以下是克隆和同步项目的基本步骤:
- 克隆项目:用户首先需要在本地机器上选择一个文件夹。然后,
CodingProject1从服务器被克隆并复制到所选文件夹中。 - 本地修改:用户随后可以对项目进行更改。
- 推送更改:用户可以将这些更改推送回服务器。
- 拉取更新:其他在同一代码库上工作的用户在其本地机器上看不到这些更改,除非他们从服务器拉取最新的更改。

Git的优势之一在于,你可以离线工作,然后在准备好时提交你的更改。
实践操作示例
现在,让我们通过一个例子来具体看看如何在GitHub中完成这些操作。
首先,我将使用 git init 命令创建一个新的本地仓库。
mkdir my_second_repo
cd my_second_repo
git init
这将返回一行信息,告诉我一个空的仓库已在指定路径下初始化。如果我执行另一个命令 git remote,它会返回空白。原因是我只初始化了一个本地仓库,它还没有连接到位于GitHub或另一台服务器上的中央仓库。目前,它只在我机器的本地可用。
现在,我将退出这个目录,并进入我之前创建的另一个仓库(my_first_repo)。这个仓库已经通过远程URL连接到了GitHub。
cd ../my_first_repo
git remote -v
Git会告诉我它设置为 git@github.com:git-tutorials-101/my-first-repo.git。接下来,我将把这个URL设置给我们新创建的第二个仓库。
cd ../my_second_repo
git remote add origin git@github.com:git-tutorials-101/my-first-repo.git
这里通常使用的名称是 origin。再次执行 git remote -v 命令,现在它已设置为指向GitHub上的仓库。
接下来,我将使用 git pull 命令,它将连接GitHub服务器并从该仓库拉取所有更改。
git pull
现在,我的本地已经有了所有更改,但当我检查目录时,它是空的。原因是我还没有建立一个与服务器仓库分支匹配的本地分支。幸运的是,我可以通过执行以下命令来改变这一点:
git checkout main
这将在我的本地建立一个 main 分支,用于跟踪远程的 main 分支。现在,当我使用 ls 命令检查文件夹时,它确认我的本地已经有了 README.md、test 和 test2 文件。

总结
本节课中,我们一起学习了GitHub中本地与远程仓库的区别。这有助于你为在开发团队内更高效地交换数据做好准备。理解如何克隆、拉取和推送是使用Git进行协作开发的基石。下次见!
入门 69:推送与拉取操作详解 🚀
在本节课中,我们将要学习Git版本控制系统中两个核心的协作命令:git push 和 git pull。你将学会如何将本地仓库的更改上传到远程仓库,以及如何从远程仓库获取最新的更改并同步到本地。

检查本地仓库状态
上一节我们介绍了如何使用 git add 和 git commit 来记录本地更改。在开始推送或拉取操作之前,首先需要检查当前仓库的状态。
以下是检查状态的命令:
git status:查看当前分支状态、暂存区和工作区的变化。git branch:列出所有本地分支,并高亮显示当前所在分支。
执行 git status 后,你可能会看到类似这样的提示:
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
这表示你的本地 main 分支比远程仓库(origin)的 main 分支领先一个提交。这体现了Git分布式工作流的优势:你可以在离线状态下工作,仅在需要同步时通过 git push 或 git pull 与远程仓库通信。
推送更改到远程仓库
了解了本地状态后,本节中我们来看看如何将本地的提交上传到远程仓库。
推送操作使用 git push 命令。其基本语法是:
git push <远程仓库名称> <本地分支名>:<远程分支名>
通常,远程仓库的默认名称是 origin。
操作步骤如下:
- 确保你位于正确的分支上(例如
main)。 - 执行推送命令。例如,将本地
main分支推送到远程origin仓库的main分支:git push origin main - 如果使用HTTPS协议,系统会提示你输入GitHub(或其它平台)的用户名和密码。
- 推送成功后,Git会将你本地仓库的提交快照上传到远程仓库。Git会比较远程和本地的文件,如果没有冲突,会自动合并,这称为 自动合并。如果存在冲突,推送会失败,你需要先在本地解决冲突。

推送完成后,你可以刷新GitHub等远程仓库的页面,确认你的文件(例如 test.txt)和提交已经成功显示。
从远程仓库拉取更改
在团队协作中,其他成员也会向远程仓库推送更改。为了保持本地代码最新,你需要定期从远程仓库拉取更新。
拉取操作使用 git pull 命令。其本质是执行了两个操作:git fetch(获取远程最新数据)和 git merge(将远程数据合并到本地当前分支)。
操作步骤如下:
- 假设其他人在远程仓库的
test.txt文件中添加了一行新内容并提交。 - 此时,你的本地
test.txt文件还没有这行内容。 - 在本地仓库目录下,执行拉取命令:
git pull origin main - Git会从远程
origin仓库的main分支获取最新更改。如果成功,终端会显示类似1 file changed, 1 insertion(+)的信息。 - 拉取完成后,Git会尝试将远程的快照与你本地的快照自动合并。如果没有冲突,合并将自动完成。此时,你本地
test.txt文件的内容就更新了,包含了远程的新增内容。

总结与最佳实践
本节课中我们一起学习了Git协作的核心流程。
关键命令总结:
- 推送:
git push将本地提交上传到远程仓库。 - 拉取:
git pull将远程仓库的最新更改下载并合并到本地。
最佳实践建议:
- 在
push之前,先执行git pull获取最新远程更改,这能极大降低代码冲突的概率。 - 始终使用
git status确认当前分支和状态,确保你在正确的分支上进行操作。 - 理解
git pull是fetch加merge的组合,遇到复杂合并情况时,可以分开执行这两个命令以便更清晰地处理。


通过掌握 push 和 pull,你已能够参与基本的Git团队协作,在分布式工作流中同步和贡献代码了。
P70:工作流范例
在本节课中,我们将学习什么是工作流,并了解软件开发中一种常见的工作流模式——功能分支工作流。我们将通过一个简单的例子来理解其重要性,并学习如何使用 Git 和 GitHub 来实践它。
你是否曾申请过工作?这个过程包括准备简历、寻找职位、提交申请、准备面试。这就是一个工作流的例子。在计算机编程中,工作流非常重要。通过本视频,你将能够描述什么是工作流,并识别不同的可用工作流。
现在,让我们从一个例子开始,说明工作流为何重要。
作为一名在项目上工作的开发者,你首先需要将项目从远程仓库拉取到你的本地机器。这通常被称为检出项目或拉取项目。项目到了本地机器后,你可以构建、运行项目并进行修改。完成后,你必须将所做的更改推送回远程仓库,以便其他开发者能看到。
从这个例子中,你可以理解工作流的目的是指导你和团队中的其他成员。它不应该干扰或阻碍部署、测试,或任何其他为项目做出贡献的开发者。
选择工作流需要仔细考虑。这可能取决于团队的规模、工作场所的文化,以及你打算构建或更新的产品类型。考虑到这些,让我解释一下功能分支工作流,这是许多开发者使用的常见工作流。
功能分支工作流意味着你从主线创建一个新分支,并在这个专用分支上工作,直到任务完成。需要制定规则和条件,以确保这段代码分支保持良好的状态。
每个代码库都有一个主仓库,它本质上是应用程序的“单一事实来源”。所有更改,如添加、编辑或删除,都直接提交到功能分支。主分支保持不变。当你对你添加的代码感到满意并准备就绪时,你必须提交更改,然后推送到服务器仓库。提交时,你推送更改。由于它是一个功能分支,随后会有一个拉取请求。这个拉取请求会与主分支进行比较,以便进行代码同行评审的开发者能确切看到更改了什么。一旦经过评审并获得批准,它就可以被合并到主线中。

上一节我们介绍了功能分支工作流的概念,本节中我们来看看如何使用 Git 和 GitHub 来具体操作。
在创建新分支之前,始终确保你拥有最新的代码。你可以通过运行 git pull 命令从远程仓库拉取最新代码来实现。
接下来,你需要创建你的新分支。你可以通过使用带有 -b 标志的 checkout 操作来完成。
以下是创建并切换到新分支的命令:
git checkout -b feature-branch-name

现在,让我们向这个分支添加新内容。我们创建一个 README.md 文件。为此,你可以使用 git add . 来添加所有更改,或者使用 git add README.md 来添加特定文件。
接下来,你需要提交新文件,并提供一个有意义的提交信息,以便其他开发者了解你添加了什么。为此,运行 git commit 命令,并使用 -m 选项来包含一个简短描述更改的信息。
以下是提交更改的命令:
git commit -m "Add README.md file with project overview"
现在,文件已被添加到本地分支。这意味着该文件目前仅对你本地可见。为了让其他开发者看到更改,你需要将文件推送到远程仓库。你可以通过运行 git push 命令并引用新分支来实现。
以下是推送分支到远程仓库的命令:
git push origin feature-branch-name
更改现在被推送到了 GitHub 上的远程仓库。

你的下一步行动是将其作为拉取请求的一部分进行评审,但关于拉取请求的更多内容将在以后讨论。

本节课中我们一起学习了工作流的概念,特别是功能分支工作流。我们了解了它的目的、基本步骤,以及如何使用 Git 命令(如 git checkout -b、git add、git commit 和 git push)来实践它。掌握工作流对于团队协作和高效的项目管理至关重要。


入门 70:HEAD指针详解 🎯
在本节课中,我们将要学习Git中一个核心概念——HEAD指针。你将了解HEAD是什么,它如何工作,以及如何通过它来追踪和管理你当前所在的分支。
概述

上一节我们介绍了.git隐藏文件夹,它负责追踪项目的所有变更。本节中我们来看看Git是如何知道我们当前在哪个分支上工作的。答案就在于一个名为HEAD的特殊指针。
什么是HEAD指针?
Git通过一个名为HEAD的特殊指针来追踪当前所在的分支。这个指针是.git文件夹中的一个文件,它指向你当前正在查看的提交。
核心概念:HEAD是一个指向当前分支最新提交的引用指针。

如何查看HEAD指针?
以下是查看HEAD指针内容的步骤:
- 首先,在终端中打开你的项目目录。
- 进入
.git文件夹:cd .git - 查看
HEAD文件的内容:
执行此命令后,通常会看到类似cat HEADref: refs/heads/main的内容。这表示HEAD当前指向main分支。

HEAD与分支的关系

在Git中,我们一次只在一个分支上工作。每个分支的最新提交记录都存储在.git/refs/heads/路径下。
让我们查看main分支当前指向的提交:
cat .git/refs/heads/main
执行此命令后,会出现一个哈希ID。这个哈希ID就是main分支上最新提交的引用。
切换分支时HEAD如何移动?
当我们切换分支时,HEAD指针会随之移动,指向新的分支。
- 切换到
testing分支:git checkout testing - 再次查看当前分支,确认已切换:
此时,git branchHEAD指针已从指向main分支改为指向testing分支。
我们可以通过查看HEAD文件来验证这一变化:
less .git/HEAD
你将看到内容从ref: refs/heads/main变为ref: refs/heads/testing。
实践演示:HEAD的工作流程
让我们通过一个简单的例子来演示HEAD如何工作。
-
确认当前分支:
运行git branch命令,可以看到当前位于main分支。
通过cat .git/HEAD命令确认,它指向refs/heads/main。 -
切换分支:
使用git checkout命令切换到另一个分支,例如feature/testing:git checkout feature/testing再次查看
HEAD文件,会发现它现在指向refs/heads/feature/testing。 -
返回主分支并查看提交哈希:
切换回main分支:git checkout main查看
main分支指向的最新提交哈希ID:cat .git/refs/heads/main这会显示一个长字符串(如
8b55f...),它是该工作目录最新提交的唯一标识。
提交如何更新HEAD引用?
提交操作会更新分支所指向的提交哈希,从而间接更新了HEAD的最终指向。
-
修改文件:
对项目中的文件进行修改,例如更新README.md文件。 -
检查哈希ID(提交前):
在提交前,再次运行cat .git/refs/heads/main,哈希ID与之前相同,因为尚未创建新提交。 -
添加并提交更改:
git add . git commit -m “minor update” -
验证哈希ID(提交后):
提交后,再次检查main分支的引用文件:cat .git/refs/heads/main你会发现哈希ID已经更新为一个新的值(如
9c90a...)。每当有新的提交发生时,这个ID就会更新为该工作目录的最新提交。

总结
本节课中我们一起学习了Git的HEAD指针。你现在知道了HEAD是一个指向当前所在分支最新提交的引用指针。通过切换分支,你可以改变HEAD指向的分支。而每次提交都会更新对应分支的提交哈希,从而让HEAD始终指向最新的工作状态。理解HEAD是掌握Git分支管理的基础。
入门 72:使用Git diff命令追踪变更 🔍
在本节课中,我们将学习如何使用Git的diff命令来比较文件、分支和提交之间的差异。这个工具对于理解代码的演变过程至关重要。
概述
优秀的文学作品很少能一蹴而就,通常需要经过多次修改,作者才会对最终成果感到满意。编程工作亦是如此,有时你需要回顾旧的代码。本视频将指导你如何使用Git diff来比较文件、分支和提交之间的变更。
Git diff的基本概念
你可能已经知道,git status命令可以告诉你哪些文件被修改过。而git diff命令则更进一步,它能精确地告诉你这些修改具体是什么。你可以将它们视为一个文件系统:git status告诉你文件名,但要打开文件查看内容,你需要使用git diff。
一个简单的例子
假设你有一个名为cities.txt的文本文件,其中记录了你访问过的城市名称。你在南美旅行期间一直在更新这个列表,但回家后却记不清具体记录了哪些内容。这时,git diff就派上用场了。
git diff会比较文件的先前版本与当前版本,找出所有差异。它会明确告诉你哪些内容被删除了,以及哪些内容被添加到了文件中。对于你的cities.txt文件,git diff会显示你删除了版本A中的一个城市,并添加了版本B中出现的一个新城市。
Git diff的详细用法

上一节我们介绍了git diff的基本概念,本节中我们来看看它的几种具体使用场景。git diff可用于比较本地仓库中的文件,也可用于比较提交和分支。
1. 比较工作区与暂存区(或HEAD)
首先,我们来看一个简单的例子。进入本地仓库,找到一个名为README.md的文件,并稍作修改。你可以使用任何编辑器(如VS Code)进行修改,也可以通过执行vim命令进入文件编辑模式,删除几个词,然后保存。
如果你想了解更多关于Vim的信息,本课末尾提供了一个扩展阅读链接。
接下来,使用git diff工具将更新后的文件与HEAD进行比较。因为我们尚未完成提交,所以无法将其与另一个提交进行比较。
输入命令:git diff HEAD -- <文件名>。这将返回一个输出,显示每个文件中发生的更改。在这里,以减号(-)开头的行代表原始内容,而以加号(+)开头的行则代表当前内容。在我的例子中,输出告诉我“minor update”这几个词已被删除。
2. 比较两个提交
除了单个文件,你还可以比较之前的提交。
首先,使用git log命令显示提交历史。这里我也会使用--pretty标志,以便每行显示一个提交。开发者常用--pretty标志使输出更易读。
每个提交都有其唯一的ID代码。我将对最近一次提交和最早一次提交的ID代码执行git diff命令。
Git会遍历所有文件,记录发生的所有更改,并返回两者之间的差异。
3. 比较两个分支
最后,我将展示git diff的另一种用法:比较分支。
如果我执行git branch命令,它将显示仓库中所有可用的分支。然后,我可以使用git diff命令,传入我的主分支(main)作为第一个参数,功能分支(feature)作为第二个参数。同样,这将显示两个分支之间发生的所有更改。
输出显示,我的功能分支包含先前的更新,而主分支包含最新的更新。

总结
本节课中,我们一起学习了如何使用git diff命令来追踪文件、分支和提交之间的变更。这个工具可以帮助你及时了解更新情况,避免错误或工作重叠。下次见!
入门 73:Git Blame命令详解 🕵️
在本节课中,我们将要学习Git中一个非常实用的命令——git blame。这个命令能帮助我们追踪文件中每一行代码的修改历史,包括是谁、在什么时间、做了哪些更改。这对于团队协作和代码审查至关重要。
想象一下,当你管理一个庞大的开发团队时,跟踪每个人对文件的修改和更新会变得多么复杂。幸运的是,Git提供了一个非常有用的命令来追踪“谁在何时做了什么”,这个命令就是git blame。

Git的核心功能与git blame的作用

Git的核心功能之一是能够追踪和记录仓库中每个文件的完整变更历史。为了查看和验证这些变更,Git提供了一套工具,允许用户逐步查看历史记录,并查看对每个文件所做的编辑。git blame命令就是用来查看特定文件的变更,并显示做出这些变更的日期、时间和用户。

到目前为止,你应该已经知道如何使用像git log这样的命令来查看所做的更改。现在,我们将使用一个示例文件来演示git blame的工作原理。

运行git blame命令

让我们从一个基本的git blame命令开始。要运行git blame命令,需要键入git blame和文件名。例如:
git blame feature.js
按下回车后,Git会返回该文件所有变更的列表。为了理解发生了什么,让我们分解这些“blame”信息,并逐行查看。
理解git blame的输出格式

首先,我来引导你了解每一行的格式。每一行都将以提交ID开头,然后是作者、进行更改的日期和时间,以及发生更改的确切行号。接着,返回的是实际的更改内容或代码。
以下是输出中每个部分的含义:
- 提交ID:这是提交的引用ID。同一个ID可能会出现在多行中,这表明同一个开发者进行了一次包含多行修改的提交。
- 作者:创建该提交的人。
- 时间戳:提交更改的日期和时间。
- 行号:表示文件中的位置,即进行更改的确切行。
- 内容:添加到文件中的代码。

现在你知道了blame输出中每一行的含义,让我们探索一个真实的例子。在这个例子中,你将检查是谁做出了更改、更改是何时做出的,以及添加了什么更改。
实战演示:查看具体文件的变更历史

为了演示,我将使用一个名为MK Docs的公共仓库。MK Docs有许多不同开发者的贡献,因此它是查看特定文件所有变更日志的好方法。
首先,我使用ls -l命令检查目录,以获取所有可用文件的列表,然后选择其中一个文件。我选择的文件是setup.py,这是一个Python文件。
为了检查该文件的不同更改,我运行命令git blame,然后传入文件名setup.py并按下回车。输出将列出所有不同开发者所做的所有更改,同时还会指示时间戳、行号以及实际所做的更改。
现在,我将带你解读这个输出。列表最左边是所谓的哈希ID,它代表了变更发生时的提交。接着列出了处理该文件的开发者姓名,然后是你有变更进入的时间戳。接下来是按顺序排列的行号,最后是实际实现的更改。
我可以滚动浏览更改列表,直到文件末尾,这取决于文件的大小或它有多少行。如果想退出,可以按Q键。这将清屏,使界面更简洁。
请注意,仅使用git blame并传入文件名,我们会列出整个文件。但在很多情况下,你会处理非常大的文件,这时你需要一种方法来缩写输出或根据行号进行截取。幸运的是,git blame为此提供了一个标志。
高级用法:限制输出范围与格式化
为了只查看文件的特定部分,我可以键入git blame并传入-L标志,指定起始行号和结束行号。例如:
git blame -L 5,15 setup.py
这次返回的是一个更小的子集,只从第5行开始,到第15行结束。输出显示,在这些行中,有五位不同的开发者进行了四次不同的更改。
现在让我再给你一些关于git blame的使用技巧。
首先,你可以更改列表的显示格式。这类似于在Unix命令中对ls命令所做的操作,你也可以传入-l标志来改变输出本身。让我们再次运行git blame -l,后跟文件名并按下回车。这次,输出有一些变化。例如,哈希ID现在是完整长度形式,而不是缩短版本。输出现在更加详细。你还可以控制是否显示电子邮件地址或更改日期格式。这些都是你可以做的各种事情的例子。
其次,使用git blame的另一个方面是,你可以查看特定哈希ID的详细更改或实际提交更改。为此,我将再次在该文件上运行一个git blame命令,以便从输出中复制一个哈希ID。
现在,我将把它与git log -p一起使用,并传入哈希ID,然后按下回车。这会给你实际发生的变更详情。需要澄清的是,git blame会向你显示它被更改的位置,而git log会给你更改的细节。我总是将两者结合使用,以获取有关发生了哪些更改的更多详细信息。
总结

本节课中,我们一起学习了git blame命令。我们了解了它的基本作用——追踪文件中每一行代码的修改者、修改时间和具体内容。我们通过实例演示了如何运行该命令、解读其输出格式,并探索了如何通过-L标志限制查看范围,以及如何结合git log -p命令获取更详细的提交信息。掌握git blame能让你在团队开发中更有效地进行代码审查和问题溯源。
入门 74:模块小结 使用Git 🎯
在本节课中,我们将回顾并总结整个Git模块的核心知识点。你已经学习了Git的基本原理、GitHub仓库的使用,以及如何通过Forking创建仓库。本节将对所有关键概念进行梳理和总结。
概述 📋
上一节我们介绍了Git的高级操作,本节中我们来看看整个模块的知识体系。通过本模块的学习,你掌握了从Git基础概念到实际工作流的完整技能。
核心知识回顾
以下是本模块涵盖的所有核心知识点。
Git基本原理与GitHub
你现在能够解释Git的工作原理并利用GitHub仓库,包括分支和代码合并。
Git的安装与初始化
你学会了在Windows操作系统上本地安装Git,在GitHub上创建新仓库并将其克隆到本地机器。

Git工作流基础


你掌握了Git的基础知识,并能概述Git的标准工作流程。同时,你能识别GitHub中远程仓库和本地仓库之间的区别。

提交更改

你理解了git add和git commit命令的作用,并能描述它们的工作方式。
代码示例:
git add <文件名>
git commit -m "提交信息"
远程同步

你学会了使用git push将内容推送到远程仓库,并使用git pull从远程服务器检索内容。

代码示例:
git push origin main
git pull origin main

分支管理
你能够通过使用分支来保持工作流的清晰和稳定,并解释Git中如何使用HEAD来标识你当前正在工作的分支。
概念公式:
HEAD -> 当前分支 -> 最新提交

比较与追溯
你学会了使用diff命令比较跨文件、提交和分支的更改,使用blame命令检查文件的更改并识别其作者。
代码示例:
git diff <分支1> <分支2>
git blame <文件名>
Forking创建仓库


最后,你掌握了如何使用Forking功能来创建仓库。
总结 🏁
本节课中我们一起学习了Git和GitHub的完整知识体系,包括从安装配置、基础命令、分支管理到远程协作和Forking的全过程。你现在已经熟悉了Git、GitHub以及如何使用Forking创建仓库。出色的工作。
入门 75:版本控制课程回顾 📚
在本节课中,我们将对之前学习的版本控制知识进行系统性的回顾。我们将梳理版本控制的核心概念、命令行操作以及Git技术的具体应用,帮助你巩固所学内容。
模块一:版本控制与软件开发工作流回顾
上一节我们完成了课程概述,本节中我们来看看第一个模块的核心内容。你学习了不同的版本控制系统以及高效的软件开发工作流程,这些知识使得现代软件开发者能够在全球范围内协作,而不会互相干扰对方的代码。
你了解了版本控制的历史,并掌握了版本控制(或称Subversion)如何为那些可能存在错误和漏洞的大型软件项目带来秩序,从而管理混乱。
接下来,你深入学习了软件开发者作为全球团队的一部分,为成功协作所利用的各种系统、工具和方法论。
你探索了如何在Git中解决冲突,并理解了版本控制在软件开发中扮演的关键角色。
随后,你继续研究了暂存环境与生产环境之间的区别。暂存环境应尽可能模拟你的生产环境。

模块二:Linux命令行操作回顾
在模块二中,你学习了如何使用命令行在Linux中执行命令。你被介绍了命令行的概念,并学会了使用命令来遍历、创建、重命名和删除硬盘上的文件。

然后,你了解到使用管道和重定向来创建强大的工作流是多么容易,这将自动化你的工作,为你节省时间和精力。
最后,你进一步探索了命令行,发现了标准输入、输出流、可用于改变命令行为的标志以及grep命令。
模块三:Git技术与实践回顾
在模块三中,你对Git技术及其在软件开发项目中用于管理团队文件的方式建立了坚实的理解。
首先,你学习了如何在各种操作系统上安装Git,然后在创建GitHub账户之前,如何通过HTTPS和SSH连接到GitHub。

接下来,你对Git的工作原理获得了实践性的理解,包括创建和克隆仓库、添加、提交、推送和拉取操作。你还探索了如何在某些与工作流相关的概念中使用仓库,例如分支、追溯和复刻。
以下是本模块涉及的核心Git命令示例:
git clone <repository_url> # 克隆远程仓库
git add <file> # 将文件更改添加到暂存区
git commit -m "message" # 提交暂存区的更改
git push origin main # 将本地提交推送到远程仓库
git pull origin main # 从远程仓库拉取更新

最后,未评分的实验环节提供了一个机会,让你通过复刻一个仓库、创建一个分支并提交更改来完成一个实践性的版本控制练习。该练习还包括暂存你的更改以及向源仓库发起一个拉取请求。


总结与展望 🎯
本节课中,我们一起回顾了版本控制的核心概念、Linux命令行的高效用法以及Git在团队协作中的实际应用。你已掌握了从理论到实践的关键步骤。

完成本次回顾后,是时候将你所学的一切付诸实践了。你准备好继续前进了吗?
祝你好运。
P76:29_恭喜您完成了版本控制课程 🎉
在本节课中,我们将对您完成的版本控制入门课程进行总结,回顾您已掌握的核心技能,并展望后续的学习路径。


恭喜您完成了版本控制入门课程。您付出了辛勤努力,并在此过程中掌握了许多新技能。现在,您应该对不同版本控制系统以及如何创建有效的软件开发工作流程有了坚实的基础。您还通过在GitHub上管理项目以完成分级评估,展示了自己的技能。
完成本课程后,您现在能够:
- 实施版本控制系统。
- 使用命令行导航、配置文档、文件和目录。
- 创建和管理GitHub仓库。
- 管理代码修订。
以下是实验环节中衡量的关键技能,它们展示了您的能力:
- 使用命令行确定当前工作目录,并创建和更改目录及文件。
- 创建、克隆、提交代码到仓库,以及推送代码。
- 通过复刻创建仓库,并在GitHub上管理项目。
上一节我们总结了您已获得的技能,本节中我们来看看接下来的步骤。您目前已奠定了良好的基础,但总有更多知识可以学习。
无论您是刚起步的技术专业人士还是学生,这个项目都能让您证明自己的知识和能力。您的项目经验向雇主表明,您具备自我驱动力和创新精神。这也充分说明了您作为个人的特质以及持续追求新教育进展的动力。
一旦您完成了此专业证书中的所有课程,您将获得Coursera认证。这些认证提供了全球认可且受行业认可的、掌握技术技能的证明。
再次祝贺您完成本课程。这是一段探索之旅。祝您好运,请继续朝着您的最终学习目标不懈追求。


入门 77:0_计划介绍
概述
在本节课中,我们将要学习Meta数据库工程师专业证书计划的整体介绍。该计划旨在帮助学习者从零开始,掌握成为数据库工程师所需的技能,并为进入像Meta这样的科技公司工作做好准备。
数字空间是一个充满连接与机遇的世界。以此刻为例,网络使你能够注册本课程,并向Meta的开发者们学习。当你完成这个专业证书时,你将能够成为数字体验的创造者。连接正在进化,你也是如此。你可能完全没有技术背景,这没关系。即使没有任何经验,本计划也能让你在一年内做好求职准备。
那么,这个专业证书如何为你进入像Meta这样的组织工作做好准备呢?数据库工程师专业证书将帮助你建立数据库工程师职位所需的、符合工作要求的技能,同时获得Meta颁发的证书。
上一节我们介绍了计划的总体目标,本节中我们来看看你将具体学习什么内容。
你将向Meta的工程师学习,了解他们如何协作创建和测试高性能数据库。你还将与其他有抱负的数据库工程师讨论有趣的话题,并完成一系列编码练习以提高技能。
按顺序完成证书中的所有课程非常重要,因为每门课程都将建立在你已掌握的技能之上。虽然我们为每门课程提供了建议的学习进度,但整个计划完全是自定进度的,这意味着你可以自由管理自己的时间。
以下是你在学习过程中将掌握的核心技能列表:
- 数据库建模与设计:学习如何根据最佳实践对数据库进行建模和结构化。
- SQL语言:学习使用
SQL(结构化查询语言)来创建、管理和操作数据。SQL是处理数据库最广泛使用的语言之一。 - Django Web框架:学习使用
DjangoWeb框架将Web应用程序的前端连接到你的数据库。 - 版本控制:学习使用
Git和GitHub进行版本控制,以便与其他开发者协作。
在你的最终项目中,你将创建一个功能性的关系型数据库设计,并使用最佳实践架构进行开发,以作为求职时作品集的一部分展示。
在最后一门课程中,你将准备编码面试。你将练习面试技巧,完善简历,并解决一些通常在技术职位面试中出现的常见编码挑战。
一旦你完成整个计划,你将获得访问Meta职业计划工作板的权限。这是一个求职平台,将你与超过200家承诺通过Meta证书计划招募人才的雇主联系起来。
谁知道你最终会走向何方?无论未来的连接是什么样子,你都将成为其创造的一部分。
让我们开始吧。
总结
本节课中我们一起学习了Meta数据库工程师专业证书计划的介绍。我们了解到,该计划适合零基础的学习者,通过一系列结构化的课程,你将掌握数据库设计、SQL、Django、Git等核心技能,并完成一个最终项目来构建你的作品集。完成计划后,你不仅将获得Meta的证书,还能获得专属的求职资源,为进入科技行业做好准备。
数据库工程:P78:课程介绍
在本课程中,我们将学习数据库结构与MySQL管理的核心知识。课程分为三个主要模块,涵盖数据操作、数据库更新与视图、以及函数与存储过程。通过理论学习、实践活动和项目作业,你将掌握关键的数据库工程技能。
上一段概述了课程整体内容,接下来我们详细看看每个模块的具体学习目标。
以下是你在第一个模块中将获得的新技能:
- 数据过滤:学习使用逻辑运算符(如
AND,OR,NOT)筛选数据。 - 表连接:掌握如何对多个表执行连接操作以关联数据。
- 使用别名:了解如何为表或列设置别名以简化查询。
- 数据分组:运用
GROUP BY和HAVING子句对数据进行分组和过滤。 - 高级运算符:在数据库中部署
ANY和ALL运算符进行复杂比较。
在掌握了基础的数据查询与操作后,第二个模块将引导你探索数据库的更新与视图管理。
以下是第二个模块的核心主题:
- 数据更新:学习使用
REPLACE语句插入和更新数据。 - 约束应用:在MySQL数据库中利用约束(如主键、外键)确保数据完整性。
- 结构变更:使用
ALTER TABLE和COPY TABLE语句更改和复制表结构。 - 子查询:了解如何使用子查询,并将其与比较运算符结合。
- 创建视图:使用
CREATE VIEW语句创建虚拟表,简化复杂查询。
了解了如何维护和优化数据库结构后,第三个模块将深入MySQL的高级功能。
在第三个模块中,你将探索函数与存储过程:
- 常用函数:掌握数值、字符串和日期等常见MySQL函数的使用。
- 流程控制:部署比较函数和控制流函数(如
CASE,IF)进行条件逻辑处理。 - 存储过程:学习创建和使用存储过程来封装可重用的数据库逻辑。

课程不仅包含知识讲解,还设计了多种实践环节以巩固学习效果。
在整个学习过程中,你将通过以下方式检验和提升技能:
- 知识测试:在模块中遇到测试知识与技能的活动。
- 实验项目:在实验项目中,有机会展示所学知识及实践数据库技能。
- 分级评估:通过分级评估来证明你对这些主题的掌握程度。

本节课中,我们一起了解了本数据库工程课程的整体框架、三个核心模块的学习目标(数据操作、更新与视图、函数与存储过程)以及课程包含的实践活动。现在,让我们正式开始学习。
入门 79:Meta如何使用MySQL 🗄️
在本节课中,我们将学习数据库在数字体验中的核心作用,并深入了解Meta公司为何以及如何使用MySQL这一流行的关系型数据库管理系统。我们将探讨MySQL的关键特性及其如何支撑大规模应用。

数据库存在于我们日常与数字体验的每一次互动中。无论是在智能手机上查找联系人电话、寻找下一部要播放的电影,还是在收银台扫描商品并完成支付,每一步都在与数据库交互。
我的名字是Daniel Bloomfield Ramenen,我是一名在Me DCC办公室工作的软件工程师。我的工作领域涉及安全、社区诚信,目前专注于隐私保护。

随着应用程序对数据的使用量增长,快速查找、管理、删除和更新信息的需求日益迫切。如果没有数据库管理系统,开发者就需要自行构建这些数据结构。初期或许可行,但随着业务规模扩大,难度会急剧增加。像MySQL这样的数据库管理系统几乎免费提供了这些服务与功能,使你能够专注于解决业务问题或用户问题,而无需过分担忧数据管理层的底层实现。
上一节我们介绍了数据库的普遍性,本节中我们来看看MySQL的具体定义。
MySQL是一个关系型数据库管理系统。它允许你存储数据、检索数据、管理数据,以及执行删除和更新操作。其应用范围广泛,适用于多种不同类型的应用。从机动车管理局管理驾驶记录,到Facebook应用中的点赞和分享,所有这些都可以通过数据库进行管理。MySQL是全球最流行的数据库之一。

以下是MySQL的一些核心优势:

- 自动化能力:MySQL允许你自动化许多任务,例如制作备份、设置故障转移和更新模式。
- 高并发处理:它擅长处理高并发请求,非常适合拥有大量访问量的Web应用。
- 强大社区与开源:它拥有一个活跃的社区,提供论坛、支持文档和帮助渠道。作为开源软件,你可以查看其代码,甚至向软件的创建者和贡献者提交请求。
了解了MySQL的优势后,我们来看看Meta是如何具体应用它的。


在Meta,我们使用MySQL来存储和检索社交图谱、用户互动、分享和点赞等数据。我知道,当我的朋友上周使用Facebook应用看到我的照片时,我可以想象,为了检索并展示这些信息,我们的MySQL服务器集群处理了成千上万的请求。MySQL为我们所有这些精彩的数字体验提供着动力。
我们选择MySQL,是因为它提供了自动化能力。这意味着一小群工程师就能管理庞大的服务器集群,执行备份、故障转移等操作,并将这些功能自动化。同时,它也非常擅长处理高事务性请求。Meta的许多业务都涉及短时间内大量精确的数据插入、删除和查询请求,而MySQL在这方面表现出色。
学习数据库知识非常有价值,它可能充满挑战,不仅涉及编码,还包括数据库管理、配置和数据结构的学习。但回报是,你将有能力构建令人惊叹的体验,为真实的用户问题提供出色的解决方案。你可以开发服务于娱乐等领域的应用程序。所有软件的各种用途,都将由组织良好、结构化的数据来驱动。坚持下去,完成本课程的学习,因为你将站在巨人的肩膀上,这些现成的数据层技术将为你所用,并推动你迈向新的高度。
本节课中我们一起学习了数据是每个应用的核心,有效地组织和管-理-数据至关重要。掌握数据库管理知识不仅能帮助你构建数据结构,还将影响后续的数据处理、API乃至用户界面。通过你的数据库管理和数据技能,你将拥有巨大的机会去影响从后端到前端体验的整个软件开发项目。希望你未来有机会应用这些知识,并祝愿你在接下来的努力中取得最佳成绩。
入门 80:使用AND、OR和NOT逻辑运算符过滤数据 🔍
在本节课中,我们将学习如何在SQL的WHERE子句中使用逻辑运算符(AND、OR、NOT)来组合多个条件,从而对数据库表中的数据进行更精确的筛选。掌握这些运算符是构建复杂查询的基础。
回顾WHERE子句
在探索如何使用多个条件过滤数据之前,我们先简要回顾一下WHERE子句的工作原理。理解这一点对于使用逻辑运算符至关重要。
当需要过滤数据库表中的数据时,可以在SQL的SELECT语句中添加WHERE子句,以指定数据应如何被筛选的条件或规则。
一个基本的SELECT语句结构如下:
SELECT column1, column2, ...
FROM table_name
WHERE condition;
它从SELECT关键字开始,指定要查询的列,使用FROM关键字指定要查询的表,最后通过WHERE子句添加过滤条件。
然而,正如你将学到的,也可以在WHERE子句中指定多个条件,这些条件需要使用逻辑运算符来组合。
理解AND和OR运算符
本节中,我们来看看AND和OR这两个核心逻辑运算符。AND运算符与WHERE子句一起使用,用于检查所有组合条件是否都满足“真”值。而OR运算符则检查组合条件中是否有任何一个满足“真”值。
让我们分别探讨一下这两个逻辑运算符的语法。
使用AND运算符
AND运算符用于组合多个条件,要求所有条件同时为真,记录才会被包含在结果集中。
其基本语法结构为:
SELECT column1, column2, ...
FROM table_name
WHERE condition1 AND condition2 AND condition3 ...;
SQL语句会检查记录是否满足所有这些条件。如果满足,则该记录被包含在结果集中。
使用OR运算符
OR运算符也用于组合多个条件,但只要其中任何一个条件为真,记录就会被包含在结果集中。
其基本语法结构为:
SELECT column1, column2, ...
FROM table_name
WHERE condition1 OR condition2 OR condition3 ...;
这意味着,如果表中某条记录至少满足一个条件,它就会被包含在查询结果集中。

探索NOT运算符
上一节我们介绍了AND和OR,本节中我们来看看NOT逻辑运算符。NOT运算符的工作方式与其他运算符略有不同,它只选择那些不满足WHERE子句中指定条件的记录。
换句话说,它对条件评估后的结果进行反转或否定。
要使用NOT运算符,只需在WHERE子句后键入NOT,然后跟上所需的条件。
其基本语法结构为:
SELECT column1, column2, ...
FROM table_name
WHERE NOT condition;
实践案例:Lucy’s Shrubbery的客户数据分析
现在,让我们花几分钟时间,通过Lucy’s Shrubbery的案例来了解这些运算符的实际应用。Lucy’s Shrubbery正在审查其账户,需要生成关于客户及其购买记录的特定详细信息。
他们可以通过使用逻辑运算符过滤数据来完成此任务。
在Lucy’s Shrubbery的数据库中,有一个名为CustomerPurchases的表,该表包含了完成查询所需的数据。数据分为以下四列:CustomerID、CustomerName、Location和Purchases。
任务一:使用AND组合条件
Lucy’s Shrubbery首先需要识别出来自“Hela County”地区且购买金额超过$2,000的客户。这需要两个搜索条件。
以下是完成此查询的步骤:
- 编写基本的
SELECT语句框架。 - 在
WHERE子句中添加第一个条件:Purchases > 2000。 - 使用
AND运算符连接第二个条件:Location = ‘Hela County’。
完整的SQL语句如下:
SELECT *
FROM CustomerPurchases
WHERE Purchases > 2000 AND Location = ‘Hela County’;
AND运算符在这里组合了两个条件,确保在过滤表数据时同时评估这两个条件。只有当一条记录的Purchases列值大于2000并且Location列值为“Hela County”时,它才会被包含在结果中。
执行此查询后,结果集包含两条记录,即Benjamin Claus和Julie Mur。
任务二:使用OR组合条件
接下来,Lucy’s Shrubbery需要识别出来自“Hela County”或“Santa Cruz County”的客户。OR逻辑运算符非常适合此任务。
以下是完成此查询的步骤:
- 编写
SELECT语句。 - 在
WHERE子句中添加第一个条件:Location = ‘Hela County’。 - 使用
OR运算符连接第二个条件:Location = ‘Santa Cruz County’。
完整的SQL语句如下:
SELECT *
FROM CustomerPurchases
WHERE Location = ‘Hela County’ OR Location = ‘Santa Cruz County’;
OR运算符确保只要记录满足至少一个条件(位于Hela County或Santa Cruz County),就会被包含在结果中。
执行此查询后,结果返回三条记录。
任务三:使用NOT排除条件
最后,Lucy’s Shrubbery需要检索不居住在“Hela County”或“Santa Cruz County”的客户的详细信息。他们可以使用NOT逻辑运算符来执行此任务。
其写法与之前类似,但在WHERE子句后键入NOT,然后列出条件。由于有多个条件,需要用括号将它们括起来。
完整的SQL语句如下:
SELECT *
FROM CustomerPurchases
WHERE NOT (Location = ‘Hela County’ OR Location = ‘Santa Cruz County’);
NOT运算符检查记录,找出那些对给定条件(位于所列任一位置)不产生“真”值的记录。换句话说,就是找出不在“Hela County”或“Santa Cruz County”的记录。
执行此查询后,输出显示了CustomerPurchases表中的四条记录。

总结
本节课中,我们一起学习了SQL中三个核心的逻辑运算符:AND、OR和NOT。
AND要求所有条件同时为真。OR要求至少一个条件为真。NOT用于否定一个条件,选择不满足该条件的记录。
通过Lucy’s Shrubbery的实践案例,我们看到了如何将这些运算符应用于WHERE子句中来构建更具体、更强大的数据查询。理解并熟练运用这些运算符,是进行有效数据筛选和分析的关键一步。如果觉得这些例子有点复杂,请不要担心,在本课程的后续视频中将会回顾如何使用这些运算符的详细示例。目前,你只需要能够识别每个运算符并解释其基本语法即可。
入门 81:使用IN、BETWEEN和LIKE逻辑运算符过滤数据 🎯
在本节课中,我们将学习如何使用IN、BETWEEN和LIKE这三个逻辑运算符来执行更复杂的数据过滤任务。这些运算符能帮助我们基于多个值、特定范围或特定模式来筛选数据,是数据库查询中不可或缺的工具。
逻辑运算符概述
上一节我们介绍了基础的AND和OR运算符。本节中,我们来看看IN、BETWEEN和LIKE运算符,它们能处理更具体的过滤需求。
IN运算符允许在WHERE子句中指定多个值。
BETWEEN运算符选择给定范围内的值。
LIKE运算符用于基于模式匹配来过滤数据。
IN运算符详解
IN运算符的语法与典型的SELECT过滤语句略有不同。在WHERE子句后,必须键入应用IN运算符的列名,然后添加IN运算符及括号内的值集合。
语法示例:
SELECT * FROM table_name
WHERE column_name IN (value1, value2, ...);
如果某条记录的指定列值与集合中的任意值匹配,则该记录将包含在查询结果集中。IN运算符就像是多个OR条件的简写形式。你也可以使用NOT IN来获取与IN运算符相反的结果。
BETWEEN运算符详解
BETWEEN运算符也需要在WHERE子句后指定列名,然后应用BETWEEN运算符及两个必需的边界值。这两个值定义了范围的起始和结束。
语法示例:
SELECT * FROM table_name
WHERE column_name BETWEEN value1 AND value2;
该运算符选择此给定范围内的值,适用的值类型包括数字、文本和日期。如果记录的指定列值落在指定的值范围内,则该记录将包含在查询结果集中。
LIKE运算符与通配符

LIKE运算符用于基于模式匹配过滤数据。该运算符放在WHERE子句和指定列名之后,然后添加要与列数据匹配的模式。此模式可以使用通配符编写。
以下是两种主要的通配符:
- 百分号(%):代表零个、一个或多个字符。
- 下划线(_):代表一个单个字符。
模式示例:
例如,模式 'G__%' 表示搜索以字母G开头且长度至少为三个字符的值。每个下划线代表一个字符,而百分号代表零个或多个字符。
语法示例:
SELECT * FROM table_name
WHERE column_name LIKE 'pattern';
如果记录的指定列值与给定模式匹配,则该记录将包含在查询结果集中。
实战演示:Lucy Shrub数据库
假设Lucy Shrub公司正在审查其账户,需要生成关于客户及其购买记录的特定详细信息。他们可以通过使用IN、BETWEEN和LIKE逻辑运算符过滤数据来完成此任务。
数据库中存在一个名为customer_purchases的表,包含以下列:customer_id、customer_name、customer_location、purchases(每位客户的单次购买金额)。
使用IN运算符
Lucy Shrub需要找出位于“Hela County”或“Santa Cruz County”且购买金额超过2000的客户。使用IN运算符可以简化多个OR条件。
查询语句:
SELECT * FROM customer_purchases
WHERE purchases > 2000 AND customer_location IN ('Hela County', 'Santa Cruz County');
执行此查询将返回三条记录,与使用多个OR运算符的结果相同。
使用BETWEEN运算符
接下来,Lucy Shrub需要购买金额在1000到2000之间(包含边界值)的客户详情。
查询语句:
SELECT * FROM customer_purchases
WHERE purchases BETWEEN 1000 AND 2000;
BETWEEN运算符是筛选购买值大于等于1000且小于等于2000的记录的一种更快捷、更简便的方法。
使用LIKE运算符
最后,Lucy Shrub需要查找customer_location列中,以字母G开头且长度至少为三个字符的所有值。这需要使用LIKE运算符配合通配符。
查询语句:
SELECT * FROM customer_purchases
WHERE customer_location LIKE 'G__%';
执行此查询后,输出结果将包含三个以G开头且长度至少为三个字符的值。所有不匹配该模式的值都已从结果表中省略。

总结
本节课中,我们一起学习了如何使用IN、BETWEEN和LIKE逻辑运算符来组合条件并过滤数据。IN运算符简化了多值匹配,BETWEEN运算符方便了范围查询,而LIKE运算符结合通配符则实现了灵活的模式匹配。掌握这些运算符能显著提升你从数据库中提取特定信息的能力。
入门 82:MySQL别名 🏷️
在本节课中,我们将要学习MySQL中别名的概念及其应用。别名可以为数据库中的表和列提供临时名称,使查询结果更易于使用、阅读和理解。我们将通过具体示例,学习在三种常见场景下如何使用别名。
概述
Little Lemon餐厅的数据库遇到了一些问题。部分表和列的名称过长,导致查询输出难以处理。他们需要找到一种方法来生成更简单、易读的结果。幸运的是,他们可以通过使用MySQL别名来解决这些问题。
接下来,我们将了解Little Lemon如何利用MySQL别名。通过本视频的学习,你将能够:理解数据库中别名的概念;识别使用别名有益的场景;并在MySQL查询中演示别名的使用。
什么是SQL别名?
SQL别名用于为数据库的列和表提供临时名称。这些临时名称使数据库的输出更易于使用、阅读和理解。例如,Little Lemon可以使用别名来缩短其数据库中表和列的名称。
有三种常见情况适合使用别名:
- 重命名原始名称过长或过于技术化的表或列。
- 与连接函数结合使用,将输出合并为一列而非两列。
- 在处理多个表时,创建不同的表名。
然而,需要注意的是,创建和使用别名的语法会根据你试图解决的问题类型而有所不同。
别名语法详解
上一节我们介绍了别名的概念,本节中我们来看看在不同场景下的具体语法。
重命名表或列
以下是重命名表或列的语法步骤:
- 使用以
SELECT关键字开头的SELECT语句。 - 输入原始列名,后跟别名。
- 两者必须用
AS关键字分隔,AS关键字用于创建别名。 - 你还可以包含表中的其他列,每列之间用逗号分隔。
- 然后写入
FROM关键字,后跟表名。
如果你的表需要多个别名,则写出每个列名,并为每个需要创建别名的列使用 AS 关键字。
例如,在客户订单表中,Little Lemon可以使用别名将冗长的列名(如 client_order_information)重命名为 orders。
使用连接函数合并列
接下来,我们回顾一下使用连接函数将输出合并为一列的语法。
以下是使用连接函数和别名的语法步骤:
- 使用
SELECT命令检索数据。 - 后跟
CONCAT函数,该函数连接或组合从括号内列名中提取的信息。 - 这些名称必须用逗号和一对双引号分隔。双引号通过在连接的值之间创建空格来分隔输出。
- 然后添加
AS关键字,后跟要分配给新连接列的名称或别名。 FROM关键字指定SQL必须从中提取数据的表。
Little Lemon可以使用连接函数来合并其客户详细信息表中 first_name 和 last_name 列包含的值。这些值随后被放入一个名为 client_names 的新连接列中。
查询多个表
最后,让我们探讨查询多个表的语法。
查询多个表时,首先要注意的是,你可以使用一个字符的别名来代表每个表。例如,如果你要查询两个不同的表,则可以使用 X 代表表1,Y 代表表2。
以下是查询多个表并使用别名的语法步骤:
- 语法以
SELECT命令开始,后跟要查询的表和列。 - 你可以使用点符号查询列。例如
x.column1查询表1的列1,或y.column2查询表2的列2。 - 接下来添加
FROM关键字,然后键入每个表的原始名称及其别名,两者用AS关键字分隔。 - 最后,根据需要添加
WHERE子句和条件。
例如,假设你正在查询在线商店数据库中的价格,并希望返回表1中价格低于12美元且表2中价格低于5美元的商品列表。

以上是MySQL别名可以使用的三种主要情况及其相关语法。
实践应用
现在你已经熟悉了MySQL别名的概念,让我们看看能否帮助Little Lemon解决他们的数据库问题。
Little Lemon餐厅的数据库中有一个名为 FoodOrdersDeliveryStatus 的表,用于跟踪食品订单。该表有两个列,分别叫做 DateFoodOrderPlacedWithSupplier 和 DateFoodOrderReceivedFromSupplier。然而,这些列名太长且复杂,需要简化以提高数据库效率。
你可以使用别名来简化输出,使查询时的列名更易于阅读和理解。
以下是简化列名的操作步骤:
- 以
SELECT语句开始,并指定OrderID列。 - 将
DateFoodOrderPlacedWithSupplier列重命名为DateOrderPlaced。 - 将
DateFoodOrderReceivedFromSupplier列重命名为Date Order Received。
请注意,Date Order Received 使用了双引号,因为别名名称包含空格。在其他情况下,你可以不使用引号来声明别名。
- 最后,键入
FROM关键字,后跟表名,然后点击执行查询。
输出现在显示的是别名,而不是原始列名,这使得Little Lemon跟踪食品订单变得容易得多。
然而,你可以让这个表更高效。例如,你可以将 OrderID 和 OrderStatus 连接成一列,而不是两列。
正如之前所学,你可以将SQL别名与函数一起使用。按如下方式编写语句:
以下是连接列并创建别名的操作步骤:
- 以
SELECT命令开始,然后是CONCAT函数。 - 将要连接的列放在一对括号内。
- 还应确保包含引号以分隔输出。
- 接下来,使用
AS关键字创建别名。在本例中,可以将别名列称为OrderStatus。 - 然后使用
FROM关键字来标识表。 - 最后,点击执行查询。
输出显示了新的 OrderStatus 列及其连接的信息。
最后,让我们回顾一下如何处理数据库中的多个表。
餐厅将其菜单分为两个表,分别称为 Starters 和 MainCourses。这两个表都显示了可供订购的餐点名称及其各自的成本。作为新促销活动的一部分,Little Lemon希望推广价格不超过7美元的开胃菜和价格不超过15美元的主菜,因此你需要查询这些表并找出符合这些价格的餐点。
在这种情况下,你可以使用一个字符的别名 S 来代表 Starters,使用 C 来代表 MainCourses。
以下是查询多表并使用别名的操作步骤:
- 将这些别名添加到
SELECT语句中,并使用点符号来请求餐点的名称和成本。 - 然后使用
FROM关键字来标识表,并使用AS关键字为每个表创建别名(MainCourses是C,Starters是S)。 - 最后,添加一个
WHERE子句并指定条件。该条件返回所有价格低于7美元的开胃菜和所有价格低于15美元的主菜。 - 最后,按Enter键执行查询。
SQL生成的输出在一个表中显示了所有相关的成本。

总结
本节课中我们一起学习了如何使用MySQL别名解决Little Lemon数据库的所有问题。在你的帮助下,Little Lemon的数据库现在使用起来更加高效,并且他们为下一次促销活动确定了一些很棒的餐点。
通过完成这些任务所获得的技能,你现在应该能够:理解数据库中别名的概念;识别使用别名有益的场景;并在MySQL查询中演示别名的使用。做得好!😊
入门 83:联接 🧩
在本节课中,我们将要学习SQL中一个核心且强大的功能——联接(JOIN)。我们将了解联接的概念、主要类型及其基本语法,帮助你理解如何从多个数据库表中组合和提取数据。
概述
Lucy Shrub园艺中心需要收集关于其客户及其所下订单的信息,但这些记录分别存储在三个不同的表中。他们可以通过使用联接(JOIN) 子句,将这些表中所需的元素连接起来,从而提取出所需信息。
接下来,我们将探讨联接子句的工作原理。通过本视频的学习,你将能够:
- 理解数据库中联接的概念。
- 描述MySQL中主要的联接类型。

理解联接的概念

在开始帮助Lucy Shrub之前,我们首先需要理解联接的概念。

SQL的联接子句用于基于两个目标表之间的公共列来查询数据。

例如,customers(客户)表和orders(订单)表都包含一个customer_id(客户ID)列。同样,product_id(产品ID)列是orders(订单)表和products(产品)表之间的公共列。
这些公共列可以用来将这些表连接在一起,并提取所需的记录。
联接的主要类型


以下是用于组合表的四种主要联接类型:
- 内联接(INNER JOIN):提取或选择两个表中具有匹配值的记录。
- 左联接(LEFT JOIN):提取或选择左表中的所有记录,以及右表中的所有匹配记录。
- 右联接(RIGHT JOIN):提取或选择右表中的所有记录,以及左表中的所有匹配记录。
- 自联接(SELF JOIN):表与自身连接,以检索存在于同一表中的信息。


上一节我们介绍了联接的基本概念和主要类型,本节中我们来看看每种联接的具体细节。

内联接详解
内联接返回在左表和右表中都具有匹配值(或列)的数据记录。

两个表之间的关系可以用维恩图来概念化表示,所有其他联接类型也是如此。在语法上,左表和右表分别被标识为table1和table2。
Lucy Shrub需要识别所有在该公司下过订单的客户的全名。要完成此查询,他们需要clients(客户)表和orders(订单)表。然后,他们可以使用两个表中都存在的client_id(客户ID)列来创建内联接。

输出结果显示了所有下过订单的客户的记录,client_id代表了所有具有匹配ID的记录。

以下是内联接的基本语法结构:
SELECT table1.column1, table2.column2...
FROM table1
INNER JOIN table2
ON table1.matching_column = table2.matching_column;
SELECT语句查询左表和具有匹配值的列。FROM关键字后跟左表的名称。INNER JOIN子句后跟右表的名称。ON关键字用于标识两个表共享的联接条件。

左联接详解
接下来,让我们继续学习左联接。左联接以与内联接类似的方式返回所有匹配的记录。此外,它还返回左表公共列的所有可用记录,即使右表中没有匹配项。

Lucy Shrub可以使用左联接,基于client_id值从clients和orders表中提取数据。联接会定位两个表之间的四个匹配记录,并将它们放在维恩图的公共区域。
以下是左联接的基本语法结构:

SELECT t1.column1 AS alias1, t2.column2 AS alias2...
FROM table1 AS t1
LEFT JOIN table2 AS t2
ON t1.matching_column = t2.matching_column;
SELECT语句标识table1中所需的列。AS关键字用于为每个列创建别名。FROM关键字用于标识需要查询的左表,并再次使用AS为其创建别名。LEFT JOIN子句用于联接table2并分配别名。ON关键字用于关联两个表之间的匹配列。
右联接详解

现在,让我们回顾一个右联接的例子。右联接返回右表和左表中的所有记录,但以右表为主要目标表。

例如,Lucy Shrub可以使用右联接,基于product_id值从orders和products表中提取数据记录。这将列出products表中的所有产品,并与左表中匹配的相关订单详情连接起来。
右联接的语法与左联接非常相似,唯一的区别是使用RIGHT JOIN子句来提取数据记录。
SELECT t1.column1, t2.column2...
FROM table1 AS t1
RIGHT JOIN table2 AS t2
ON t1.matching_column = t2.matching_column;


自联接详解
最后是自联接。自联接是一种特殊情况,即一个表必须与自身进行联接。换句话说,将一个表视为两个表,以便从左联接、右联接或内联接中提取特定信息。
以Lucy Shrub为例,该公司将所有员工的记录保存在一个staff(员工)表中。该表包含销售层员工和直线经理的记录。Lucy Shrub可以将该表视为两个表,以确定谁是直线经理,谁是销售层员工。
自联接的语法写成一个SELECT语句,其中为table2中的公共列创建别名。

SELECT a.column1, b.column2...
FROM table_name AS a, table_name AS b
WHERE a.matching_column = b.matching_column;

总结
本节课中我们一起学习了SQL联接的核心知识。我们首先了解了联接的概念,即通过公共列连接多个表以查询数据。接着,我们详细探讨了四种主要的联接类型:内联接(INNER JOIN)、左联接(LEFT JOIN)、右联接(RIGHT JOIN) 和自联接(SELF JOIN),并分别介绍了它们的作用和基本语法结构。
本视频包含大量信息,特别是在语法方面。如果现阶段你还没有完全理解,请不要担心。在后续的视频中,你将更详细地学习如何创建每种类型的联接。目前,你应该能够理解数据库中的联接概念,并描述MySQL中的主要联接类型了。
入门 84:内连接 🧩
在本节课中,我们将学习如何使用SQL的INNER JOIN子句,从两个相关联的表中查询匹配的数据。我们还将学习如何使用别名(Alias)为查询结果的列创建更易读的临时名称。
概述
Ly Shrub园艺中心需要查看其客户最近订单的信息。这些信息分别存储在clients(客户)表和orders(订单)表中。为了高效地查看信息,避免同时操作两个表,我们可以使用INNER JOIN。通过本课学习,你将能够应用INNER JOIN概念,并使用SQL别名。

表结构回顾
上一节我们了解了数据库规范化的概念,相关数据通常存储在不同的表中。本节中,我们先来回顾一下涉及的两个表。
clients表包含以下四列:
client_idfull_namecontact_numberaddress
orders表包含以下五列:
order_idclient_idproduct_idquantitycost
使用INNER JOIN查询数据
我们的第一个任务是找出所有下过订单的客户的完整姓名。这可以通过在SQL SELECT语句中使用INNER JOIN子句来实现。
以下是实现此查询的SQL语句:

SELECT clients.full_name
FROM clients
INNER JOIN orders ON clients.client_id = orders.client_id;
代码解析:
SELECT clients.full_name: 指定要从clients表的full_name列查询数据。FROM clients: 指定主查询表为clients表。INNER JOIN orders: 表示要将orders表与clients表进行内连接。ON clients.client_id = orders.client_id: 这是连接条件。它指定只有当clients表中的client_id与orders表中的client_id值相等时,两条记录才会被连接并返回。

重要提示: 当SQL语句涉及多个表时,必须使用表名.列名的格式来明确指定列所属的表。这在列名(例如client_id)同时出现在多个被查询表中时尤为重要。
执行上述查询后,结果集将列出所有下过订单的客户的完整姓名。
使用别名优化查询结果
上一节我们查询了客户姓名。本节中我们来看看如何查询更多信息,并使用别名让结果更易读。
我们可以从两个表中查询更多列,并使用AS关键字为列创建临时的、更友好的标签。
以下是查询客户ID、姓名、联系方式以及订单产品、数量和总成本的示例语句:

SELECT
clients.client_id AS ‘客户ID‘,
clients.full_name AS ‘姓名‘,
clients.contact_number AS ‘联系方式‘,
orders.product_id AS ‘产品ID‘,
orders.quantity AS ‘数量‘,
orders.cost AS ‘订单金额‘
FROM clients
INNER JOIN orders ON clients.client_id = orders.client_id;
代码解析:
- 在
SELECT子句中,为每个列使用了AS ‘新名称‘的语法来创建别名。 - 例如,
clients.client_id AS ‘客户ID‘表示查询clients.client_id列,但在结果集中该列的标题显示为“客户ID”。
执行此查询后,将得到一个包含所有相关数据的表格,清晰地显示了客户C1、C2、C3和C4的订单信息。
总结

本节课中我们一起学习了如何在MySQL中使用INNER JOIN子句从数据库的两个表中查询匹配的数据。我们还学习了如何使用别名(Alias)为查询结果的列创建临时的、更易读的标签。现在,Ly Shrub园艺中心可以借助INNER JOIN子句,通过一个更高效的表格来查看所需数据。
入门 85:左连接与右连接 🧭
在本节课中,我们将学习如何在MySQL中使用LEFT JOIN和RIGHT JOIN子句,从多个相关联的表中查询数据。我们还将学习如何使用别名来简化查询语句。
概述
Lucky Shrub公司需要审查其客户的订单数据。这些数据分别存储在clients(客户)表和orders(订单)表中。由于两个表共享client_id(客户ID)这一关键列,我们可以使用LEFT JOIN和RIGHT JOIN子句将它们连接起来进行查询。通过本课学习,你将能够演示如何应用左连接和右连接,并利用别名创建临时的列名和表名。

在开始编写查询之前,我们先快速回顾一下这两个表的结构。
数据表结构
clients表包含以下四列:
client_id:客户IDfull_name:客户全名contact_number:联系电话address:地址
orders表包含以下五列:
order_id:订单IDclient_id:客户IDproduct_id:产品IDquantity:数量cost:成本
使用左连接(LEFT JOIN)
我们的第一个任务是创建一个查询,从clients表(左表)中获取client_id和full_name列,并从orders表(右表)中连接order_id、quantity和cost列。我们将使用LEFT JOIN子句来完成。
以下是构建查询的步骤:
首先,使用SELECT命令选择数据,并指定来自clients表的列。当在同一个语句中处理多个表时,使用点号.来指定列所属的表名非常重要,尤其是在列名(如client_id)在多个表中都存在的情况下。
SELECT clients.client_id, clients.full_name
接着,我们需要连接来自orders表的列。我们可以使用AS关键字为列名和表名创建别名,以使查询更简洁,输出结果更易读。
SELECT
c.client_id,
c.full_name,
o.order_id,
o.quantity,
o.cost
FROM clients AS c
LEFT JOIN orders AS o ON c.client_id = o.client_id;
在上面的语句中:
clients AS c为clients表创建了别名c。orders AS o为orders表创建了别名o。LEFT JOIN子句会为左表(clients)中的每一行记录创建数据,即使在右表(orders)中没有匹配的记录。对于没有订单的客户(例如ID为C5和C6的客户),右表相关列的值将显示为NULL。
执行此查询后,输出结果表中,ID为C5和C6的客户对应的订单信息列将显示为NULL值,因为他们尚未下任何订单。
使用右连接(RIGHT JOIN)

接下来,我们使用RIGHT JOIN概念创建一个类似的查询。其语法与左连接相似,只需将LEFT关键字替换为RIGHT关键字。
在这个语句中,clients表是左表,orders表是右表。RIGHT JOIN子句会根据client_id值从两个表中提取数据。
SELECT
c.client_id,
c.full_name,
o.order_id,
o.quantity,
o.cost
FROM clients AS c
RIGHT JOIN orders AS o ON c.client_id = o.client_id;
执行此查询将返回右表(orders)中所有的请求信息,并根据共同的client_id列连接左表(clients)中的匹配信息。
输出结果显示,右连接返回了所有来自右表(orders)且客户已下订单的记录,并根据client_id值提取了左表(clients)中的匹配记录。输出结果表中没有打印NULL值,因为所有下过订单的客户都已存在于clients表中。
总结
本节课中,我们一起学习了MySQL中的LEFT JOIN和RIGHT JOIN操作。
LEFT JOIN会返回左表的所有记录,以及右表中匹配的记录。如果右表无匹配,则结果中右表的部分为NULL。RIGHT JOIN会返回右表的所有记录,以及左表中匹配的记录。如果左表无匹配,则结果中左表的部分为NULL。- 我们使用了
AS关键字 为表和列创建别名,这简化了查询语句并提高了可读性。 - 在连接查询中,使用表名.列名(或别名.列名)的格式来明确指定列所属的表是至关重要的,可以避免歧义。

现在,Lucky Shrub公司已经获得了他们所需的订单和客户信息。你也能在MySQL中演示如何应用左连接和右连接,并利用别名了。
入门 86:自连接

在本节课中,我们将学习SQL中一个特殊的连接类型——自连接。我们将了解如何通过自连接,从同一张表中提取出具有层级关系的数据,例如员工与其直属经理的对应关系。
概述
Lucy Shrub公司的数据库中有一个名为Employees的表,它记录了公司所有员工的信息。其中一些员工是直线经理,而其他员工则向这些经理汇报。我们将使用自连接来查询这张表,以确定每位员工的角色及其对应的经理。

回顾员工表结构

在开始编写查询之前,我们先来了解一下Employees表的结构。这张表包含以下五列:
EmployeeID:员工ID,是表的主键。FullName:员工的全名。JobTitle:员工的职位。County:员工所在的郡。LineManagerID:该员工的直线经理的ID。
在这个表中,主键EmployeeID的值也出现在LineManagerID列中,用于表示每位员工的汇报关系。我们的主要任务是列出所有直线经理的全名,以及他们各自管理的员工的全名。
理解自连接的概念
上一节我们介绍了表的结构,本节中我们来看看如何解决这个查询问题。由于经理和员工的信息都存储在同一个FullName列中,我们需要一种方法将表“一分为二”地进行比较。
自连接就是一种特殊的连接操作,它允许我们将同一张表视为两个独立的表进行连接。为了实现这一点,我们必须为同一个表创建两个不同的别名,以便在查询中区分它们。
编写自连接查询
理解了自连接的核心思想后,现在我们来编写具体的SQL查询语句。以下是实现步骤:
- 使用
SELECT语句开始查询。 - 使用
AS关键字为Employees表创建两个别名,例如E1和E2。这相当于在查询中创建了两个逻辑上的表。 - 从别名
E1中选择FullName列,并使用AS关键字将其重命名为Line Manager。 - 从别名
E2中选择FullName列,并使用AS关键字将其重命名为Employee。 - 使用
FROM子句指定表来源,即Employees AS E1。 - 使用
INNER JOIN将E1与Employees AS E2连接起来。 - 在
ON子句中指定连接条件:E1.EmployeeID = E2.LineManagerID。这个条件意味着,我们将E1表中的员工ID与E2表中的经理ID进行匹配,从而找出谁是经理,谁是其下属。
完整的查询代码如下:
SELECT
E1.FullName AS `Line Manager`,
E2.FullName AS Employee
FROM
Employees AS E1
INNER JOIN
Employees AS E2
ON
E1.EmployeeID = E2.LineManagerID;
执行此查询后,数据库会检查E2.LineManagerID中的每一个值,并在E1.EmployeeID中寻找匹配项。如果找到匹配(条件为真),则返回E1表中的经理姓名和E2表中的员工姓名。
解读查询结果
运行上述查询后,我们将得到一个结果集。这个结果集清晰地展示了员工与经理之间的汇报关系。

例如,输出结果可能显示:
- 员工Seamus和Greta向经理Simon汇报。
- Simon的经理ID指向他自己(这可能表示他是最高级经理或此字段用于特定标识)。
- 其他所有员工都向Seamus汇报。
通过自连接查询,Lucy Shrub公司成功地理清了组织内部的角色和汇报结构。
总结

本节课中我们一起学习了SQL中的自连接操作。我们了解到,自连接通过为同一张表创建两个别名,使其能够与自己进行连接,非常适合查询存储在同一个表中的层级关系数据(如员工-经理关系)。关键步骤包括使用AS关键字创建别名,以及通过ON子句精确地定义两个别名实例之间的关联条件。掌握自连接将极大地增强你处理复杂数据关系的能力。
入门 87:MySQL UNION运算符 🧩
在本节课中,我们将要学习MySQL中的UNION运算符。UNION运算符用于将多个SELECT语句的结果集合并成一个单一的结果集。这对于从不同表中汇总数据非常有用。
概述
假设Lucky Shrub公司需要整理过去12个月雇佣的所有员工信息,以便进行年终税务申报。公司既有全职员工,也有为应对假期旺季而雇佣的兼职员工。然而,全职员工和兼职员工的记录分别存储在两个不同的数据库表中。为了解决这个问题,我们可以使用MySQL的UNION运算符来合并这两个表的数据。
UNION运算符的定义与语法
上一节我们介绍了使用UNION的背景,本节中我们来看看UNION运算符的具体定义和工作原理。
UNION运算符用于在同一个查询中合并来自多个语句的结果集。例如,你可以使用UNION运算符连接两个SELECT语句,将它们的结果集合并并呈现为一个表。
其基本语法结构如下:
SELECT column1, column2, ...
FROM table1
UNION
SELECT column1, column2, ...
FROM table2;
你首先编写一个SELECT语句,指定要查询的列名,并使用FROM关键字定位记录所在的表。接着,添加UNION运算符,然后编写第二个SELECT语句,从第二个表中查询所需的记录。UNION运算符本质上是在两个SELECT语句之间创建了一个联合。
使用UNION的最佳实践
在使用UNION运算符编写SQLSELECT语句时,必须遵循一些最佳实践以确保查询成功执行。
以下是使用UNION时必须遵守的关键规则:
- 每个
SELECT语句必须拥有相同数量的列。 - 所有对应的列必须具有相似的数据类型。
- 所有对应的列在每个
SELECT语句中必须遵循相同的顺序。
处理重复值:UNION与UNION ALL
但是,如果同一个值(例如一个姓名或地点)同时存在于两个表中,在合并后的结果集中却只出现一次,该怎么办?这是因为UNION运算符默认只从目标表中返回不重复的值。
为了列出所有值,包括重复的数据,你可以使用ALL关键字。在UNION运算符后使用ALL关键字可以确保保留所有值,即使是重复的。
SELECT column1, column2, ...
FROM table1
UNION ALL
SELECT column1, column2, ...
FROM table2;

实战示例:合并员工数据
现在,让我们通过一个实际例子来探索UNION运算符的用法。正如之前所见,Lucky Shrub需要合并两个表中的记录。

全职员工表和兼职员工表都包含相同的四列:EmployeeID、FullName、ContactNumber和Location。Lucky Shrub需要查询所有员工的姓名和地址(或所在地)。
为了合并两个表的结果,你可以编写两个SELECT语句,分别针对FullName和Location列。一个语句针对full_time_employees表,另一个针对part_time_employees表,并在两个语句之间放置UNION运算符以合并结果。
在执行这些语句之前,你必须检查每个SELECT语句是否包含相同数量的列。此外,所有列必须包含相同的数据类型,并且在两个语句中必须以相同的顺序放置。
执行查询后,输出将两个SELECT查询的结果放入一个包含两列(FullName和Location)的表中。这些列包含了Lucky Shrub所有兼职和全职员工所需的全部记录。
然而,Lucky Shrub有两名都叫“Julia Mar”的员工,一名兼职,一名全职,但在合并的结果集中只出现了一个“Julia Mar”。这是因为UNION运算符默认只返回不重复的值,它将两个“Julia Mar”实例视为重复值。
幸运的是,你可以使用UNION ALL运算符来生成包含两名员工的输出。只需再次编写相同的SELECT语句,并在UNION后加上ALL关键字。正如之前所学,ALL关键字确保输出保留两个表中的所有结果,即使它们是重复值。

执行查询后,屏幕上生成的输出就包含了两个“Julia Mar”的实例。

总结
本节课中我们一起学习了MySQL的UNION运算符。多亏了UNION运算符,Lucky Shrub现在获得了他们需要的所有信息。通过帮助他们的过程,你现在应该能够理解UNION运算符,并解释如何在MySQL中使用它来合并多个查询的结果集,无论是需要去重(UNION)还是保留所有记录(UNION ALL)。
入门 88:MySQL GROUP BY 子句 🗂️
在本节课中,我们将学习如何使用 MySQL 的 GROUP BY 子句。我们将了解如何将具有相似值的记录分组,以便分析数据并生成汇总报告。课程将涵盖 GROUP BY 的基本语法及其与聚合函数的结合使用。
概述
GROUP BY 子句是 SQL 语法中用于根据指定列将表中的行分组为汇总行(也称为子组)的工具。它通常与聚合函数结合使用,以对每个子组执行计算。
GROUP BY 子句详解
上一节我们介绍了 GROUP BY 的基本概念,本节中我们来看看它的具体语法和规则。
GROUP BY 子句的语法结构如下:
SELECT column_name(s)
FROM table_name
WHERE condition
GROUP BY column_name(s);
SELECT语句后跟需要查询的列名。FROM子句指定包含这些列的表名。GROUP BY子句后跟一个由逗号分隔的列名列表,数据将根据这些列进行分组。- 如果查询中包含
WHERE子句,则GROUP BY子句必须放在WHERE子句之后。 - 确保
SELECT子句中列出的列包含GROUP BY子句中列出的列。
聚合函数回顾
GROUP BY 子句经常与聚合函数一起使用。聚合函数对一个或多个值执行计算,并为每个子组返回单个值。
以下是数据库开发人员常与 GROUP BY 子句搭配使用的主要聚合函数:
SUM:用于将给定列的值相加并返回总和。AVG:用于计算列值的平均值。MAX:返回一个或多个给定列的最大值。MIN:确定一个或多个给定列的最小值。COUNT:用于计算给定列值出现的次数。
结合 GROUP BY 与聚合函数
了解了基本语法和聚合函数后,现在我们来看看如何将它们结合起来使用。
结合 GROUP BY 与聚合函数的 SELECT 语句语法如下:
SELECT column1, AGGREGATE_FUNCTION(column2)
FROM table_name
GROUP BY column1;
- 首先输入
SELECT语句,后跟列列表。 - 然后根据需要在任何列上应用聚合函数,例如,使用
MAX(column1)计算 column1 的最大值。确保将列名放在括号内。 - 接着包含
FROM子句和表名。 - 最后包含
GROUP BY子句,后跟数据应据以分组的列名。确保这些列也出现在SELECT的列列表中。
实践案例:分析订单数据
现在,我们将运用所学知识,通过一个案例来帮助 Lucky Shrub 公司分析其订单数据。

假设 Lucky Shrub 公司需要分析其订单数据。他们的 orders 表包含五列:order_id、department、order_date、order_quantity 和 order_total。表中存在多条具有相同部门值的记录。
基础分组
首先,我们需要将记录按部门分组,使每个部门只对应一行记录,以便于分析。
以下是按部门分组的基本查询:
SELECT department
FROM orders
GROUP BY department;
执行此查询后,输出结果会将 department 列中的所有记录简化为若干个组,业务中的每个部门对应一行记录。
使用 COUNT 函数
Lucky Shrub 的报告需要显示每个部门收到的订单数量。我们可以使用 COUNT 函数来生成这些数据。
查询语法与之前的几乎相同,关键区别在于必须在 SELECT department 后添加 COUNT 函数及括号内的列名。
SELECT department, COUNT(order_id)
FROM orders
GROUP BY department;
此查询指定了包含数据的列,COUNT 函数会统计订单记录中每个部门出现的次数。执行后,输出结果将返回五个部门及其各自的订单总数。
使用 SUM 函数
接下来,我们计算每个部门从这些订单中获得的总收入。可以使用相同的语法,但这次对 order_total 列使用 SUM 聚合函数。
SELECT department, SUM(order_total)
FROM orders
GROUP BY department;
执行查询后,输出结果返回所选数字列的总和。换句话说,它汇总了每个部门每次出现的 order_total 列的值。
使用 MIN 函数
现在,我们来确定每个部门的最小订单数量。再次使用相同的语法,但使用以 order_quantity 列为目标的 MIN 函数。
SELECT department, MIN(order_quantity)
FROM orders
GROUP BY department;
运行查询后,输出结果返回该列的最小值。
使用 AVG 函数
最后,Lucky Shrub 还需要每个部门的平均订单总额。最后一次编写语法,这次可以使用 AVG 聚合函数来查询 order_total 列。
SELECT department, AVG(order_total)
FROM orders
GROUP BY department;
返回的输出结果显示了 order_total 列的平均值。

总结
本节课中我们一起学习了如何使用 MySQL 的 GROUP BY 子句将行分组为子组,以及如何将该子句与 SQL 聚合函数(如 COUNT、SUM、MIN、AVG)结合使用来分析数据并生成汇总报告。通过帮助 Lucky Shrub 公司的实践案例,我们掌握了从基础分组到应用多种聚合函数进行数据分析的完整流程。
入门 89:MySQL HAVING子句详解 🎯
在本节课中,我们将要学习MySQL中一个非常重要的子句——HAVING子句。它用于对GROUP BY分组后的数据进行筛选,是进行数据聚合分析的关键工具。
什么是HAVING子句?🤔
在之前的课程中,我们学习了如何使用GROUP BY子句对数据进行分组。现在,Luc Shrub公司需要从已分组的客户订单数据中,筛选出符合特定条件的部门,以确定业务中表现最佳的部门。这时,就需要用到HAVING子句。
HAVING子句用于在SQL语句中,为GROUP BY子句生成的分组数据指定筛选条件。
语法回顾与对比 📝
首先,让我们快速回顾一下典型SQL语句的语法。在之前的视频中我们学过,WHERE子句用于在SELECT语句中指定一个或多个筛选条件,并且必须放在GROUP BY子句之前。
但是,WHERE子句不能用于对GROUP BY生成的分组数据指定筛选条件。那么,如何筛选这些分组后的数据呢?答案就是:在SQL语句中添加HAVING子句。
HAVING子句添加在GROUP BY子句之后,用于指定需要应用于分组数据的筛选条件。HAVING子句会针对GROUP BY子句返回的每个组评估筛选条件。如果结果为真,则该组包含在结果集中。
重要提示:如果省略了GROUP BY子句,那么HAVING子句的行为将与WHERE子句完全相同。
HAVING子句基础示例 💡

Luc Shrub可以使用HAVING子句结合聚合函数,来确定哪些部门收到了特定金额的订单。
以下是HAVING子句的基本语法结构:
SELECT column1, aggregate_function(column2)
FROM table_name
GROUP BY column1
HAVING aggregate_function(column2) condition value;
实战演练:协助Luc Shrub进行数据分析 🛠️
现在,是时候运用你新学的HAVING子句知识来协助Luc Shrub了。正如之前所发现的,Luc Shrub需要筛选客户订单数据,以检查哪些部门达到了每月2275美元的销售目标。让我们看看能否帮助他们。
首先,我们来回顾一下存储所需数据的orders表。该表分为五列:order_id、department、order_date、order_qty和order_total。
第一个任务是识别哪些部门的订单总额大于2275美元。因此,我们只关心department和order_total这两列。
我们可以使用带有GROUP BY子句的SELECT语句来确定每个部门的总订单额。
以下是构建查询的步骤:
-
编写基础分组查询:
首先,输入SELECT子句,后跟department列。接着,需要包含SUM聚合函数,并将order_total列放在括号内。然后,添加FROM关键字,后跟表名orders。最后,包含GROUP BY子句并指定department列。SELECT department, SUM(order_total) FROM orders GROUP BY department;执行该语句,将检索出显示五个部门各自总销售额的输出。
-
使用HAVING添加筛选:
下一步是筛选这些数据,以检索订单总额大于2275美元的结果。我们可以使用之前的语句,但这次在GROUP BY子句后添加HAVING子句。
HAVING子句后跟SUM聚合函数的第二个实例,再次针对order_total列。最后,使用大于运算符>,后跟数字2275。这指示SQL语句筛选大于2275美元的结果。SELECT department, SUM(order_total) FROM orders GROUP BY department HAVING SUM(order_total) > 2275; -
使用别名优化查询:
现在这个SQL语句已经可以执行了。但是,我们可以通过使用别名使语法更高效。你应该从之前的课程中熟悉了别名的概念。我们可以在SELECT子句中为聚合函数使用一个名为total的别名。
然后,在HAVING子句中就可以引用这个别名。这使得条件更简洁、更易读。SELECT department, SUM(order_total) AS total FROM orders GROUP BY department HAVING total > 2275;现在执行查询。生成的输出揭示了Luc Shrub公司中三个达到本月销售目标的部门。
感谢你的协助,Luc Shrub已经确定了他们表现最佳的部门。

总结 ✨
本节课中我们一起学习了MySQL的HAVING子句。你现在应该能够识别HAVING子句并解释其用途,同时也应该能够演示如何使用HAVING子句为行组指定筛选条件。你在数据分组方面的学习正在取得巨大进展。
入门 90:MySQL简介模块小结 🎯
在本节课中,我们将回顾并总结第一个模块的核心内容。这个模块主要介绍了MySQL的基础知识,包括数据过滤、表连接和数据分组等关键技能。
模块内容回顾
恭喜你完成了本课程第一个模块的学习。现在,让我们花点时间回顾一下你在本模块课程中获得的一些关键技能。


第一课:课程与MySQL简介
在第一课中,你学习了课程介绍,了解了为什么MySQL是数据库工程师的关键语言,以及Meta公司如何使用MySQL。你还通过复习一些关键的额外资源来巩固了知识。

第二课:数据过滤

上一节我们介绍了MySQL的基础,本节中我们来看看如何筛选数据。你首先学习了数据过滤和逻辑运算符的概念。

接着,你发现了如何使用逻辑运算符来过滤你的数据集。
然后,你完成了一篇阅读材料,探索了一些数据过滤的真实世界例子。
最后,你复习了关于数据过滤和逻辑运算符主题的一些额外资源。


第三课:连接表
掌握了数据过滤后,我们进入下一部分:连接表。你首先学习了别名的概念以及如何在MySQL中使用它们。
然后,你学习了如何识别不同类型的连接(JOIN)以及如何在数据库表中使用它们,并在实验环境中演示了这些新技能。

接下来,你了解了并集(UNION)运算符的概念,并在数据库中演示了它的用法。


最后,你通过探索额外的阅读材料加深了对这些主题的理解。

第四课:数据分组

在第三课学习了连接表之后,第四课也是最后一课,你将获得数据分组的技能。你首先学习了如何识别和使用 GROUP BY 子句。

然后,你学习了如何使用 HAVING 子句。
接下来,你完成了一篇阅读材料,学习了如何利用MySQL的 ANY 和 ALL 运算符。


最后,你需要在实验环境中挑战自己,演示这些新的数据分组技能。
总结
本节课中我们一起学习了MySQL模块的核心内容。你现在应该能够使用MySQL在数据库中过滤数据、连接表和分组数据了。做得很好!我期待在下一个模块中继续指导你,在那里你将学习如何更新数据库和使用视图。
入门 91:MySQL REPLACE语句详解 🛠️
在本节课中,我们将要学习MySQL中的REPLACE语句。这是一种用于插入或更新表中数据的强大命令,尤其适用于需要替换现有记录的场景。我们将通过一个园艺中心的案例,了解其工作原理、语法以及具体应用。
概述 📋
REPLACE命令用于向表中插入新数据或更新现有数据。与标准的INSERT和UPDATE命令不同,REPLACE会首先检查是否存在重复的主键或唯一键。如果找到重复项,它会先删除现有记录,然后用新数据替换它。
上一节我们介绍了数据操作的基本概念,本节中我们来看看REPLACE这个特殊的命令如何工作。
REPLACE命令的工作原理 ⚙️
REPLACE命令首先通过检查现有记录的主键或唯一键,来判断新数据记录是否已存在于表中。
- 如果没有匹配的键,则
REPLACE会像普通的INSERT语句一样,直接添加新数据。 - 如果找到匹配的键,则该命令会删除现有记录,并用新记录替换它。
这个过程可以确保数据的唯一性,同时简化了“插入或更新”的操作逻辑。
REPLACE命令的语法 📝
为了更好地理解REPLACE命令,我们先快速回顾一下INSERT命令的语法。它们的相似性将帮助你更快掌握REPLACE。
以下是INSERT命令的基本语法:
INSERT INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...);
REPLACE命令的工作方式非常相似。你需要写出表名、列名和值,唯一的区别是语句必须以REPLACE命令开头。
REPLACE命令有两种主要语法形式。

第一种语法(类似INSERT):
REPLACE INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...);
第二种语法(使用SET关键字):
REPLACE INTO table_name
SET column1 = value1, column2 = value2, ...;
SET子句为选定的列赋值。如果不使用WHERE子句指定条件,它会定位所需的数据记录,然后用新的值集进行替换。如果在SET子句中未指定某列的值,则REPLACE命令会使用默认值或将值设置为NULL。
实战演练:为Lucky Shrub更新员工联系信息 🌿
现在你已经熟悉了REPLACE命令的工作原理,让我们花点时间看看如何帮助Lucky Shrub在其数据库中插入和替换新旧员工记录。
Lucky Shrub的员工联系记录存储在employees_contact_info表中。该表包含三列:作为主键的EmployeeID、ContactNumber和EmailAddress。
任务1:插入新员工记录
你需要为新员工Shamus Hogan插入一条新数据记录,详细信息如下:ID为1,以及联系电话和电子邮件地址。
你可以使用标准的INSERT命令添加此数据:
INSERT INTO employees_contact_info (EmployeeID, ContactNumber, EmailAddress)
VALUES (1, ‘123-456-7890‘, ‘shamus@example.com‘);
执行此查询后,新员工记录被添加到表中。
对于员工Thomas Erickson,你可以使用REPLACE命令完成相同的操作:
REPLACE INTO employees_contact_info (EmployeeID, ContactNumber, EmailAddress)
VALUES (2, ‘987-654-3210‘, ‘thomas@example.com‘);
执行查询后,使用SELECT语句检查表记录,可以看到Thomas和Shamus的联系详情都已存在。
任务2:替换离职员工记录
假设Shamus决定离开Lucky Shrub,你需要将他的详细信息替换为新员工Maria Carter的详细信息。
如果你尝试使用INSERT命令更新表,并给Maria分配ID为1,系统会返回一个“重复条目”的错误。这是因为ID 1作为主键值已经分配给了Shamus,而主键在表的每一行中都必须具有唯一值。
那么,如何用Maria的记录替换Shamus的记录呢?只需再次键入语句,但这次使用REPLACE命令而不是INSERT:
REPLACE INTO employees_contact_info (EmployeeID, ContactNumber, EmailAddress)
VALUES (1, ‘555-123-4567‘, ‘maria@example.com‘);
MySQL接受了该语句且没有报错。查询表后确认,记录已成功替换。
任务3:更新现有员工信息
Maria最近更改了她的联系电话,该号码也需要在表中更新。你可以使用REPLACE命令的SET语法来更新这条数据记录:
REPLACE INTO employees_contact_info
SET EmployeeID = 1, ContactNumber = ‘555-999-8888‘, EmailAddress = ‘maria@example.com‘;
注意:必须为所有列设置值,否则它们将被设置为NULL或默认值。
执行查询后,再次使用SELECT语句检查表,可以确认Maria的详细信息已更新。
总结 🎯

本节课中我们一起学习了MySQL的REPLACE语句。我们了解到,REPLACE是一种结合了插入和更新功能的命令,它通过检查主键或唯一键来决定是新增记录还是替换已有记录。我们通过Lucky Shrub的案例,实践了如何使用REPLACE INTO ... VALUES ...和REPLACE INTO ... SET ...两种语法来插入新数据、替换旧数据以及更新现有信息。掌握REPLACE命令能让你更高效地处理需要维护数据唯一性的场景。
入门 92:MySQL中的约束 🛡️
在本节课中,我们将要学习MySQL中的约束概念。约束是用于确保数据库表中数据有效性和完整性的规则。我们将通过小柠檬餐厅的案例,了解约束的主要类型、功能以及ON DELETE CASCADE和ON UPDATE CASCADE选项的作用。
什么是约束?🔍
当创建表时,你可能需要为某些列设定规则。例如,你可能要求表中的每一行在某个列(如电话号码)上都必须持有唯一的值。

你可以通过使用唯一约束来强制执行此规则。该约束能防止在数据库中插入或更新数据时违反此规则。


MySQL约束的主要类型 📊
MySQL数据库中有三种主要的约束类型,用于强制执行数据规则:
- 键约束:应用于键类型的规则。
- 域约束:用于管理特定列可以存储的值的规则。
- 参照完整性约束:为参照键(外键)建立的规则。


接下来,我们将逐一探讨这三种MySQL约束类型,并了解小柠檬餐厅如何在他们的数据库中使用它们。


键约束 🔑

在之前的课程中我们了解到,所有表都包含不同类型的键,例如主键和外键。


你可以使用约束为这些键建立规则。例如,主键约束可用于指定一个或多个列的值必须始终唯一,并且不能接受NULL值。

小柠檬餐厅的数据库中有一个名为Customers的表。该表使用主键约束来记录客户预订的关键数据。该表有三列:CustomerID、FullName和PhoneNumber。
CustomerID被定义为主键,它标识表中唯一的记录。由于主键约束,该列的值必须始终唯一,并且绝不能接受NULL值。换句话说,该列中的每一行都必须有一个客户ID,并且所有客户ID都必须是唯一的。

域约束 📏
正如前面提到的,域约束是为特定列可以存储的值定义的特殊规则。
小柠檬餐厅的数据库包含一个Bookings表,用于记录客户预订数据。然而,餐厅每次预订最多只能容纳8位客人,因此他们在NumberOfGuests列上实施了SQL的检查约束。



这限制了可以放入该列的值范围,意味着该表会拒绝任何大于8的数值。

参照完整性约束 🔗
前面提到,这种类型的约束为参照键(外键)建立规则,但它具体是如何工作的呢?

基本上,在参照完整性约束中,涉及两种类型的表:一个包含主键的参照表和一个包含外键的被参照表。


参照表中存在的外键列的值,必须始终存在于被参照表中。否则,两个表之间就无法建立连接。
为了更好地理解这一点,让我们通过实体关系图来探索小柠檬餐厅数据库中相关表的例子。

小柠檬餐厅的数据库包含两个相关的表:存储客户数据的Customers表和记录客户餐厅预订信息的Bookings表。

Bookings表中的每条预订都必须关联到Customers表中的特定客户,否则餐厅无法确定是谁进行了预订。这也意味着,每个客户必须先注册在Customers表中,才能在Bookings表中进行预订。

Bookings表中的CustomerID列被定义为外键。这是将两个表连接在一起并在它们之间建立依赖关系的属性。


这意味着,如果在Customers表中修改或删除一行数据,那么这个操作会破坏Bookings表中相关的数据行。

换句话说,从Customers表中删除一行数据会违反参照完整性规则,这将导致MySQL返回错误消息,警告该操作会直接影响Bookings表。


使用CASCADE选项 🔄
那么,如何在不违反参照完整性约束的情况下对Bookings表进行必要的更改呢?


在这种情况下,你可以使用ON DELETE CASCADE选项。此选项会自动从Bookings表中删除相关的数据行。
如果你想更新Customers表中的主键值,可以使用ON UPDATE CASCADE选项来自动更新Bookings表中的相关行。

你将在后续视频中了解更多关于这些选项的信息。


总结 📝
本节课中我们一起学习了MySQL中的约束。你现在应该能够识别约束的主要类型并解释它们的功能。同时,你也应该能够解释MySQL的ON DELETE CASCADE和ON UPDATE CASCADE选项的作用。这些工具对于维护数据库的数据完整性和一致性至关重要。
入门 93:约束实践 🛠️
在本节课中,我们将学习如何在MySQL数据库中为表应用常见的约束,以确保数据的一致性和完整性。我们将通过为Little Lemon餐厅创建“顾客”和“预订”两个表来实践。


概述

我们将创建两个表,并应用以下四种常见约束:NOT NULL、UNIQUE、CHECK和FOREIGN KEY。通过这个过程,你将理解每种约束的作用及其对数据质量的重要性。
创建顾客表
首先,我们需要创建Customers表来记录顾客的详细信息。此表需要应用以下约束:
- 在
CustomerID列上应用主键约束。 - 在
FullName列上应用非空约束。 - 在
PhoneNumber列上应用唯一约束,确保每个顾客的电话号码都是唯一的。
以下是创建该表的步骤和代码:
CREATE TABLE Customers (
CustomerID INT NOT NULL PRIMARY KEY,
FullName VARCHAR(100) NOT NULL,
PhoneNumber INT NOT NULL UNIQUE
);
执行上述语句后,我们可以查看表的结构以确认约束已正确应用。
SHOW COLUMNS FROM Customers;
执行SHOW COLUMNS命令后,输出结果将显示Customers表的所有列及其约束。我们可以看到:
- 所有列都被定义为
NOT NULL。 - 声明了两个键:
CustomerID是主键,PhoneNumber被设置为唯一键,这意味着该列只接受唯一的值。
创建预订表
上一节我们创建了顾客表,本节中我们来看看如何创建预订表并建立表之间的关系。创建Bookings表的重点是应用参照完整性约束和一个CHECK约束,以将客人数量限制为最多8位。
以下是创建该表的完整代码:
CREATE TABLE Bookings (
BookingID INT NOT NULL PRIMARY KEY,
BookingDate DATE NOT NULL,
TableNumber INT NOT NULL,
NumberOfGuests INT NOT NULL CHECK (NumberOfGuests <= 8),
CustomerID INT NOT NULL,
FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID) ON DELETE CASCADE ON UPDATE CASCADE
);
在这段代码中,我们定义了以下列和约束:
BookingID:定义为主键。NumberOfGuests:使用CHECK约束,通过<=运算符确保其值不超过8。CustomerID:定义为外键,并通过REFERENCES约束使其引用Customers表中的CustomerID列。ON DELETE CASCADE和ON UPDATE CASCADE选项确保了当Customers表中的数据被更新或删除时,Bookings表中的相关记录也会自动同步。
现在,让我们查看Bookings表的结构。
SHOW COLUMNS FROM Bookings;

输出结果显示,所有列都被赋予了所需的约束和数据类型。值得注意的是,CustomerID列被标记为MUL(Multiple),这意味着它不是唯一键,多行可以拥有相同的键值。这是合理的,因为每位顾客可能在不同时间进行多次预订。
总结

本节课中,我们一起学习了如何在MySQL数据库表中应用NOT NULL、UNIQUE、CHECK和FOREIGN KEY约束。我们通过为Little Lemon餐厅创建Customers和Bookings两个表进行了实践,并理解了外键约束如何连接两个表并建立依赖关系。当主表中的数据发生变化时,相关子表中的数据会自动更新或删除,这有效地维护了数据的完整性和一致性。
入门 94:MySQL ALTER TABLE 语句详解 🛠️
在本节课中,我们将学习如何使用 MySQL 的 ALTER TABLE 语句来修改现有的数据库表。我们将通过一个实际案例,学习如何添加、删除和修改表中的列与约束。
概述
Lishhrub 园艺中心购置了新的重型机械,但只有合格的员工才能操作。公司有一个名为 Machinery 的数据库表,用于记录所有合格员工的联系信息。然而,该表在约束方面存在问题,并且缺少一些关键信息。我们可以使用 ALTER TABLE 语句来修复这些问题。通过本课学习,你将能够对现有表进行添加、删除和修改列与约束的操作。
ALTER TABLE 语句简介
你可能会经常遇到数据库中的表缺少某些列或约束,或者现有的列和约束需要修改的情况。ALTER TABLE 语句就是用来实现这些更改的。它通常与不同的 SQL 命令结合使用。
以下是 ALTER TABLE 语句中常用的一些命令的快速概览:
MODIFY命令用于针对特定列,并指示 SQL 对其进行更改。ADD命令用于向表中添加新列。DROP命令用于从表中删除或移除列。
语法与实践
那么,如何使用这些命令来修改表呢?ALTER TABLE 语句以 ALTER TABLE 子句开始,后跟要修改的表的名称。
接下来,插入一个 MODIFY 命令,后跟要修改的列名以及要进行的更改。例如,你可以更改列的数据类型并添加 NOT NULL 约束。然后,为所有其他要修改的列重复 MODIFY 命令。
你也可以通过添加另一列来修改表,只需使用 ADD COLUMN 命令,后跟新列的名称即可。
要从表中删除列,只需使用 DROP 命令,后跟要删除的列名。
现在你已经熟悉了 ALTER TABLE 语句,让我们看看能否帮助 Lishhrub 公司对他们的表进行必要的修改。
Lishhrub 需要完成的任务如下:
- 将
employee_id列设置为主键。 - 更改列约束。
- 向表中添加一个新列。
让我们开始吧。
任务实施
Lishhrub 的 machinery 表包含四列:employee_id、full_name、phone_number 和 county。该表缺少一个主键。幸运的是,employee_id 列是完美的候选者,因为所有值都是唯一的。

要将此列设置为主键,你可以编写一个 ALTER TABLE 语句。
ALTER TABLE machinery
MODIFY employee_id VARCHAR(10) NOT NULL PRIMARY KEY;
employee_id 列现在已成为表的主键。
看起来表中的每一列也都设置为接受 NULL 值。这意味着表中可以包含空字段或行,这在数据库实践中是不好的。因此,要将所有列更改为 NOT NULL,你可以编写另一个 ALTER TABLE 语句。实际上,你可以使用与之前相同的语句,只需为每一列添加一个新行。
对于 full_name 和 county 列,你可以编写以下语法:
ALTER TABLE machinery
MODIFY full_name VARCHAR(100) NOT NULL,
MODIFY county VARCHAR(100) NOT NULL;
对于 phone_number 列,你可以编写类似的语法,但使用 INT 数据类型和 UNIQUE 约束:
ALTER TABLE machinery
MODIFY phone_number INT UNIQUE;
这意味着该列现在只接受唯一的数值。这避免了任何重复的值。
要查看新的表结构,请编写以下语句:
SHOW COLUMNS FROM machinery;
此查询的输出显示:
employee_id现在被设置为主键。phone_number是一个唯一值。- 所有列都设置为
NOT NULL。
现在,你的最终任务是向表中添加一个新列。
Lishhrub 的重型机械只能由 18 岁及以上的员工操作,因此公司需要识别每位员工的年龄,并确定谁有资格操作机械。表中目前没有年龄列,因此你需要创建它并添加一个约束,以确保添加到表中的每位新员工至少年满 18 岁。
你可以按如下方式编写语句:
ALTER TABLE machinery
ADD COLUMN age INT CHECK (age >= 18);
然后点击执行查询。要查看表的新结构,请编写:
SHOW COLUMNS FROM machinery;

输出现在显示包含新 age 列的 machinery 表。
总结
在本节课中,我们一起学习了如何使用 MySQL 的 ALTER TABLE 语句。通过帮助 Lishhrub 公司修改 machinery 表,我们实践了如何设置主键、修改列的数据类型和约束(如 NOT NULL 和 UNIQUE),以及如何添加带有检查约束的新列。现在,你应该能够使用 ALTER TABLE 子句对现有表进行添加、删除和修改列与约束的操作了。
入门 95:MySQL 复制表教程 📋
在本节课中,我们将要学习如何在MySQL数据库中复制表。复制表是数据库管理中的一项常见任务,可以用于备份数据、创建测试环境或在数据库重构期间保护数据安全。
概述
Looky Shrub公司计划对其数据库进行重大改造。在准备过程中,他们需要创建数据的副本,以确保在重建期间数据的安全。他们可以通过复制表的过程来完成这项任务。接下来,你将学习复制表的过程,并帮助Looky Shrub复制其数据库中的表。完成本视频后,你将学会如何:
- 在同一数据库内,将数据从现有表复制到新表。
- 将表复制到新位置,同时确保其保留约束。
- 将数据从现有表复制到不同数据库的新表中。
这些任务是使用 CREATE TABLE 语法执行的。然而,在深入探讨此语法之前,让我们先回顾一下复制表的过程。
复制表流程回顾
在开始复制表之前,熟悉流程非常重要。
以下是复制表的基本步骤:
- 识别源:首先,需要确定要从中复制数据的数据库和表。
- 选择列:接下来,确定要复制的列,可以是所有列,也可以只是其中一部分。
- 创建新表:然后,使用
CREATE TABLE语句构建一个具有相关表名的新表。 - 填充数据:最后,使用
SELECT命令,通过指定要从中复制数据的列来构建新表的结构。
现在你已经熟悉了流程步骤,让我们来回顾一下 CREATE TABLE 语法。
复制表语法详解
上一节我们介绍了复制表的流程,本节中我们来看看实现这一流程的具体SQL语法。
在同一数据库内复制表

复制表的SQL语句以 CREATE TABLE 命令开始,后跟新表的名称。接着,编写 SELECT 命令,然后标识要复制的列。你可以复制一列、多列或所有列。最后,使用 FROM 命令,后跟要复制的现有表的名称。
其基本语法结构如下:
CREATE TABLE new_table_name
SELECT column1, column2, ...
FROM existing_table_name;
在不同数据库之间复制表
那么,如何在两个不同的数据库之间复制表呢?同样以 CREATE TABLE 命令开始。但是,在这种情况下,必须使用点符号来标识新数据库和表的名称。然后使用 SELECT 命令选择现有表的列。最后,使用 FROM 子句,后跟另一个点符号实例,该实例标识要复制的现有表和数据库的名称。
其语法结构如下:
CREATE TABLE new_database.new_table_name
SELECT column1, column2, ...
FROM existing_database.existing_table_name;
实践操作:帮助Looky Shrub复制表
现在,Looky Shrub已准备好开始复制其数据库中的表。他们希望按以下步骤执行此过程:
- 将
clients表复制到同一数据库中的名为clients_test的新表中。 - 仅将几个选定的列复制到表中。
- 确保原始表中的所有约束都复制到新表中。
- 将表从一个数据库复制到另一个数据库。
运用你新学到的复制表知识来帮助他们。
任务一:复制整个表
首先,让我们通过输入 SELECT * FROM clients; 来查看Looky Shrub数据库中的 clients 表,然后单击“执行”以运行查询。这将在屏幕上生成 clients 表。该表包含四列:client_id、full_name、contact_number 和 location。
对于测试的第一部分,Looky Shrub需要将 clients 表复制到同一数据库中名为 clients_test 的新表中。
你可以使用 CREATE TABLE SQL查询来执行此任务。以下是具体操作:
CREATE TABLE clients_test
SELECT *
FROM clients;
此查询将所有列及其数据从 clients 表复制到新的 clients_test 表。
要检查查询是否成功,可以键入以下语句:SELECT * FROM clients_test;。此查询会生成 clients_test 表,并且该表按要求包含了所有数据的副本。
任务二:复制部分列数据
接下来,Looky Shrub需要你仅复制部分数据。他们需要将 clients 表中的 full_name 和 contact_number 列复制到另一个表中。
以下是操作步骤:
CREATE TABLE clients_test2
SELECT full_name, contact_number
FROM clients
WHERE location = ‘Palo Alto‘;
此查询创建了 clients_test2 表,并且该表包含了来自 clients 表中所有位于“Palo Alto”的员工的 full_name 和 contact_number 数据的副本。
任务三:复制表结构及约束
现在,你需要确保原始表中的所有约束都复制到新表中。重要的是要记住,使用目前遇到的方法复制数据不会复制键约束。
你可以通过键入并执行语句 SHOW COLUMNS FROM clients; 来检查原始表上的约束。查询会生成 clients 表的结构,显示为 client_id 和 contact_number 列设置的键约束。
现在,让我们通过键入并执行以下语句来检查 clients_test 表上的这些约束:SHOW COLUMNS FROM clients_test;。此语句显示 clients_test 表缺少原始表中定义的主键和唯一键。
那么,如何复制这些键呢?你可以使用以下语句:
CREATE TABLE clients_test3 LIKE clients;
LIKE 关键字创建现有表结构的精确副本。然后,键入并执行以下SQL语句以显示新表结构:SHOW COLUMNS FROM clients_test3;。输出显示这是初始 clients 表的精确副本,并且所有键约束都已按预期复制。
任务四:跨数据库复制表
你的最终任务是将 clients 表从Looky Shrub数据库复制到新的 testdb 数据库。
操作如下:
CREATE TABLE testdb.clients_test
SELECT *
FROM lookyshrub.clients;
现在,你只需通过进入 test 数据库来检查查询是否成功。键入 USE testdb;,然后 SHOW TABLES; 以显示测试数据库中的所有表。此语句显示了在 testdb 数据库中创建的所有表,包括你刚从Looky Shrub数据库复制过来的 clients_test 表,并且该表包含了原始表中的所有数据。

总结
本节课中我们一起学习了MySQL中复制表的核心操作。Looky Shrub现在在其数据库中拥有了所有需要的表副本。你现在应该能够:
- 在同一数据库内,将数据从现有表复制到新表。
- 将表复制到新位置,同时确保其保留约束。
- 将数据从现有表复制到不同数据库的新表中。
做得好!
入门 96:MySQL子查询 🧩
在本节课中,我们将要学习MySQL中的子查询概念。子查询是嵌套在另一个查询内部的查询,它可以帮助我们从数据库中提取更复杂、更精确的数据集。我们将了解子查询的基本语法、适用场景以及如何利用它来检索数据。
什么是子查询?
上一节我们介绍了课程目标,本节中我们来看看子查询的定义。子查询,顾名思义,是一个查询中的查询。换句话说,它是一个放置在外部查询内部的内部查询。内部查询可被视为子查询,而外部查询则可被视为父查询。
子查询的语法
为了理解子查询的工作原理,最好的方式是学习其语法。正如刚才所学,子查询是一个查询中的查询,即一个位于外部(父)查询内部的内部(子)查询。
内部查询(子查询)首先执行,其结果随后传递给外部(父)查询。在MySQL中,你也可以构建多个子查询。外部查询的写法与任何普通查询一样,包含SELECT、FROM和WHERE子句。同样,子查询也写作标准查询。
然而,子查询必须始终放置在一对括号内。执行时,子查询可以返回以下任何一种结果:一个单个值、单行、单列或多行(包含一列或多列)。
子查询的一个关键优势是,你可以使用比较运算符将其结果与其他值进行比较。

以下是子查询与比较运算符结合使用的语法示例。子查询可以放在父查询WHERE子句中比较运算符的前面或后面。
SELECT * FROM 表名
WHERE 列名 比较运算符 (SELECT 列名 FROM 表名 WHERE 条件);
子查询的演示应用
现在我们已经熟悉了子查询的基础知识,接下来通过一个演示来看看它们是如何被使用的。
假设Little Lemon餐厅需要从其数据库中提取员工薪资数据来完成财务核算。这些数据存储在employees表中。该表包含四列:EmployeeID、EmployeeName、Role和AnnualSalary。餐厅需要利用此表找出哪些员工的年薪高于助理厨师。
我们可以使用子查询来完成此任务。这个查询可以分两部分进行:
- 外部(主)查询必须提取年薪大于指定值的所有员工的详细信息。
- 子查询必须找出助理厨师的年薪。
执行时,子查询从员工数据库中提供一个数据子集,这个数据子集随后作为外部查询的输入。
以下是构建查询的步骤:
首先,编写外部查询:
SELECT *
FROM Employees
WHERE AnnualSalary >
接下来,我们需要确定WHERE子句中要比较的具体值。这通过子查询实现。
在大于运算符后添加括号,并在其中编写子查询:
(SELECT AnnualSalary FROM Employees WHERE Role = 'Assistant Chef')
现在,完整的查询语句如下:
SELECT *
FROM Employees
WHERE AnnualSalary > (SELECT AnnualSalary FROM Employees WHERE Role = 'Assistant Chef');
执行此查询。子查询首先执行,提取出助理厨师的年薪(例如45,000美元)。这个值现在成为外部查询WHERE子句的输入。接着,外部查询执行,筛选出年薪高于助理厨师的所有员工记录。
查询结果显示,助理厨师年薪为45,000美元,而外部查询显示有三名员工的薪资高于此数额,他们分别是经理、助理经理和主厨。

总结
本节课中我们一起学习了MySQL子查询。我们了解到子查询是一个嵌套在另一个查询内部的查询,它先于外部查询执行,并将其结果提供给外部查询使用。我们学习了子查询的基本语法,并通过一个实际案例演示了如何使用子查询来比较和筛选数据。掌握子查询能让你更灵活、更高效地从数据库中检索所需信息。
入门 97:子查询与复杂比较运算符 🧮
在本节课中,我们将学习如何将子查询与复杂的比较运算符结合使用,以执行更高级的数据检索任务。我们将重点介绍 ALL、ANY、SOME、EXISTS 和 NOT EXISTS 这些运算符,并通过 Little Lemon 餐厅的实际案例来演示它们的应用。
概述
子查询是嵌套在主查询(外部查询)内部的查询。一个关键优势在于,你可以使用运算符将子查询的结果与其他值进行比较。然而,当子查询返回多行结果时,就需要使用更复杂的比较运算符来处理这些结果集。
上一节我们介绍了标准子查询,本节中我们来看看如何与 ALL、ANY、SOME、EXISTS 和 NOT EXISTS 这些运算符配合使用。
复杂比较运算符简介
以下是可与多行子查询一起使用的核心运算符:
ANY运算符:如果主查询中的值与子查询返回的任意一个值满足比较条件,则返回数据。ALL运算符:只有当主查询中的值与子查询返回的所有值都满足比较条件时,才返回数据。SOME运算符:功能与ANY相同,返回与子查询中一个或多个值匹配的数据。
这些运算符允许你在一个单一的比较值和一系列其他值之间进行比较。
EXISTS 与 NOT EXISTS 运算符

子查询也可以与 EXISTS 和 NOT EXISTS 运算符结合使用。
EXISTS运算符:用于测试子查询返回的结果集中是否存在行。如果子查询返回一行或多行记录,则结果为TRUE。NOT EXISTS运算符:检查子查询返回的结果是否不存在。当子查询没有返回任何行时,结果为TRUE。
让我们回顾一下 EXISTS 和 NOT EXISTS 的语法。其语法与标准子查询非常相似,关键区别在于 EXISTS 或 NOT EXISTS 运算符被放置在 WHERE 子句之后,用于判断子查询中指定值的存在与否。
-- EXISTS 语法示例
SELECT * FROM 表A
WHERE EXISTS (SELECT * FROM 表B WHERE 条件);
-- NOT EXISTS 语法示例
SELECT * FROM 表A
WHERE NOT EXISTS (SELECT * FROM 表B WHERE 条件);
实战演示:使用 ALL 运算符
Little Lemon 餐厅需要识别出所有年薪小于或等于以下所有职位员工年薪的员工:经理、助理经理、主厨和服务领班。
所需数据在 employees 表中,该表包含 EmployeeID、Name、Role、AnnualSalary 四列。
我们可以使用一个外部查询来识别年薪符合条件的员工,以及一个子查询来提取指定职位员工的年薪数据。
以下是构建查询的步骤:
- 编写外部查询:选择所有列,从
employees表,并设置WHERE条件比较AnnualSalary。 - 编写子查询:在括号内,选择
AnnualSalary列,从employees表,并筛选Role在指定列表中。 - 使用 ALL 运算符:在比较运算符
<=之后、子查询之前插入ALL运算符。
最终查询语句如下:
SELECT *
FROM employees
WHERE AnnualSalary <= ALL (
SELECT AnnualSalary
FROM employees
WHERE Role IN ('Manager', 'Assistant Manager', 'Head Chef', 'Head Waiter')
);
执行过程:子查询先执行,找出经理等四个角色的年薪(例如 70,000, 65,000, 50,000, 40,000)。然后外部查询筛选出年薪小于或等于所有这些值的员工。最终输出显示,只有 ID 为 5 和 6 的员工满足条件。
实战演示:使用 ANY 运算符
接下来,Little Lemon 需要识别年薪大于或等于前述四个职位中任意一个职位员工年薪的员工。
我们可以复用之前的查询结构,但需要调整比较运算符并使用 ANY。
- 将外部查询
WHERE条件中的比较运算符改为>=。 - 将
ALL运算符替换为ANY运算符。
修改后的查询如下:
SELECT *
FROM employees
WHERE AnnualSalary >= ANY (
SELECT AnnualSalary
FROM employees
WHERE Role IN ('Manager', 'Assistant Manager', 'Head Chef', 'Head Waiter')
);
执行后,输出显示有五名员工的年薪大于或等于子查询返回的任意一个值。
实战演示:使用 EXISTS 与 NOT EXISTS
最后,Little Lemon 需要确定他们的主厨和服务领班是否被分配了预订任务。这可以使用 EXISTS 或 NOT EXISTS 运算符来完成。
查询涉及两个动作:外部查询提取员工详情,子查询判断主厨或服务领班是否被分配了预订。相关数据在 bookings 表中。
使用 EXISTS 的查询:
SELECT *
FROM employees e
WHERE EXISTS (
SELECT *
FROM bookings b
WHERE b.EmployeeID = e.EmployeeID
AND e.Role IN ('Head Chef', 'Head Waiter')
);
EXISTS 运算符检查子查询中是否存在指定结果。如果存在(结果为 TRUE),则外部查询会筛选出那两名被分配了预订的员工详情。
使用 NOT EXISTS 的查询:
SELECT *
FROM employees e
WHERE NOT EXISTS (
SELECT *
FROM bookings b
WHERE b.EmployeeID = e.EmployeeID
AND e.Role IN ('Head Chef', 'Head Waiter')
);
NOT EXISTS 运算符检查子查询结果是否不存在。在本例中,WHERE 子句会筛选出不在子查询结果中的员工,即返回那些不满足子查询条件(未被分配预订)的四名员工的数据。

总结
本节课中我们一起学习了如何将子查询与复杂的比较运算符结合使用。我们探讨了 ALL、ANY/SOME 运算符用于多值比较的场景,以及 EXISTS 和 NOT EXISTS 运算符用于检查结果存在性的场景。通过 Little Lemon 餐厅的具体示例,我们演示了这些技术在复杂数据检索任务中的应用,使你能够更灵活、更强大地操作数据库。
入门 98:创建与管理视图
概述
在本节课中,我们将要学习数据库中的一个重要概念——视图。我们将了解什么是视图,为什么需要使用视图,并掌握如何在MySQL数据库中创建、重命名和删除视图。通过一个帮助Lucy Shrub商店识别畅销商品的实例,我们将把理论知识应用到实践中。
什么是视图?👀
上一节我们介绍了课程概述,本节中我们来看看视图的基本概念。
视图是基于一个或多个数据库表的查询结果集生成的虚拟表。它本身不存储数据,而是提供一种访问和操作底层表中数据的接口。
以下是创建视图的核心语法:
CREATE VIEW view_name AS
SELECT column1, column2, ...
FROM table_name
WHERE condition;
为什么使用视图?
理解了视图是什么之后,我们来看看数据库工程师使用视图的几个常见原因。
以下是视图的主要用途:
- 简化数据访问:当表中列很多时,可以创建一个只包含必要列的视图,简化查询。
- 数据整合:可以将来自多个不同表的数据组合到一个虚拟表中,方便查询。
- 增强安全性:通过视图可以限制用户只能访问特定的行或列,保护敏感数据。
- 逻辑抽象:可以隐藏复杂的查询逻辑,为用户提供一个清晰、简单的数据接口。
如何创建视图?
了解了视图的用途,接下来我们学习创建视图的具体语法和步骤。
创建视图的语法遵循一个清晰的五步过程:
- 使用
CREATE VIEW语句开始创建。 - 列出需要从原表移动到虚拟表的列。
- 指定从中提取数据以创建视图的原表。
- 设置数据筛选条件。
- 设置数据排序规则。
从单表创建视图
从单个表创建视图相对简单。其基本语法结构如下:
CREATE VIEW view_name AS
SELECT table1.column1, table1.column2
FROM table1
WHERE condition
ORDER BY column1;
其中,点符号(.)用于将列与其所属的表关联起来,在查询单表时可省略。

从多表创建视图
当需要从多个表创建视图时,语法会稍有不同,关键在于需要使用 JOIN 来连接表。
从多表创建视图的语法示例如下:
CREATE VIEW view_name AS
SELECT table1.column1, table2.column2
FROM table1
INNER JOIN table2 ON table1.matching_column = table2.matching_column
WHERE condition;
点符号在这里尤为重要,它可以避免来自不同表但名称相同的列产生冲突。
实践:帮助Lucy Shrub商店
现在我们已经掌握了视图的理论知识和创建方法,是时候运用这些知识来帮助Lucy Shrub商店解决实际问题了。
Lucy Shrub商店今年销售业绩很好,他们需要找出销量前三的商品,以确保未来几个月有足够的库存。他们的数据库中有订单表(orders)和产品表(products)。
分析表结构
在创建视图前,我们先熟悉一下相关的表。
orders表:包含order_id、client_id、product_id、quantity、cost五列。products表:包含product_id、item_name、price三列。
我们需要创建一个视图,包含产品名称、订单数量和总成本。
创建“畅销商品”视图
以下是创建该视图的完整SQL语句:
CREATE VIEW top_three_products AS
SELECT p.item_name AS item, o.quantity, o.cost
FROM orders o
INNER JOIN products p ON o.product_id = p.product_id
ORDER BY o.cost DESC
LIMIT 3;
执行此查询后,会生成一个名为 top_three_products 的虚拟表。我们可以像查询普通表一样查询它:
SELECT * FROM top_three_products;
管理视图:重命名与删除
视图创建后,我们还可以对它进行重命名或删除操作。
重命名视图
如果觉得视图名称太长,可以使用 RENAME TABLE 命令来重命名它。
RENAME TABLE top_three_products TO top_products;
执行后,视图名称就从 top_three_products 改为 top_products 了。

删除视图
当不再需要某个视图时,可以使用 DROP VIEW 命令将其删除。删除视图不会影响创建它的原始基表。
DROP VIEW top_products;
执行此命令后,top_products 视图即被移除。
总结
本节课中我们一起学习了数据库视图的核心知识。我们首先了解了视图是作为一种虚拟表存在的,它能够简化查询、整合数据并提升安全性。接着,我们详细学习了如何使用 CREATE VIEW 语法从单个或多个表创建视图,并理解了点符号在区分列时的重要性。最后,通过一个实际案例,我们实践了视图的创建,并学会了如何使用 RENAME TABLE 和 DROP VIEW 来管理视图。掌握视图的创建与管理,是高效进行数据库操作和维护的重要技能。
入门 99:模块小结 - 更新数据库和使用视图
在本节课中,我们将回顾本模块的核心内容,总结关于数据更新、约束、表结构修改、子查询以及视图的关键知识与技能。
恭喜你完成了本课程的第二个模块。现在,让我们花点时间回顾一下你在本模块课程中获得的一些关键技能。
📝 第一课:插入与更新数据


在第一课中,你学习了如何插入和更新数据。现在你应该能够解释 REPLACE 语句的概念,概述如何使用 REPLACE 语句在数据库表中插入或更新数据,并能在实验环境中完成项目后演示 REPLACE 语句。

以下是 REPLACE 语句的基本语法:
REPLACE INTO table_name (column1, column2, ...) VALUES (value1, value2, ...);
🔧 第二课:值与约束
上一节我们介绍了数据更新,本节中我们来看看如何管理数据完整性。在第二课中,你学习了如何处理值和约束。完成本课后,你能够识别主要的约束类型,解释约束在数据库中的工作原理,概述 MySQL 中的 ON DELETE CASCADE 和 ON UPDATE CASCADE 选项,并能在实验环境中证明你运用值和约束的能力。



以下是定义外键约束并级联操作的示例:
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE ON UPDATE CASCADE
);
🏗️ 第三课:修改表结构
接着,你进入了第三课,学习了如何更改表的结构。完成本课后,你现在能够在现有的数据库表中添加、删除和修改列及约束,使用 COPY TABLE 语法在表内和数据库之间复制数据。你也在实验中展示了修改表的能力,并通过额外资源学习了更多相关概念。
以下是添加列和复制表的语法示例:
-- 添加列
ALTER TABLE employees ADD COLUMN hire_date DATE;

-- 复制表结构及数据
CREATE TABLE new_table LIKE original_table;
INSERT INTO new_table SELECT * FROM original_table;


🔍 第四课:子查询
在第四课中,你探索了子查询的概念。完成本课后,你能够识别子查询并理解其语法,确定可以使用子查询的场景,并解释如何使用子查询来检索数据。你同样在实验环境中展示了运用子查询的能力。


以下是一个使用子查询的示例:
SELECT name FROM products WHERE category_id IN (SELECT id FROM categories WHERE name = 'Electronics');

👁️ 第五课:虚拟表(视图)
最后,在第五课中,你学习了关于虚拟表或视图的知识。完成本课后,你能够解释数据库中视图的概念,演示如何在数据库中创建、重命名和删除视图,识别在 MySQL 中使用视图的优势,并通过阅读材料获得了关于视图主题的额外知识。

以下是创建和删除视图的语法:
-- 创建视图
CREATE VIEW customer_summary AS SELECT customer_id, COUNT(*) AS order_count FROM orders GROUP BY customer_id;
-- 删除视图
DROP VIEW IF EXISTS customer_summary;


✅ 模块总结
本节课中我们一起学习了本模块的核心技能。完成本模块后,你现在应该能够:
- 更新数据。
- 处理值与约束。
- 更改表的结构。
- 运用子查询和虚拟表。
做得很好!我期待在下一个模块中继续指导你,在那里你将学习如何在 MySQL 中使用函数和存储过程。
入门 100:数据建模与管理小结 🎯
在本模块中,我们学习了数据建模的核心概念、数据库设计原则以及如何使用MySQL Workbench工具进行实践。现在,让我们一起来回顾本模块的关键知识点。
数据建模基础回顾 📊
上一节我们介绍了数据建模的基本概念,本节中我们来看看数据建模的三个层次。
数据模型展示了数据库系统的结构。数据建模分为三个不同层次。

以下是数据建模的三个层次:
- 概念数据模型:通过实体及其相互关系的可视化表示,呈现数据系统的抽象概览。
- 逻辑数据模型:识别每个实体的属性,并定义每个表的主键和外键。
- 物理数据模型:提供在数据库管理系统(DBMS)中实现内部模式所需的详细级别。




数据模型类型与数据库规范化 🔍
了解了数据建模的层次后,我们来看看有哪些具体的数据模型类型,以及如何通过规范化优化数据库设计。
数据库工程师可以使用多种类型的数据模型。我们回顾了它们的优缺点,以确定哪种模型最适合需求。
以下是几种常见的数据模型:
- 关系数据模型
- 实体关系模型
- 层次数据模型
- 面向对象模型
- 维度数据模型
我们还回顾了数据库规范化的主题。规范化是构建表结构以解决异常的过程,例如插入异常、更新异常和删除异常。
我们回顾了用于解决这些异常的三个规范化级别。

以下是数据库规范化的三个范式:
- 第一范式(1NF):专注于数据的原子性问题,确保每列都是不可再分的基本数据项。
- 第二范式(2NF):在满足1NF的基础上,消除非主属性对主键的部分函数依赖。
- 第三范式(3NF):在满足2NF的基础上,消除非主属性之间的传递依赖。



在本课中,我们还探讨了一个数据模型的示例。然后通过一个练习,展示了设计自己的数据库模型的新技能。
MySQL Workbench 工具实践 🛠️
掌握了理论之后,我们进入实践环节,学习如何使用MySQL Workbench这一强大工具。
本模块的第二课介绍了MySQL Workbench。MySQL Workbench是一个用于数据库建模和管理的统一可视化工具。它提供了一系列用于创建、编辑和管理数据库的有用功能。
作为对该工具的入门,我们学习了如何在自己的操作系统上下载和安装它。我们还了解了如何使用该工具创建新用户并建立到MySQL数据库的连接。

然后,我们探索了如何使用MySQL Workbench管理数据库。我们看到了如何使用该工具创建和导航数据库模式,并学习了如何用它来创建和查看表(包括虚拟表)以及查询数据。



MySQL Workbench 中的数据库建模 🧩


接下来,我们深入了解了MySQL Workbench中的数据库建模功能。
在MySQL Workbench中,可以创建新的数据库模式。还可以使用MySQL Workbench的正向工程功能构建数据模型图。此过程涉及在MySQL Workbench中创建数据模型,然后将其转换为可以在MySQL数据库系统中实现的SQL模式。


MySQL Workbench还可用于通过从现有数据库构建数据模型ER图来反向工程数据模型。可以打印模型、共享模型,或应用更改并使用正向工程功能将其推送到数据库。
然后,我们通过一个练习测试了新技能,在该练习中,我们被要求在MySQL Workbench中设计自己的数据库模型。
总结 📝


本节课中我们一起学习了数据建模和管理的基础知识。我们现在应该熟悉了数据建模的三个层次、多种数据模型类型、数据库规范化的三个范式,以及如何使用MySQL Workbench进行数据库的创建、管理和建模(包括正向与反向工程)。期待在下一个模块中继续指导大家深入学习高级数据建模。
入门 101:字符串函数 🧵
在本节课中,我们将学习MySQL中常用的字符串函数。字符串函数用于处理和操作文本数据,例如连接多个字符串、提取部分字符串或转换字母大小写。掌握这些函数对于从数据库中提取和格式化信息至关重要。
什么是字符串函数?
上一节我们介绍了课程目标,本节中我们来看看什么是字符串函数。
字符串函数用于操作字符串值。例如,将多个字符串连接在一起,或者从一个较长的字符串中提取出一段子字符串。
以下是几个常用字符串函数的例子:
- CONCAT 函数用于将多个字符串连接在一起。
- SUBSTRING 函数用于从主字符串中提取一段子字符串。
- UPPER 函数将字符串转换为大写。
- LOWER 函数将字符串转换为小写。
字符串函数的语法
了解了基本概念后,本节中我们来探索这些字符串函数在MySQL数据库中的具体语法。
CONCAT 函数语法
一个非常简单的连接函数示例如下:
SELECT CONCAT("字符串1", "字符串2") FROM 表名;
它以 SELECT 命令开始,后跟 CONCAT 函数。在括号内,包含需要连接的字符串值。确保字符串用双引号括起来,并用逗号分隔。然后使用 FROM 关键字指定包含数据的表名。你还可以使用 WHERE 子句来指定条件。
一个更复杂的 CONCAT 函数示例可能涉及从两个独立的表中提取字符串值。例如,M&G公司需要的数据位于 items 和 mg_orders 两个表中。他们可以在 SELECT 子句中传递参数,在 FROM 子句中指定所需的两个表,并在 WHERE 子句中指定条件,以便SQL从两个表的组合中筛选出所需数据。
SUBSTRING 函数语法
SUBSTRING 函数的语法类似,但括号内包含三个参数:
SUBSTRING(字符串, 起始索引, 长度)
第一个参数是字符串本身。下一个是起始索引,即子字符串必须开始的字符串位置。长度 参数指的是需要提取的字符串部分的长度。
UPPER 和 LOWER 函数语法
M&G公司经常需要将表中某一列的值转换为大写,将另一列的值转换为小写。以下是他们执行此任务的方法。

大写字符串函数以 SELECT 语句开始,后跟 UPPER 函数。在括号内,写入需要转换为大写的列名。最后,指示SQL要操作的目标表。
SELECT UPPER(列名) FROM 表名;
小写字符串函数非常相似。唯一的区别是括号内必须包含需要转换为小写的列名。
SELECT LOWER(列名) FROM 表名;
实践应用:M&G公司的库存审查
学习了基本语法后,本节中我们来看看M&G公司如何在MySQL数据库中使用字符串函数。
任务一:连接商品名称与库存数量
如前所述,M&G需要一份商品名称及其可用数量的列表,格式为“商品名称 - 订单数量”。商品详情在 items 表中,订单详情在 mg_orders 表中。
items 表在以下列中记录M&G库存的商品信息:item_id, name, cost。
mg_orders 表在以下列中记录交货数据:order_id, item_id, quantity, cost, order_date, delivery_date, order_status。
你可以使用 CONCAT 字符串函数从这些表中提取所需数据。
SELECT CONCAT(name, ‘ - ‘, quantity) AS ‘item_name - order_quantity‘
FROM items, mg_orders
WHERE items.item_id = mg_orders.item_id;
查询以 SELECT 命令开始,然后调用 CONCAT 函数并写上一对括号。在括号内,传递参数 name 和 quantity。这些是你的输出列的名称,分别代表 items 表和 mg_orders 表。然后在参数之间添加一个连字符“-”以组合它们。连字符使用一对单引号,并确保所有参数用逗号分隔。使用 FROM 关键字指定两个表。最后,使用 WHERE 子句指定一个条件,从两个表的组合中筛选所需数据。然后执行查询。MySQL将提取一个显示库存中每种商品总数量的表。
任务二:转换订单状态的大小写
下一个任务是检索 mg_orders 表的 order_status 列中的所有字符串值,分别以大写和小写形式显示。
你可以使用 UPPER 和 LOWER 字符串函数来操作 order_status 列中的字符串值。
SELECT UPPER(order_status) FROM mg_orders;
在你的 SELECT 查询中,调用 UPPER 函数并传入列名 order_status。然后使用 FROM 关键字指定 mg_orders 表。执行查询以检索所有大写值。
要检索所有小写值,只需再次键入相同的查询,但这次调用 LOWER 函数。
SELECT LOWER(order_status) FROM mg_orders;
再次执行查询以检索所有小写值。
任务三:提取客户名字
作为下一项任务的一部分,M&G正在审查一位客户的订单。他们需要从 clients 表中提取该客户的名字。
clients 表记录客户的关键信息,并将其存储在以下列中:client_id(所需客户的ID为1)、client_name、address 和 contact_number。
你可以使用 SUBSTRING 函数从表的 client_name 列值中提取字符串的相关部分,从而检索M&G所需的信息。
SELECT SUBSTRING(client_name, 1, 6) AS first_name
FROM clients
WHERE client_id = 1;
首先,编写一个 SELECT 语句,调用 SUBSTR 函数,后跟一对括号。然后将 client_name 列作为第一个参数传递给子字符串函数。将起始索引作为第二个参数传入,即字符串的第一个字母或字符(索引为1)。并将需要提取的字符串部分的长度作为第三个参数传入。客户的名字是“Kisen”,有六个字母长。所以“6”是我们的第三个参数。然后使用 FROM 关键字指定目标表。最后,添加 WHERE 子句,以客户ID等于1作为条件。运行查询以提取客户的名字。

总结
本节课中我们一起学习了MySQL的核心字符串函数。我们首先了解了CONCAT、SUBSTRING、UPPER和LOWER函数的基本概念与语法。随后,我们通过M&G公司的实际案例,逐步实践了如何使用这些函数来连接字符串、转换文本大小写以及提取子字符串,从而完成具体的数据库查询任务。掌握这些字符串函数,能够帮助你有效地处理和格式化数据库中的文本数据。
入门 102:日期函数 📅
在本节课中,我们将学习MySQL中的日期函数。我们将了解什么是日期函数,探索几个常用的日期函数及其语法,并通过一个实际案例来演示如何使用这些函数处理和操作数据库中的日期数据。
什么是日期函数?
上一节我们介绍了课程目标,本节中我们来看看什么是日期函数。
日期函数用于在MySQL数据库中提取和处理时间与日期值,并能以多种不同的格式返回结果。例如,M&G公司的员工经常使用日期函数来获取客户订单的关键时间和日期信息。
常见的日期函数
了解了日期函数的基本概念后,本节中我们来看看几个在MySQL中常用的日期函数。
以下是几个M&G公司常用的日期函数:
- CURRENT_DATE:此函数以“年-月-日”的格式返回当前日期。
- CURRENT_TIME:此函数以“时:分:秒”的格式返回当前时间。
- DATE_FORMAT:此函数用于根据给定的、在MySQL中有效的格式来格式化一个日期。
- DATEDIFF:此函数用于计算两个日期值之间相隔的天数。
日期函数的语法
我们已经认识了几个核心的日期函数,本节中我们来学习如何正确地书写它们的语法。
在大多数情况下,日期函数通过SELECT语句来调用。
要提取当前日期,语法如下:
SELECT CURRENT_DATE();
要提取当前时间,语法如下:
SELECT CURRENT_TIME();
然而,DATE_FORMAT和DATEDIFF函数的语法则稍微复杂一些。
要更改日期的显示格式,需要使用DATE_FORMAT函数。其基本语法结构是:
SELECT DATE_FORMAT(date, format);
其中,date是待格式化的日期,format是指定的格式字符串。例如,‘%M’代表完整的月份名称。

要计算两个日期之间的天数差,需要使用DATEDIFF函数。其基本语法结构是:
SELECT DATEDIFF(date1, date2);
此函数返回date1减去date2的天数结果。
实践应用:帮助M&G公司
现在我们已经掌握了日期函数的语法,本节中我们来看看如何运用这些知识来解决M&G公司的实际问题。
M&G公司需要完成一系列与时间和日期相关的任务。
任务一:提取当前日期和时间
要获取当前日期和时间,只需分别执行以下两个查询:
SELECT CURRENT_DATE();
SELECT CURRENT_TIME();
任务二:格式化日期,显示给定日期的月份名称
你可以使用DATE_FORMAT函数来完成此任务。以下是具体查询:
SELECT DATE_FORMAT(order_date, ‘%M’)
FROM mg_orders;
执行此查询将返回订单日期的完整月份名称。
任务三:计算最近订单的交付日期与订单日期之间的天数差
正如之前所了解的,DATEDIFF函数可以用于完成此任务。相关数据存储在mg_orders表中,该表包含delivery_date和order_date等列。
以下是完成该任务的查询语句:
SELECT DATEDIFF(delivery_date, order_date)
FROM mg_orders
WHERE delivery_date IS NOT NULL;
此查询首先计算交付日期与订单日期之间的天数差,然后通过WHERE子句过滤掉那些交付日期为NULL(即尚未交付)的记录。
执行查询后,就能得到最近订单从下单到交付所经历的天数。

总结

本节课中我们一起学习了MySQL的日期函数。我们首先了解了日期函数的定义和作用,然后学习了CURRENT_DATE、CURRENT_TIME、DATE_FORMAT和DATEDIFF这几个核心函数的语法。最后,我们通过帮助M&G公司解决三个实际任务,练习了如何运用这些函数来提取、格式化和计算数据库中的日期数据。现在,你应该能够使用常见的MySQL日期函数来有效地处理和操作数据了。
入门 103:比较函数 🔍
在本节课中,我们将学习 MySQL 中的比较函数。这些函数用于比较数据库中的值,例如找出最大值、最小值或检查空值。掌握这些函数能帮助你更有效地处理和筛选数据。
什么是比较函数?
MySQL 比较函数允许你在数据库中比较数值。例如,这些函数可用于确定最高值、最低值等。比较函数的优势在于它们能处理多种类型的值,包括数字、字符串和字符。
以下是几个常见的 MySQL 比较函数示例:
- GREATEST 函数用于找出最高值。
- LEAST 函数用于确定最低值。
- IS NULL 函数用作等号运算符的替代方案,用于测试值是否为空。
比较函数的语法
上一节我们介绍了比较函数的基本概念,本节中我们来看看它们的语法结构。
GREATEST 和 LEAST 函数
以下是针对仅包含数值的表格,找出最高和最低值的语法示例。
语法以 SELECT 命令开始,后跟所需列的名称(通常是包含主键或标识属性的列)。接着,输入 GREATEST 函数,括号内包含需要比较的列名。然后使用 AS 关键字和列别名(例如 highest),确保 SQL 在新表的该列下返回所需值。类似地使用 LEAST 函数。最后,指定要查询的表。
例如,M 和 G 可以使用以下语法提取销售数据,针对最近四个业务季度,找出每个季度的最高和最低值。
SELECT item_id,
GREATEST(Q1, Q2, Q3, Q4) AS highest,
LEAST(Q1, Q2, Q3, Q4) AS lowest
FROM sales_revenue;
IS NULL 函数
IS NULL 通常与 SELECT 命令一起使用,后跟所需列的名称。然后使用 FROM 关键字指定目标表。IS NULL 函数也可以与 WHERE 子句结合使用,该子句调用 IS NULL 函数并指定其必须检查的列。
SELECT *
FROM mg_order
WHERE delivery_date IS NULL;
在 M&G 数据库中的应用

现在你已经熟悉了比较函数的语法,让我们花点时间看看它们如何在 M&G 数据库中使用。
提取销售数据
如前所述,M&G 需要获取库存中每个物品在过去四个业务季度的销售数据。销售数据存储在 sales_revenue 表中,该表包含五列:item_id 列标识每个库存物品,以及四个季度各占一列。
M&G 首先需要找出每个物品在过去四个季度中的最高和最低收入。你可以使用 GREATEST 和 LEAST 比较函数来帮助他们,就像之前的语法示例一样。
以下是具体步骤:
- 以
SELECT命令开始,并将item_id列为第一列。 - 为找出带来最高收入的物品,调用
GREATEST函数,并将四个业务季度列作为参数传递。 - 创建别名
highest。 - 为
LEAST函数编写类似的语法行,并分配别名lowest。 - 最后,使用
FROM关键字指定sales_revenue表。
执行后,查询输出将显示每个物品在过去四个业务季度中的最高和最低销售值。例如,ID 为 1 的物品在销售高峰时价值 138,000 美元,在销售最低时期价值 60,000 美元。
筛选未交付订单
M&G 需要确定哪些最近订单尚未交付。交付数据保存在 mg_order 表中,该表包含七列:order_id、item_id、quantity、cost、order_date、delivery_date 和 order_status。这里主要关注 delivery_date 列。所有尚未交付的订单在该列中都有一个空值。
因此,你可以在此列上使用 IS NULL 函数,并结合 WHERE 子句来筛选这些订单。
以下是具体步骤:
- 像往常一样编写
SELECT语句,后跟一个星号*。 - 使用
FROM关键字指定目标表。 - 最后,编写
WHERE子句并调用IS NULL函数来检查delivery_date列。
执行后,查询返回值为 3;这是所有 delivery_date 列为空值的记录的真实值。

总结
本节课中我们一起学习了 MySQL 中的比较函数。我们了解了 GREATEST 和 LEAST 函数用于找出数据中的最大值和最小值,以及 IS NULL 函数用于检查空值。通过 M&G 数据库的实际示例,我们看到了这些函数如何应用于提取销售数据和筛选未交付订单。掌握这些函数将帮助你在数据库管理中更有效地处理和分析数据。
入门 104:控制流函数 📊
在本节课中,我们将学习MySQL中的控制流函数。控制流函数允许你根据条件评估结果,决定查询的执行路径。我们将重点介绍最常见的控制流函数——CASE函数,并通过一个实际案例演示如何使用它来区分盈利和亏损的商品。
什么是控制流函数?
控制流函数用于评估条件并决定查询的执行流程。在MySQL数据库中,最常用的控制流函数是CASE函数。CASE函数会遍历一组条件,并在满足第一个条件时返回相应的值。
CASE函数的工作原理
CASE函数包含在一个CASE块中,其运作方式类似于IF-THEN-ELSE语句。一旦找到为真的条件,它就返回结果。如果没有条件为真,则返回ELSE子句中指定的值。如果没有ELSE子句且没有条件为真,则返回NULL。
以下是CASE函数语句的完整语法:
SELECT column_name,
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
...
ELSE result
END AS alias_name
FROM table_name;

实际案例:区分盈利与亏损商品
M和G需要确定库存中哪些商品盈利,哪些商品亏损。他们可以使用控制流函数来完成这项任务。所需数据存储在sales_revenue表中,该表包含五列:item_id列用于标识库存中的每个商品,以及四个业务季度的单独列。
通过检查最低季度的值是否小于或等于25,000美元,M和G可以确定哪些商品盈利,哪些商品亏损。执行此任务的最简单方法是使用CASE控制流函数。
以下是执行此任务的步骤:
- 编写
SELECT语句并指定item_id列。 - 使用
CASE关键字开始CASE块。 - 在
CASE块中,使用WHEN和LEAST函数给出条件。 - 列出括号中的季度销售列。
- 使用小于或等于运算符。
- 使用
THEN指定条件为真时要显示的信息(例如“loss”)。 - 使用
ELSE关键字指定条件为假时要显示的信息(例如“profit”)。 - 使用
END关键字结束CASE块。 - 使用
AS关键字创建别名(例如profit_loss)。 - 使用
FROM关键字指定目标表(例如sales_revenue)。
执行查询后,结果显示商品1、4、5和6盈利,而商品2和3亏损。
总结

本节课我们一起学习了MySQL中的控制流函数,特别是CASE函数的使用。通过实际案例,我们了解了如何利用CASE函数根据条件评估结果,区分盈利和亏损的商品。掌握控制流函数将帮助你在编写SQL查询时更灵活地处理数据。
入门 105:MySQL存储过程 📚
在本节课中,我们将要学习MySQL中的存储过程。存储过程是一种将特定SQL查询保存为代码块的方法,可以在需要时随时调用,从而避免重复编写相同的SQL语句。通过本教程,你将理解存储过程的概念,并学会如何创建和删除简单的存储过程。
什么是存储过程? 🤔
上一节我们介绍了存储过程的基本概念,本节中我们来看看它的具体定义。
数据库工程师所说的“存储过程”,指的是一段可以存储在数据库中的代码或预编译查询。你可以使用 CALL 命令来调用或执行这段存储的代码。
使用存储过程有很多好处:
- 你的代码更加一致。
- 你的代码可以重复使用,无需反复编写相同的SQL语句。
- 你的代码也更容易使用和维护。
存储过程的语法 📝
理解了存储过程的概念后,本节中我们来探索其语法,以更好地理解它是如何工作的。
首先,要创建一个基本的存储过程,需要使用 CREATE PROCEDURE 命令。该命令后面必须跟上过程名称和一对括号,括号内包含参数列表。即使你的存储过程不包含任何参数,这对括号也是必需的。然后,根据需要编写过程逻辑。
例如,如果你的过程需要从表中选取所有数据,可以编写一个带有星号(*)的 SELECT 命令,后跟 FROM 关键字和目标表名。
当编写带有一个或多个参数的存储过程时,语法大致相同。关键区别在于,你必须在括号内包含所有必需的参数,然后再编写过程逻辑。
创建存储过程后,下一步就是调用它。要调用一个过程,可以使用 CALL 命令,后跟过程名称。请确保包含括号。
但是,当你不再需要一个存储过程时,如何从数据库中删除它呢?要删除存储过程,可以使用 DROP PROCEDURE 命令,后跟过程名称。在这种情况下,你不需要包含任何括号。

实践:创建与调用存储过程 🛠️
理论结合实践才能掌握知识。接下来,我们将通过一个具体案例来应用刚才学到的语法。
正如之前提到的,Ly Shrub 经常在其数据库中使用相同的查询。例如,他们经常需要查询数据库产品表中的产品列表,以便为客户查找商品或检查商店库存。然而,每次与产品表交互时,他们都需要重写相同的查询,这是一个耗时的过程。
现在,让我们运用关于存储过程的新知识来帮助他们创建一个可重用的查询。
Ly Shrub 需要创建一个存储过程,用于从其产品表中提取所有数据。该表存储了商店中所有产品的数据,分为三列:product_id 列、列出所有产品名称的 item 列,以及列出所有价格(四舍五入到两位小数)的 price 列。
以下是创建该存储过程的步骤:
- 使用
CREATE PROCEDURE命令,后跟过程名称。由于此过程的目的是返回所有产品的详细信息,我们可以将其命名为GetProductsDetails,然后加上括号。 - 此存储过程不需要任何参数,因此括号内可以留空。
- 编写一个
SELECT命令和星号(*)符号,指示MySQL提取所有数据。 - 最后,编写
FROM关键字并指定目标表products。
执行此查询后,新的过程 GetProductsDetails 就创建好了。Ly Shrub 现在可以调用此查询来从表中提取数据,而无需每次都重写新的 SELECT 语句。
要演示如何调用存储过程,只需编写以下 CALL 命令:CALL GetProductsDetails();。执行该过程后,将提取包含所有产品数据的结果集。
实践:带参数的存储过程 🔧
上一节我们创建了一个简单的无参数存储过程,本节中我们来看看如何创建和使用带参数的存储过程。
Ly Shrub 还经常编写查询来识别数据库中价格最低的产品,以便将这些商品添加到促销活动中。我们可以为此查询创建一个带有一个或多个参数的存储过程。
以下是创建带参数存储过程的步骤:
- 使用
CREATE PROCEDURE命令,后跟过程名称。我们可以将其命名为GetLowestPriceProducts。 - 在括号内,需要声明参数。例如,声明一个名为
lowest_price的整数类型参数。 - 编写一个
SELECT命令和星号(*)符号。 - 编写
FROM子句并指定目标表products。 - 在
FROM子句后,包含一个小于或等于运算符(<=),后跟参数名lowest_price。
在这个语句中,我们声明了一个整数数据类型的参数,必须将一个整数值传递到存储过程中。但请注意,此查询包含了参数,因此每次调用查询时,都需要指定存储过程必须处理的值。
例如,让我们通过键入 CALL 命令、存储过程名称 GetLowestPriceProducts 并在括号中放置值 50,来返回价格小于或等于50美元的产品数据。执行查询后,值 50 通过参数传递给存储过程,屏幕上会输出所有价格小于或等于50美元的产品列表。
删除存储过程 🗑️
学会了创建,自然也需要知道如何清理。本节中,我们将学习如何删除不再需要的存储过程。
最后,Ly Shrub 决定从他们的数据库中删除 GetProductsDetails 存储过程。要从数据库中删除存储过程,请键入 DROP PROCEDURE 命令和过程名称 GetProductsDetails。执行查询后,该存储过程就从数据库中删除了。
得益于存储过程的使用,Ly Shrub 现在可以更高效地在其数据库中执行查询。
总结 📋

本节课中我们一起学习了MySQL存储过程的核心知识。你现在应该能够展示对MySQL数据库中存储过程的理解,并且能够在MySQL中创建和删除简单的存储过程。
我们了解到,存储过程是一段可存储和重复调用的SQL代码块,它能提高代码的一致性、可重用性和可维护性。我们学习了使用 CREATE PROCEDURE 和 CALL 命令来创建和调用存储过程,也掌握了使用 DROP PROCEDURE 命令来删除存储过程。通过实践案例,我们进一步巩固了创建无参数和带参数存储过程的方法。
入门 106:函数与存储过程小结 🎯
在本节课中,我们将回顾并总结本模块的核心内容,即MySQL中的函数与存储过程。您将清晰地理解这两大概念的区别、用途以及基本使用方法。
恭喜您完成了本课程的第三个模块。现在,让我们花点时间回顾一下您在本模块课程中获得的关键技能。
第一课:MySQL函数 📊
在第一课中,您学习了MySQL中的函数。现在,您应该能够解释MySQL函数的概念,区分常见的MySQL函数类型,并在MySQL数据库中使用基本的MySQL函数。您还在实验和测验中展示了关于MySQL函数的知识和技能。



您所接触到的MySQL函数主要包括以下几种类型:

以下是本模块介绍的核心函数类别:

- 数值函数:用于聚合数据或执行数学运算。例如,
SUM()、AVG()。 - 字符串函数:对数据库中的字符串值进行操作。例如,
CONCAT()、SUBSTRING()。 - 日期函数:返回时间和日期信息。例如,
NOW()、DATE_ADD()。
您还探索了比较函数,并了解了如何使用它们来比较数据库中的值。例如,CASE WHEN ... THEN ... ELSE ... END。


最后,您学习了控制流函数如何用于评估条件并确定查询的执行路径。例如,IF() 函数。

第二课:MySQL存储过程 ⚙️
上一节我们介绍了各种函数,本节中我们来看看MySQL的另一个强大功能——存储过程。


在第二课中,您探索了存储过程。现在,您应该能够解释MySQL数据库中存储过程的概念,并在MySQL中创建和删除简单的存储过程。
您同样在实验环境中展示了相关技能。

总结 📝

完成了本模块的学习后,您现在应该能够使用函数和MySQL存储过程。出色的工作。
本节课中,我们一起学习了MySQL中函数与存储过程的核心概念。函数是预定义的操作,用于处理数据并返回结果;而存储过程则是存储在数据库中的一组SQL语句,可以被重复调用。掌握这两者将极大提升您管理和操作数据库的效率与灵活性。
入门 107:课程回顾 📚
在本节课中,我们将一起回顾整个课程的核心内容。您已经学习了关于MySQL数据库结构与管理的知识。现在,让我们花一些时间来总结您所学到的关键主题。
概述
本课程回顾将带您重温从MySQL入门到高级功能的各个模块。我们将依次回顾数据过滤、表连接、数据分组、数据库更新、视图以及函数和存储过程等重要概念。

第一模块:数据操作基础


在开篇课程中,您学习了MySQL的简介。您了解了数据库的基本概念,探索了Meta如何在日常工作中使用MySQL数据库,并学习了如何充分利用本课程内容以确保达成学习目标。
上一节我们介绍了课程概览,本节中我们来看看数据过滤。


数据过滤
您学习了如何使用逻辑运算符来过滤数据。
以下是本课学到的核心过滤方法:
- 使用
AND、OR、NOT、IN、BETWEEN和LIKE等逻辑运算符。 - 使用逻辑运算符组合多个条件。
- 识别通配符字符,并解释如何使用它们来过滤数据。
- 在一系列知识检查中展示了数据过滤的技能。


接下来,我们进入别名的概念与表连接的学习。
别名与表连接
您现在可以解释别名的概念,并在实验环境中演示其用法。


以下是关于表连接的核心内容:
- 概述什么是表连接。
- 解释不同类型的连接,例如内连接(
INNER JOIN)、左连接(LEFT JOIN)、右连接(RIGHT JOIN)和自连接(SELF JOIN)。 - 演示如何在MySQL数据库中连接表并使用联合运算符(
UNION)。 - 在完成视频学习和知识检查后,展示了相关技能。

在掌握了如何连接数据后,我们进一步学习如何对数据进行分组和聚合。

数据分组

您学习了如何对数据进行分组。

以下是数据分组的关键操作:
- 使用MySQL的
GROUP BY子句对行进行分组,并将其与聚合函数(如COUNT(),SUM(),AVG())结合使用。 - 演示如何使用MySQL的
HAVING子句来应用过滤条件。 - 使用
ANY和ALL运算符。 - 在实验环境中展示了数据分组的能力。
第二模块:数据库更新与视图

接下来,您开始了第二个模块的学习,探索了更新数据库和使用视图的不同技术。


首先,我们学习了如何插入和更新数据。
插入与更新数据
您现在可以使用 REPLACE 命令来更新和插入数据。

以下是关于数据完整性与修改的核心知识点:
- 识别主要的约束类型,如键约束、域约束和参照完整性约束。
- 解释这些约束如何运作。
- 使用
ALTER TABLE命令来添加、删除和修改列。 - 使用子查询。


随后,课程转向了数据库中一个非常实用的功能——视图。

MySQL数据库中的视图

您现在可以解释视图的概念。
以下是关于视图操作的要点:
- 在MySQL数据库中创建、重命名和删除视图。
- 识别使用视图的优势。
- 在一系列知识检查和非评分实验中展示了关于视图的知识和技能。
第三模块:函数与存储过程


在第三个模块中,您学习了函数和MySQL存储过程。
首先,我们介绍了各种类型的函数。

函数

您现在可以解释什么是函数,并识别不同类型的函数。
以下是各类函数及其用途:
- 使用数值函数(如
ROUND(),ABS())来聚合数据或执行数学运算。 - 使用字符串函数(如
CONCAT(),SUBSTRING())来操作字符串值。 - 使用日期函数(如
NOW(),DATE_ADD())提取关于时间和日期值的数据。 - 使用比较函数(如
GREATEST(),LEAST())来比较值。 - 部署控制流函数(如
IF(),CASE)来评估条件并确定执行路径。


在本模块的最后,我们探讨了存储过程的概念。
存储过程

您现在可以解释MySQL数据库中的存储过程是什么。
以下是关于存储过程的核心操作:
- 在MySQL中创建和删除简单的存储过程。


总结
本节课中,我们一起回顾了整个课程的学习路径。从MySQL基础和数据过滤开始,到表连接、数据分组,再到数据库更新、视图的运用,最后学习了函数和存储过程。您已经到达本课程回顾的终点,现在是时候在分级评估中尝试运用所学知识了。祝您好运!
入门 108:31_课程总结
在本节课中,我们将对Meta数据库工程师课程的核心内容进行回顾与总结,梳理您已掌握的关键技能,并展望后续的学习路径。
您已经完成了这门Meta数据库工程课程。您付出了辛勤的努力,并在此过程中掌握了许多新技能。您在数据库学习的道路上取得了巨大进步。

现在,您应该能够理解数据库结构并使用MySQL进行管理。您能够在实验项目中展示部分学习成果以及您的实践数据库技能。

🎯 课程核心技能回顾

完成本课程后,您现在应该能够:

- 筛选、连接与分组数据:使用SQL语句对数据进行精确查询和聚合分析。
- 插入与更新数据:在数据库中操作数据,并应用约束、子查询和视图来确保操作的准确性与效率。
- 部署函数与存储过程:在MySQL数据库中创建和使用自定义函数与存储过程,实现复杂的业务逻辑封装。
📊 评估所衡量的关键能力
在分级评估中,关键技能衡量了您展示以下MySQL核心知识的能力:
- 数据筛选、连接与分组。
- 解释与虚拟表、数据完整性和子查询相关的数据库概念。
- 展示您在函数和存储过程方面的实践经验。

🚀 后续步骤与展望
这门Meta数据库工程课程为您介绍了几个关键领域的初步知识。您可能意识到仍有更多内容需要学习。
如果您觉得本课程有帮助并希望探索更多,何不注册下一门课程?在每一门Meta数据库工程课程中,您都将持续发展您的技能。在最终的实验项目中,您将运用所学的一切知识,创建您自己功能完整的数据库系统。
无论您是刚起步的技术专业人士、学生还是业务用户,本课程及其项目都能证明您对数据库系统价值和能力的理解。
实验项目通过实际应用来巩固您的能力。该实验还有另一个重要益处:这意味着您将拥有一个完全可以运行的数据库,可以将其纳入您的作品集中。
这有助于向潜在雇主展示您的技能。它不仅向雇主表明您具有自我驱动力和创新能力,也充分说明了您作为个人以及您新获得的知识。
一旦您完成了所有课程,您将获得Meta数据库工程认证。根据您的目标,此认证也可作为通往其他基于角色的Meta认证的进阶途径。您可以选择深入学习高级角色认证,或在获得此认证后学习其他基础课程。

Meta认证为您提供了全球认可且受行业认可的技术技能证明。
感谢您!很高兴能与您一同踏上这段探索之旅。祝您未来一切顺利!
入门 109:高级MySQL主题简介 🚀
在本课程中,我们将学习高级MySQL主题。我们将探索如何通过函数、存储过程、触发器和优化技术来提升数据库的功能与性能,并了解如何在MySQL中进行数据分析。
模块一:函数、存储过程与触发器 ⚙️
上一节我们介绍了课程概述,本节中我们来看看第一个核心模块。你将学习如何在MySQL中创建和使用函数、存储过程,以及如何利用触发器自动化任务。
函数与存储过程
以下是关于创建和使用函数与存储过程的核心内容:
- 你将学习如何创建并使用函数,以及基础与复杂的存储过程。这使你能够复用或调用代码块来执行特定操作。
- 你将学习如何利用变量和参数,在MySQL中创建更复杂的存储函数和过程。
- 当MySQL的内置函数无法满足项目需求时,你将学习如何开发用户自定义函数。
触发器与计划事件
接下来,我们将学习如何利用触发器自动化数据库任务。
以下是关于触发器和计划事件的具体内容:
- 你将探索不同类型的MySQL触发器,例如插入、更新和删除触发器,并学习如何使用每种类型。
- 你还会理解如何利用计划事件,以确保数据库任务和事件在特定时间完成。
模块二:数据库优化核心规则 📈
上一模块我们介绍了代码复用与自动化,本节中我们将聚焦于数据库性能的核心——优化。
你将理解数据库优化的概念及其为MySQL数据库带来的优势。
以下是优化数据库查询语句的技术:
- 你将学习优化数据库SELECT语句的技术,使其快速高效执行。例如,仅选择所需列或避免使用复杂函数。
- 你还将学习如何在MySQL中使用索引,以加速数据检索查询的性能。
进阶优化技术
接下来,我们将探索更多进阶的优化技术。
以下是本部分涵盖的关键技术点:
- 你将首先学习如何使用MySQL事务语句来管理数据库事务。
- 你将发现如何利用公共表表达式,通过将复杂SQL查询编译成单个代码块来管理它们。
- 你将学习如何使用预处理语句,以限制MySQL必须编译和解析代码的次数。
- 你将了解如何使用JSON数据类型与MySQL数据库进行交互。

模块三:MySQL中的数据洞察 🔍
上一节我们探讨了性能优化,本节中我们将视角转向数据价值挖掘。你将在第三个模块中探索MySQL中的数据分析概念。
首先,你将理解数据库分析与MySQL之间的关系。
以下是关于数据分析基础的内容:
- 你将了解如何利用数据分析过程中收集的数据,将其转化为可为未来决策提供依据的有用信息。
- 你还将探索可以在数据库内执行的不同类型的数据分析。
- 之后,你将学习MySQL与数据分析之间的关系,包括MySQL作为数据分析工具的优势与局限性。
使用SQL进行数据分析

接下来,我们将学习如何具体执行分析。
以下是使用SQL查询进行数据分析的方法:
- 在本模块的第二课,你将学习如何使用SQL查询(如连接、子查询和视图)在MySQL中执行数据分析。
- 接着,你将探索如何在MySQL中模拟全外连接,以提取两个表中的所有记录,包括不匹配的记录。
- 最后,你将学习如何使用连接方法从多个表中提取数据。
实践与评估 🧪
在整个学习过程中,你将遇到许多旨在测试你技能和知识的活动。
以下是课程中包含的实践环节:
- 这些活动包括实验练习、知识检查和模块测验。
- 在最后一个模块中,你将有机会在实验项目中展示部分所学知识及你的实践数据库技能。
- 你还将在一次分级评估中展示你对这些主题的掌握程度。


本节课中,我们一起学习了高级MySQL主题的课程大纲。我们了解到,后续内容将涵盖函数与存储过程、数据库优化技术以及数据分析方法,并通过实践活动来巩固所学知识。现在,让我们开始深入学习吧。
入门 110:MySQL中的函数和存储过程 📚
在本节课中,我们将要学习MySQL中函数和存储过程的基本概念、它们的优势以及关键区别。我们将通过简单的例子来理解如何创建和使用它们,以便在数据库项目中重用代码,提高效率和可维护性。
概述 📖
在之前的课程中,你已经了解到可以通过使用函数和存储过程在数据库项目中重用代码。这些方法可以避免重复输入相同的代码。接下来,我们将回顾函数和存储过程的基础知识,并学习它们的好处和主要区别。
代码封装与重用 🔄
正如你刚刚学到的,创建存储过程和函数的主要目的是将代码封装在函数或过程的主体中。这意味着,你无需重复输入相同的代码,只需通过调用标识符名称来执行特定的操作。
除了避免重复,函数和存储过程还有其他好处。它们使代码更加一致、更有组织,并引入了可重用性,从而使代码更易于使用和维护。
存储过程示例 🛠️
让我们来看一些具体的例子。之前提到,Luc Shrub公司经常使用存储过程来查询产品表中的库存数据。这样,他们每次检查库存时就不必重复输入相同的代码。
以下是他们实现此目标的方式:首先,他们使用 CREATE PROCEDURE 命令将查询创建为存储过程,后跟过程名称和所需的逻辑。然后,他们使用 CALL 命令调用此过程,从数据库中提取所需的数据。如果表中没有数据,则函数返回空值。
CREATE PROCEDURE CheckStock()
BEGIN
SELECT * FROM products WHERE stock_quantity < 10;
END;
CALL CheckStock();
函数示例 🔢
现在,我们来看一个函数的例子。MOD 函数可用于计算两个数值 X 和 Y 相除的余数。例如,计算 7 除以 5 的余数。要得到结果,可以在 SELECT 语句中使用标识符名称调用该函数。在这个例子中,结果是 2。
SELECT MOD(7, 5);

记住,与存储过程不同,函数总是返回一个值。例如,你可能还记得上一个课程中的场景,M 和 G 使用一个函数来确定每位客户在其业务上的平均消费金额。这个函数总是返回值,因为它专门针对花费了钱的客户。
参数的区别 ⚙️
接下来,我们花点时间探讨函数和存储过程之间的一个关键区别:参数。函数只能有输入参数,而存储过程既可以有输入参数,也可以有输出参数。
函数和过程都可以在其各自的代码中接受值。换句话说,它们都接受输入。但只有过程可以通过使用输出参数再次将值传递出去。如果你觉得这个概念令人困惑,不用担心。在后续的视频中,你将学到更多关于参数的知识。

选择使用场景 🤔
你可以根据需要创建任意数量的函数和过程。只需确保知道何时使用其中一个而不是另一个。例如,当你需要返回一个特定值时,函数是最佳选择,比如在 SQL 语句中或在另一个函数内部。存储过程主要用于处理、操作和修改数据。
总结 📝
本节课中,我们一起学习了函数和存储过程是完成重复性任务的有效代码重用方式。尽管它们带来了许多好处,但了解何时使用其中一个而不是另一个非常重要。通过封装代码,我们可以提高工作效率,并使数据库项目更加易于维护。

在接下来的课程中,我们将更深入地探讨这些概念。
入门 111:变量和参数 🧩
在本节课中,我们将要学习如何在MySQL中使用变量和参数来构建更复杂的存储过程和函数。变量和参数是增强SQL代码灵活性和可重用性的关键工具。
概述
您可能已经从之前的课程中熟悉了基础的存储过程和函数。然而,MySQL也提供了更复杂的存储过程和函数,它们依赖于变量和参数。接下来,您将学习如何使用变量和参数来构建高级的函数和过程。
Lucky Shrub园艺中心需要为其数据库创建几个重复但复杂的查询。他们可以使用变量和参数来创建这些查询。让我们跟随他们的流程,了解其工作原理。
变量
首先,您需要了解在MySQL上下文中“变量”这个术语的含义。
一个变量代表一个存储值的占位符。这个值有时可能会根据查询的需要而改变。基本上,变量用于在SQL语句之间,或在过程与SQL语句之间传递值。
在MySQL中,变量有两种不同的使用方式。您可以在存储过程内部或外部,以及在SELECT语句内部或外部创建变量。
变量的语法

在MySQL中,用户定义的变量由字母数字字符组成。您只需键入@符号,后跟您想为变量命名的名称。然后使用等号运算符为变量赋值。确保以分号结束语法。

代码示例:
@variable_name = value;
在存储过程中创建变量
但是,如何在存储过程内部或外部创建变量呢?为此,您需要在语法中使用SET命令。SET命令用于在存储过程中为变量赋值。
让我们花点时间看看SET命令的实际应用。在存储过程内部或外部创建变量时,键入SET命令,后跟变量名称。然后为变量赋值。
示例:
Lucky Shrub的数据库中有一个记录业务订单的orders表。他们可以创建并使用一个名为orderID的变量,来定位orderID号为3的记录。现在,他们可以使用此变量来删除、更新或查询该记录。
或者,您可以使用DECLARE命令在存储过程内部创建变量。在这种情况下,您键入变量名时不带@符号。然后为变量分配相关的数据类型和默认值。
Lucky Shrub可以使用此方法创建一个名为minimum_order_cost的变量。预期该变量存储的值等于Lucky Shrub数据库中最低订单的成本。
代码示例:
DECLARE minimum_order_cost DECIMAL(10,2) DEFAULT 0.00;
在SELECT语句中创建变量

正如您之前所学,您也可以在SELECT语句中创建变量。然而,在SELECT语句中为变量赋值时,需要使用赋值运算符语法。这会指示MySQL为变量赋值。标准的等号运算符仅检查一个值是否等于另一个值。
因此,键入SELECT命令,然后是变量名。然后使用赋值运算符为变量赋值。
示例:
Lucky Shrub可以创建一个max_order变量,用于从其orders表中检索最昂贵的订单。
代码示例:
SELECT @max_order := MAX(Cost) FROM orders;

然后,他们可以通过键入SELECT @max_order;来访问该值。输出将显示最昂贵的订单。
也可以在SELECT语句内部创建变量,并为其分配从函数返回的值。您只需键入SELECT命令,后跟函数,然后是INTO关键字和变量名。最后,键入FROM关键字和要从中提取值的表名。
Lucky Shrub可以使用此方法创建一个名为average_cost的变量,该变量返回其orders表中项目的平均成本。
代码示例:
SELECT AVG(Cost) INTO @average_cost FROM orders;
参数
现在您已经熟悉了变量,让我们继续探讨参数这个主题。
参数用于从外部向函数或过程传递参数或值。在MySQL中,函数只接受输入参数。但是,在存储过程中可以声明三种不同类型的参数:IN、OUT和INOUT参数。
让我们花点时间探讨每种参数的工作原理。
IN参数
IN参数是默认参数。它用于向存储过程传递参数或值。要使用此参数类型,在CREATE PROCEDURE命令和过程名之后,在一对括号内键入IN关键字。如果您不指定关键字,则MySQL默认使用IN。然后在括号内,添加另一对包含参数名的括号。接着添加一个SELECT语句来概述查询的逻辑。
示例:
Lucky Shrub可以创建一个过程,用于计算每位员工工资的20%用于税务目的。然后,他们可以针对特定的工资值调用该过程。这将把工资传递给该过程,并返回应缴税额。
代码示例:
CREATE PROCEDURE CalculateTax(IN salary DECIMAL(10,2))
BEGIN
SELECT salary * 0.20 AS tax_due;
END;
OUT参数
接下来,让我们研究OUT参数。OUT参数用于将值传递给过程外部的变量。
以下是一个示例,Lucky Shrub使用一个名为GetLowestCost的过程来识别其orders表中成本最低的订单。他们使用OUT关键字将值传递到参数外部。
代码示例:
CREATE PROCEDURE GetLowestCost(OUT lowest_cost DECIMAL(10,2))
BEGIN
SELECT MIN(Cost) INTO lowest_cost FROM orders;
END;
下一步是调用该过程。过程的值随后可以以变量的形式存储在一对括号内。要显示变量存储的值,只需使用SELECT语句返回输出。
INOUT参数
最后是INOUT参数。这是两种参数的组合。它用于向过程传递一个参数,然后将新值传递回外部。因此,它实际上是一个IN和一个OUT参数。
示例:
您可以使用INOUT关键字和一个数字变量创建一个名为SquareANumber的过程,该过程返回特定数字的平方值。该过程通过a_number参数期望一个输入数字。它将此数字乘以自身,然后将结果再次返回到同一个a_number参数。
代码示例:
CREATE PROCEDURE SquareANumber(INOUT a_number INT)
BEGIN
SET a_number = a_number * a_number;
END;
然后,您可以设置一个名为x_number的变量,其值为5,并使用x_number变量值调用该过程。该过程通过参数传递值,然后执行计算,并通过参数将结果返回。
使用SELECT语句输出变量值。

总结
本节课中,我们一起学习了如何在MySQL中创建和使用变量与参数。您了解了变量的定义、创建方式(包括在存储过程内外及SELECT语句中),以及三种不同类型的参数(IN、OUT、INOUT)的用途和语法。通过使用这些工具,您可以构建出更灵活、更强大的存储过程和函数,以应对复杂的数据库查询需求。
入门 112:开发自定义函数 🛠️
在本节课中,我们将学习如何在MySQL中创建用户自定义函数。我们将了解其基本概念、语法结构,并通过一个实际案例来演示如何开发一个满足特定业务需求的函数。
概述
您可能已经熟悉MySQL的内置函数。但如果这些内置函数都无法满足项目需求,您完全可以开发自己的用户自定义函数。本节视频将解释用户自定义函数是什么,并指导您如何创建自己的函数。
什么是用户自定义函数? 🤔
您可能已经熟悉MySQL的内置函数,例如字符串或数值函数。用户自定义函数是为了执行那些无法通过内置函数完成的操作而创建的。用户需要编写代码来实现特定的方程或公式,以完成任务并返回结果。
让我们来分解这个过程:数据库工程师创建自己的代码,代码执行特定功能,然后函数返回所需的结果。
创建函数的基本语法
要在MySQL中构建函数,您可以使用 CREATE FUNCTION 命令,配合 RETURNS 子句和 RETURN 命令。这些命令和子句用于指定函数返回的数据类型和值。
以下是该语法的工作原理:
- 以
CREATE FUNCTION命令开始语句。 - 为您的函数分配一个名称。
- 在函数名后加上括号和参数。括号是必需的,但参数并非总是需要。
- 指定返回数据类型,后跟关键字
DETERMINISTIC。DETERMINISTIC意味着对于相同的输入参数,函数总是返回相同的结果。例如,如果一个求和函数被定义为确定性的,那么对于相加的数字,它总是返回相同的结果。 - 最后,使用
RETURN关键字实现逻辑。
让我们看看Lucky Shrub如何利用用户自定义函数。
案例:创建基础折扣函数
Lucky Shrub正在进行促销,对选定商品提供10%的折扣。但为每笔交易的每个商品重复编写相同的计算语句非常耗时。因此,Lucky Shrub需要您创建一个用户自定义函数,以便在需要计算折扣时调用。
Lucky Shrub可以使用以下语法创建一个名为 FindTotalCost 的函数:
CREATE FUNCTION FindTotalCost(cost DECIMAL(10,2)) RETURNS DECIMAL(10,2) DETERMINISTIC
RETURN cost - (cost * 0.10);
cost参数具有十进制数据类型,用于传递用户输入的成本值。RETURNS子句将函数的返回类型定义为具有5位数字的十进制数。RETURN命令计算并返回扣除10%后的最终成本。
现在,每当Lucky Shrub需要确定商品的销售价格时,他们只需在 SELECT 语句中调用该函数,并在括号内填入当前价格即可。
开发更复杂的函数
上一节我们介绍了基础的自定义函数。本节中,我们来看看如何创建一个更复杂的函数,实现阶梯式折扣。
假设Lucky Shrub希望为消费100美元或以上的顾客提供10%的折扣,为消费500美元或以上的顾客提供20%的折扣。
第一步是使用 DELIMITER 命令,将整个函数作为一个复合语句进行编译。这需要使用 BEGIN 和 END 关键字。输入以下命令将分隔符从默认的分号更改为双斜杠:
DELIMITER //

接下来,使用 CREATE FUNCTION 命令并命名您的函数为 GetTotalCost。
以下是创建该函数的完整代码:
CREATE FUNCTION GetTotalCost(cost DECIMAL(10,2)) RETURNS DECIMAL(10,2) DETERMINISTIC
BEGIN
DECLARE discount DECIMAL(10,2);
IF cost >= 500 THEN
SET discount = cost * 0.20;
ELSEIF cost >= 100 THEN
SET discount = cost * 0.10;
ELSE
SET discount = 0;
END IF;
RETURN cost - discount;
END //
- 函数包含一个
cost参数,用于传递用户输入的成本值。 RETURNS子句定义了函数的返回类型。- 函数被定义为
DETERMINISTIC。 - 使用
BEGIN和END关键字来确定函数体。 - 在函数体内,使用
IF...ELSE语句来检查输入成本并扣除相应的折扣金额。 - 最后,使用
RETURN命令计算扣除折扣后的最终成本。
输入完成后,创建新函数。然后将分隔符改回默认的分号,以便正常使用MySQL:
DELIMITER ;
测试与删除函数

现在,是时候使用 SELECT 语句来测试函数了。假设一位顾客刚刚进行了一笔价值500美元的购买,Lucky Shrub需要确定应用的折扣。
输入一个 SELECT 命令,后跟函数名以及在括号内的购买价值:
SELECT GetTotalCost(500);
执行该函数,输出结果是400美元。这意味着在应用20%的折扣后,这位顾客的购买现在价值400美元。
如果您想删除这个函数,只需使用 DROP FUNCTION 语句,后跟函数名:
DROP FUNCTION GetTotalCost;
执行后,函数即被删除。
总结
在本节课中,我们一起学习了如何在MySQL中创建用户自定义函数。我们了解了其基本概念和语法结构,并通过Lucky Shrub的案例,实践了如何开发一个基础折扣函数和一个更复杂的阶梯折扣函数。现在,Lucky Shrub可以根据需要轻松地将折扣应用于顾客的购买,而您也掌握了为特定项目创建自定义函数的方法。
入门 113:创建复杂存储过程 🛠️
在本节课中,我们将学习如何创建比基础存储过程更复杂的存储过程。这类过程通常包含多个SQL语句,并能通过输出参数返回结果。我们将通过一个帮助Lucky Shrub公司分析产品价格的实例来掌握其创建与调用方法。
概述
上一节我们介绍了基础存储过程的创建。本节中,我们来看看如何构建一个包含多个语句、并能通过OUT参数返回数据的复杂存储过程。我们将帮助Lucky Shrub公司统计其产品数据库中价格低于和高于50美元的商品数量,为即将到来的促销活动做准备。
步骤详解
以下是创建复杂存储过程的具体步骤。
1. 更改语句分隔符
由于存储过程体包含多个以分号结尾的SQL语句,我们需要临时更改MySQL的语句分隔符,以便MySQL能将整个BEGIN...END代码块视为一个复合语句来编译。
输入以下命令,将默认的分号分隔符改为双斜杠//:
DELIMITER //

2. 创建存储过程
接下来,使用CREATE PROCEDURE命令来定义存储过程。我们需要为其指定名称、定义输出参数,并编写过程体逻辑。
输入以下代码创建名为GetProductSummary的存储过程:
CREATE PROCEDURE GetProductSummary (
OUT low_price_count INT,
OUT high_price_count INT
)
BEGIN
-- 统计价格低于50美元的产品数量
SELECT COUNT(ProductID) INTO low_price_count FROM products WHERE Price < 50;
-- 统计价格高于50美元的产品数量
SELECT COUNT(ProductID) INTO high_price_count FROM products WHERE Price > 50;
END //
代码解释:
OUT low_price_count INT:定义一个名为low_price_count的整数型输出参数,用于接收低价产品数量。SELECT ... INTO ...:将查询结果直接存入指定的输出参数变量中。
3. 恢复默认分隔符
存储过程创建完成后,需要将分隔符改回默认的分号,以便后续正常执行其他SQL语句。
DELIMITER ;
4. 调用存储过程并查看结果
现在,我们可以执行这个存储过程并获取其输出的数据了。
首先,使用CALL语句调用过程。调用时需要提供两个变量来接收输出参数的结果。
CALL GetProductSummary(@total_low_price_products, @total_high_price_products);
代码解释:
@total_low_price_products和@total_high_price_products是用户变量,用于接收存储过程计算出的两个数量值。
过程执行完毕后,数据已存储在上述变量中。我们可以通过一个简单的SELECT语句来查看结果。
SELECT @total_low_price_products, @total_high_price_products;
执行此查询后,输出结果将分别显示价格低于50美元和高于50美元的产品总数。Lucky Shrub公司便获得了策划促销活动所需的关键数据。
总结


本节课中我们一起学习了如何创建和使用复杂的存储过程。关键步骤包括:使用DELIMITER临时更改分隔符、使用CREATE PROCEDURE定义包含OUT参数的过程体、以及最后通过CALL调用并用SELECT查看结果。通过这个实例,你掌握了将多个查询逻辑封装在一个可重复调用的数据库对象中的方法,这能极大地提高数据操作的效率和代码的复用性。
入门 114:MySQL触发器是什么 🚀
在本节课中,我们将要学习MySQL触发器的基本概念、创建与删除语法,并通过一个实际案例了解其应用场景。
概述
作为数据库工程师,您经常需要在特定事件发生时自动执行某些操作,例如在表中插入、更新或删除数据时。如何确保这些操作自动发生,而无需每次调用时重写代码?您可以通过使用MySQL触发器来实现。本节将介绍什么是MySQL触发器,以及如何编写和使用它们。
什么是MySQL触发器?
MySQL触发器是一种以存储程序形式存在的一组操作。当特定事件发生时,这组操作会被自动调用。这些事件包括在MySQL数据库表中插入、更新和删除数据。
在使用触发器之前,您需要创建它。通常,在触发器完成其使命后,您也需要删除或丢弃它。
创建与删除触发器的语法

上一节我们介绍了触发器的基本概念,本节中我们来看看如何创建和删除触发器。
创建触发器
创建触发器使用CREATE TRIGGER语句。
CREATE TRIGGER trigger_name
trigger_time trigger_event
ON table_name FOR EACH ROW
BEGIN
-- 触发器逻辑
END;
以下是创建触发器语句各部分的说明:
CREATE TRIGGER:这是创建触发器的关键字。trigger_name:触发器的名称。由于触发器通常是用户定义的,您可以创建自定义名称,但需确保其在数据库中是唯一的。trigger_time:定义触发器执行的时间,例如在操作之前 (BEFORE) 或之后 (AFTER)。trigger_event:定义触发触发器的事件,例如插入 (INSERT)、更新 (UPDATE) 或删除 (DELETE)。ON table_name:指定触发器关联的表。FOR EACH ROW:指定触发器应如何应用于表,通常表示对受影响的每一行数据执行。BEGIN ... END:如果触发器逻辑包含多个语句,则必须将它们包含在BEGIN和END块中。
执行该语句即可创建触发器。
删除触发器
要删除已创建的触发器,可以使用DROP TRIGGER命令。
DROP TRIGGER IF EXISTS schema_name.trigger_name;
以下是删除触发器语句各部分的说明:
DROP TRIGGER:这是删除触发器的关键字。IF EXISTS:此子句确保仅当MySQL能在数据库中找到该触发器时,删除命令才会执行。如果没有此子句而尝试删除不存在的触发器,MySQL将返回错误。schema_name.trigger_name:使用点符号标识触发器所属的数据库(模式)和触发器名称。这确保MySQL仅从指定模式中删除触发器,而不是整个数据库。
执行该语句即可删除触发器。
重要提示:如果您从数据库中删除或丢弃一个表,那么MySQL会自动删除与该表关联的所有触发器。

触发器应用案例:Lucky Shrub折扣审批
了解了基本语法后,我们来看看Lucky Shrub的销售团队如何应用触发器。
Lucky Shrub的销售团队正在为产品添加折扣。然而,任何超过25%的折扣都必须由经理审核。这意味着销售团队需要在数据库中添加一个触发器,当员工尝试为商品添加超过25%的折扣时,该触发器会标记这些商品,然后必须向经理发送审批请求。
Lucky Shrub可以使用CREATE TRIGGER命令来创建此触发器。他们可以将触发器命名为approval_request。然后,他们指定触发器类型为AFTER UPDATE,以便在表内发生更新操作后执行触发器逻辑。最后,他们将触发器逻辑放在BEGIN ... END块中。
触发器的其他优势

除了自动执行业务逻辑,触发器还有以下好处:
以下是触发器的一些主要优势:
- 维护审计跟踪:触发器可用于记录数据库中所做的更改,每次发生更改时都会向数据库插入一条记录,从而维护审计跟踪。
- 替代约束:触发器是约束的一种替代方案,通过确保所有数据按要求更新,有助于维护数据完整性。
- 自动执行任务:触发器可用于在数据库表上发生指定操作时自动执行任务。

总结
本节课中,我们一起学习了MySQL触发器的基本概念。您现在应该知道什么是MySQL触发器,并理解了在数据库中创建和删除它们的基础知识。触发器是自动化数据库操作、维护数据完整性和记录变更的强大工具。
入门 115:MySQL触发器类型 🚀
在本节课中,我们将要学习MySQL触发器的不同类型。触发器是一组在特定事件发生时自动执行的动作。我们将探讨如何通过不同类型的触发器来控制其执行时机和行为,并了解每种触发器的适用场景。
触发器的主要分类:行级与语句级
上一节我们介绍了触发器的基本概念,本节中我们来看看触发器的两种主要分类:行级触发器和语句级触发器。


以下是这两种触发器的核心区别:
- 行级触发器:对表中每一行被插入、更新或删除的数据都会调用一次。例如,如果向表中插入100行数据,行级触发器会被调用100次。
- 语句级触发器:对每个操作语句只调用一次,无论该语句影响了多少行数据。例如,一个INSERT语句可能插入100行数据,但触发器只激活一次。



了解这两种类型很重要。然而,MySQL只支持行级触发器,因此本节课我们将重点讨论行级触发器。

触发时机:BEFORE 与 AFTER 触发器
我们已经知道触发器通常用于执行插入、更新和删除这三种操作。那么,如何确定触发器是在操作之前还是之后执行呢?这取决于触发器的触发时机,可以分为BEFORE触发器和AFTER触发器。




以下是这两个关键字的含义:

BEFORE:表示触发器必须在对表行执行任何操作之前被调用。AFTER:表示触发器在对每一行执行操作之后被调用。

MySQL触发器的组合类型与语法
通过将 BEFORE/AFTER 修饰符与 INSERT、UPDATE、DELETE 关键字组合,可以创建不同类型的触发器。


以下是可创建的触发器类型示例:
BEFORE INSERT:在表的插入事件发生前自动调用。AFTER INSERT:在插入事件发生后调用。BEFORE UPDATE:在更新事件发生前调用。AFTER UPDATE:在更新事件发生后调用。BEFORE DELETE:在表中数据被删除前调用。AFTER DELETE:在数据被删除后调用。


每种触发器的语法大体相同。以下是创建触发器的基本结构:




CREATE TRIGGER trigger_name
[BEFORE | AFTER] [INSERT | UPDATE | DELETE]
ON table_name
FOR EACH ROW
BEGIN
-- 触发器逻辑(一个或多个SQL语句)
END;

让我们通过Lucky Shrub公司的案例来具体理解。他们需要为订单表(orders)添加一条新约束:OrderQuantity(订单数量)字段不能插入负值。




他们可以使用一个 BEFORE INSERT 触发器来实现:
CREATE TRIGGER OrderQuantityCheck
BEFORE INSERT
ON Orders
FOR EACH ROW
BEGIN
IF NEW.OrderQuantity < 0 THEN
SET NEW.OrderQuantity = 0;
END IF;
END;
现在,每次向表中插入新行时,BEFORE INSERT 触发器都会在插入新值之前执行所需的检查与修正操作。


更多触发器应用示例


接下来,我们看看Lucky Shrub公司可以使用的其他几种触发器类型。
他们希望维护一个对订单表所有更新的审计追踪。使用 AFTER INSERT 触发器,他们可以在每次插入新订单时,将一条日志信息从订单表发送到审计表(audits)。
此外,公司还需要创建一个日志,记录从订单表中删除订单记录的日期和时间。他们可以使用 AFTER DELETE 触发器来完成此任务。在记录被删除后,该触发器会在日志表中插入一条包含日期和时间的记录。






总结 📝
本节课中我们一起学习了MySQL触发器的不同类型。我们了解到,虽然SQL理论上存在行级和语句级触发器,但MySQL仅支持行级触发器。我们重点探讨了通过组合 BEFORE/AFTER 与 INSERT/UPDATE/DELETE 关键字来定义触发器执行时机的方法,并通过Lucky Shrub的实例学习了创建 BEFORE INSERT 触发器的基本语法及其应用场景。我们还简要了解了 AFTER INSERT 和 AFTER DELETE 触发器的潜在用途。掌握这些触发器类型是构建自动化、健壮数据库规则的基础。
入门 116:在MySQL中创建和删除触发器 🛠️
在本节课中,我们将学习如何在MySQL数据库中创建和删除触发器。触发器是一种特殊的存储过程,它会在指定的数据库事件(如插入、更新或删除)发生时自动执行。通过本教程,你将掌握创建BEFORE INSERT触发器来验证数据,以及如何安全地移除不再需要的触发器。

触发器应用场景示例
上一节我们介绍了MySQL触发器的基本概念和类型,本节中我们来看看如何在具体业务场景中应用触发器。
以Lucky Shrub公司的数据库为例。该公司的数据库中包含一个orders表,该表有多个列,用于记录每笔订单的信息。Lucky Shrub希望确保在记录新订单时,quantity(数量)列不会被插入负值。任何遇到的负值都必须被设置为默认值0。他们可以通过创建一个BEFORE INSERT触发器来完成此任务。

创建触发器语法解析
以下是创建一个触发器的基本语法结构。
CREATE TRIGGER trigger_name
trigger_time trigger_event
ON table_name FOR EACH ROW
BEGIN
-- 触发器逻辑(一个或多个SQL语句)
END;
让我们分解这个语法,并应用到Lucky Shrub的例子中。
CREATE TRIGGER命令:这是定义新触发器的起始关键字。- 触发器名称:在此例中,触发器被命名为
order_quantity_check。确保触发器名称在数据库中是唯一的。 - 触发器类型与时机:接下来,指定触发器的类型和调用时机。本例中是
BEFORE INSERT,意味着它将在INSERT命令执行之前被调用。 - 目标表:使用
ON关键字后接表名(例如orders),以告知MySQL触发器作用于哪个表。 - 行级触发:添加
FOR EACH ROW,确保触发器针对表中的每一行受影响的数据进行操作。 - 触发器逻辑:最后,编写触发器的主体逻辑。这是一系列在触发器激活时执行的SQL语句。如果有多条语句,需要用
BEGIN ... END块包裹起来。
编写触发器逻辑
触发器的逻辑需要检查是否即将向quantity列插入负值。这需要一个IF语句来访问quantity列的值。
要创建这个IF语句,你需要使用NEW或OLD修饰符之一。NEW修饰符用于访问操作后的列值(即即将插入的新值),这符合我们当前的需求。如果你需要访问操作前的列值,则应使用OLD修饰符。
因此,编写的逻辑语句是:如果新的订单数量值小于0,则将其设置为0。
对应的代码逻辑如下:
IF NEW.quantity < 0 THEN
SET NEW.quantity = 0;
END IF;
如果你现在对这些修饰符的理解还不够透彻,不必担心,本课程后续会进行更详细的讲解。
执行与删除触发器
在运行此触发器之前,有一个重要的步骤。
- 重定义分隔符:由于触发器主体包含分号(
;),需要先将MySQL的语句分隔符临时从分号重定义为其他符号(例如//),以防止MySQL提前结束解析。 - 执行创建语句:使用新的分隔符执行完整的
CREATE TRIGGER语句。 - 恢复分隔符:创建完成后,将分隔符改回分号。
至此,Lucky Shrub的orders表中已经成功添加了所需的触发器。
当需要从表中删除这个触发器时,可以使用DROP TRIGGER语句。
以下是删除触发器的推荐语法:
DROP TRIGGER IF EXISTS database_name.trigger_name;
IF EXISTS条件可以防止因触发器不存在而导致的错误。- 使用点符号(
.)同时提供数据库名(模式名)和触发器名。指定数据库名是可选的,但强烈建议使用,它有助于MySQL定位正确的触发器。
重要提示:如果你删除了orders表,那么与该表相关的所有触发器也会被自动删除。


课程总结
本节课中,我们一起学习了如何在MySQL中创建和删除触发器。我们通过Lucky Shrub的案例,逐步解析了创建BEFORE INSERT触发器的完整语法,包括命名、定义时机、指定目标表、编写行级逻辑,并使用了NEW修饰符来验证和修正数据。最后,我们介绍了如何安全地使用DROP TRIGGER语句移除触发器。现在,你应该能够在你自己的数据库中应用这些知识来创建和管理触发器了。


做得好! 🎉
入门 117:使用MySQL定时事件 🕐
在本节课中,我们将要学习MySQL中的定时事件功能。定时事件允许我们安排数据库在特定时间自动执行任务,例如生成报告或更新数据,即使我们不在现场。我们将了解定时事件的概念、创建语法,并通过实例来掌握其用法。
什么是MySQL定时事件? 🤔
上一节我们介绍了课程目标,本节中我们来看看什么是MySQL定时事件。
MySQL中的定时事件是根据给定时间表执行的任务。换句话说,它是在指定时间发生的事件。每个事件都有一个唯一的名称,并包含一个或多个SQL语句。它们存储在数据库中,可以只执行一次,也可以是重复发生的事件。
在MySQL中,你将主要处理两种类型的定时事件:
- 一次性事件:仅发生一次的定时事件。例如,一小时后向表中插入数据。
- 重复事件:定期发生的定时事件。例如,每周从数据库生成报告。
如何创建定时事件? 🛠️
了解了定时事件的基本类型后,本节中我们来看看如何创建它们。
在MySQL中,使用 CREATE EVENT 关键字来创建事件。以下是其基本语法结构:
CREATE EVENT [IF NOT EXISTS] event_name
ON SCHEDULE schedule
DO
event_body;
以下是关键部分的解释:
CREATE EVENT IF NOT EXISTS:如果事件尚不存在,则创建它。event_name:为事件指定一个唯一的名称。ON SCHEDULE:指定事件必须发生的时间计划。DO:此关键字后跟着事件主体,即使用SQL语句指定的事件逻辑。
创建一次性事件
对于一次性事件,需要使用 AT 子句来指定计划。它后面跟着一个时间戳和 INTERVAL 关键字,以及事件必须执行的具体时间。
例如,Lucky Shrub可以使用以下语法在12小时后生成一次性收入报告:
CREATE EVENT generate_report_once
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 12 HOUR
DO
-- 在此处放置SQL逻辑,例如:INSERT INTO report_table SELECT * FROM orders WHERE ...;
创建重复事件
重复事件的语法大体相同。关键区别在于必须使用 EVERY 子句代替 AT,后面跟着一个时间间隔。你还可以使用 STARTS 和 ENDS 关键字与时间戳和间隔一起,为事件指定特定的开始和结束点。
例如,Lucky Shrub可以使用重复事件语法创建一个每日库存检查事件:
CREATE EVENT daily_stock_check
ON SCHEDULE EVERY 1 DAY
STARTS CURRENT_TIMESTAMP
DO
-- 在此处放置SQL逻辑,例如检查并更新库存;
如何删除定时事件? 🗑️
学会了创建事件,有时我们也需要清理不再需要的事件。本节中我们来看看如何删除现有的MySQL事件。
使用 DROP EVENT 语句来删除事件。良好的实践是包含 IF EXISTS,这会告诉MySQL检查事件是否仍然存在且尚未从数据库中删除。
语法如下:
DROP EVENT IF EXISTS event_name;
实践案例:帮助Lucky Shrub 📊
现在你已经熟悉了定时事件及其语法,让我们通过实践来帮助Lucky Shrub解决实际问题。

案例一:生成月度收入报告
Lucky Shrub的财务部门需要一份本月所有订单的报告,并要求在当月最后一天的晚上11:59生成。现在是当月最后一天的中午,因此他们需要在12小时后生成报告。这是一个一次性事件。
以下是创建该事件的步骤:
- 使用
CREATE EVENT关键字开始。 - 为事件分配一个唯一名称,例如
generate_revenue_report。 - 指定计划。由于是一次性事件,使用
AT子句,并安排事件在当前时间戳的12小时后发生。 - 添加事件逻辑。键入
DO关键字,然后是一个BEGIN ... END代码块。在此代码块内,指示MySQL选择本月插入订单表的所有数据,并将这些数据放入报告数据表中。
示例代码如下:
CREATE EVENT generate_revenue_report
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 12 HOUR
DO
BEGIN
INSERT INTO report_data (order_id, customer_id, amount, order_date)
SELECT OrderID, ClientID, Cost, OrderDate
FROM orders
WHERE MONTH(OrderDate) = MONTH(CURRENT_DATE())
AND YEAR(OrderDate) = YEAR(CURRENT_DATE());
END;
案例二:每日库存补货检查
Lucky Shrub需要确保在售的每种商品至少有50件库存。我们可以使用一个重复事件来帮助他们。
以下是创建该事件的步骤:
- 创建事件并将其命名为
daily_restock。 - 指定计划。由于是重复事件,使用
EVERY子句并将其安排为每天执行一次。 - 添加
DO关键字,后跟一个BEGIN ... END代码块。在此代码块内,编写事件逻辑:MySQL必须检查产品表中是否有任何记录的商品数量低于50。如果找到低于50的记录,则必须更新该商品的数量。
示例代码如下:
CREATE EVENT daily_restock
ON SCHEDULE EVERY 1 DAY
STARTS CURRENT_TIMESTAMP
DO
BEGIN
UPDATE products
SET Quantity = 50
WHERE Quantity < 50;
END;
如果将来需要删除此事件,只需执行:
DROP EVENT IF EXISTS daily_restock;

总结 📝
本节课中我们一起学习了MySQL定时事件的基础知识。我们了解了定时事件是自动执行计划任务的有力工具,区分了一次性事件和重复事件。我们掌握了使用 CREATE EVENT ... ON SCHEDULE ... DO 语法创建事件,以及使用 DROP EVENT 删除事件的方法。最后,我们通过为Lucky Shrub创建月度报告和每日库存检查两个实际案例,巩固了所学知识。现在,你应该能够在自己的数据库中设置定时任务了。
入门 118:函数与触发器模块小结 🎯
在本模块中,我们学习了MySQL中的高级函数、存储过程、触发器以及事件。这些工具能帮助你封装代码、实现自动化操作,从而提升数据库的效率和可维护性。
课程介绍与目标 🎯
在第一课中,我们介绍了本课程。你了解了Meta高级数据库工程师的角色,与同学讨论了学习目标,并预览了课程将涵盖的主题。通过复习关键资源,你巩固了相关知识。
高级MySQL函数与存储过程 📊
上一节我们介绍了课程概览,本节中我们来看看高级MySQL函数与存储过程。你学习了创建存储过程和函数的主要目的是将代码封装在函数或过程的主体中。


以下是存储过程和函数的主要优点:
- 使代码更一致、更有条理。
- 引入可重用性,使代码更易于使用和维护。
你还了解到函数和存储过程的关键区别在于参数。函数只能有输入参数,而存储过程可以同时拥有输入和输出参数。
接着,你学习了如何利用变量和参数在MySQL中创建更复杂的存储函数和过程。
- 变量用于在SQL语句之间,或在过程与SQL语句之间传递值。你可以在存储过程内部或外部,以及在SELECT语句内部或外部创建变量。
- 参数用于从外部向函数或过程传递参数或值。在存储过程中,可以声明三种不同类型的参数:IN、OUT 和 INOUT 参数。

此外,你还学习了当MySQL内置函数无法满足项目需求时,如何开发用户自定义函数。数据库工程师可以编写自己的代码,该代码执行特定功能,然后返回所需结果。
MySQL触发器与事件 ⚙️
在第三课中,我们探讨了MySQL触发器和事件。你了解到MySQL触发器是一组以存储程序形式存在的操作。当某些事件发生时,这组操作会自动被调用。这些事件的例子包括在MySQL数据库表中插入、更新和删除数据。
以下是用于管理SQL事件的两种主要触发器类型:
- 行级触发器
- 语句级触发器
接下来,你学习了如何在MySQL中创建和删除这些触发器。你现在可以使用 CREATE TRIGGER 语句创建触发器,并使用 DROP TRIGGER 命令删除触发器。
你还回顾了创建MySQL触发器时涉及的其他语法方面。这包括定义触发器名称和类型,以及通过将多个语句包含在 BEGIN...END 块中来指定逻辑。
作为本课的一部分,你还学习了MySQL计划事件。你回顾了在MySQL中创建计划事件的语法和步骤。
总结 📝

本节课中,我们一起学习了MySQL中的高级函数、存储过程、触发器以及计划事件。你现在应该能够在MySQL数据库中运用函数和触发器了。做得很好!我期待在下一个模块中继续指导你,在那里你将学习如何优化数据库。
入门 119:数据库优化概述 🚀
在本节课中,我们将要学习数据库优化的基本概念及其重要性。随着数据量的增长和业务需求的复杂化,数据库的响应速度可能会变慢。通过优化,我们可以提升数据库的性能,确保快速响应查询。
概述
数据库优化是提升数据库系统性能的过程,旨在减少查询、处理和传输用户请求所需的时间。本质上,它是最大化数据库运行速度和效率的方法。一个经过优化的数据库能够快速处理SQL查询并返回所需数据。值得注意的是,数据库性能同时依赖于硬件和软件。在本课程中,我们将重点学习使用MySQL软件来优化查询。
SQL语句的分类
在课程的这个阶段,你已经接触了许多不同类型的SQL语句。这些语句主要可以分为两大类:数据检索语句和数据更改语句。
以下是这两类语句的简要说明:
- 数据检索语句:这类语句用于从数据库中返回数据,通常指
SELECT语句。 - 数据更改语句:这类语句用于修改数据库中的数据,例如
INSERT、UPDATE和DELETE语句。



这两种类型的语句需要不同的优化技术。在本模块的后续部分,我们将详细探讨这些技术,现在我们先了解一些基础知识。
优化数据检索语句
数据检索语句即SELECT语句。优化SELECT语句涉及大量工作,其中索引是典型且核心的方法。



索引是一种可以快速查找数据的“手柄”,它创建在表的列上。其基本概念可以表示为:
索引 -> 快速定位数据

我们将在本课后面更深入地学习索引。
以下是本课中你将遇到的其他优化SELECT语句的方法:

- 在
SELECT命令中明确指定所需的列,而不是使用SELECT *。 - 谨慎在查询条件(
WHERE子句)中使用函数和通配符(如%)。 - 在可能的情况下,优先使用内连接(
INNER JOIN)而非外连接(OUTER JOIN)。 - 了解
DISTINCT和UNION子句的使用场景,避免不必要的开销。 - 使用
ORDER BY子句对结果进行排序时,注意其对性能的影响。
优化数据更改语句
优化数据更改语句需要不同的方法。
例如,优化UPDATE和DELETE语句,首先需要优化其WHERE子句中的条件,以确保高效定位要修改的行。
对于INSERT语句,可以通过执行批量插入来优化。这意味着在单次INSERT操作中插入多行数据,其基本形式如下:
INSERT INTO table_name (column1, column2) VALUES
(value1a, value2a),
(value1b, value2b),
...;
目前,你只需要了解数据检索语句与数据更改语句在优化上的区别即可。我们将在本课后面进行更深入的探索。
优化的重要性
尽管数据库优化可能很复杂,但这项努力是值得的。正如你所了解的,一个经过优化的数据库能提供更快的响应时间,从而提升整体性能,同时还能减轻数据库不必要的负载。
通过优化数据库,Lucky Shrub公司可以更快速、更高效地处理其销售数据,避免因数据增长而可能出现的潜在问题。


总结
本节课中,我们一起学习了数据库优化的概念,并了解了可以优化的不同类型SQL语句。你现在应该对为什么需要进行优化以及优化的基本方向有了初步认识。干得不错!
入门 120:优化数据库选择语句 📊
在本节课中,我们将学习如何优化SQL中的SELECT语句,以确保数据库能够快速、高效地编译和执行查询。这对于处理大量数据、提升系统性能至关重要。
优化的重要性
当操作数据库时,确保SQL查询能被数据库快速高效地编译和执行非常重要。但这只有在查询本身被优化的情况下才能实现。在接下来的内容中,我们将探讨优化SELECT语句的技术。
Luc Shrub公司收到了大量客户订单,这导致其数据库中的数据量激增。他们需要使用SELECT语句来查询这些数据。为了提高查询性能,他们必须确保这些语句是经过优化的。
优化指南与核心技术
正如你可能已经知道的,SELECT语句属于SQL语句中的数据检索类别。这类语句旨在从数据库中返回数据。但如果它们没有被正确优化,就会给数据库增加额外负载,拖慢其性能。这意味着数据库执行你的SQLSELECT语句或查询所需的时间会更长,并返回你需要的数据。
然而,你可以遵循一些基本的指南或最佳实践来优化你的SELECT语句。你可能已经熟悉其中的一些方法。
以下是优化SELECT语句的核心指南列表:
- 在
SELECT子句中仅指定所需列:避免使用SELECT *。 - 避免在谓词中使用函数:尤其是在涉及未索引列或会阻止索引使用的场景。
- 避免在谓词中使用前导通配符:例如在
LIKE操作符的模式开头使用%。 - 尽可能使用
INNER JOIN:它比OUTER JOIN更高效。 - 仅在必要时使用
DISTINCT和UNION:考虑使用UNION ALL来提升速度。
优化技巧详解

上一节我们介绍了优化的核心指南,本节中我们来详细看看每个技巧的具体应用和原因。
1. 指定具体列而非使用通配符
查询表时,你可能经常在SELECT语句中使用星号(*)来提取所有可用数据。然而,指示MySQL查询表中的所有数据会给数据库增加额外负载并降低其性能,特别是当你只需要特定列的数据时。
一个更优的方法是,在语句中仅列出你所需数据所在的列,而不是使用星号。
-- 不推荐
SELECT * FROM orders;
-- 推荐
SELECT order_id, customer_name, order_date FROM orders;
Luc Shrub公司可以使用此方法,精准定位其订单表中的所需数据,从而更快地返回数据。
2. 避免在谓词中对列使用函数
数据库工程师常犯的另一个错误是在谓词中使用引用未索引列的MySQL函数。谓词是返回真或假值的表达式,WHERE子句条件就是其典型例子。你也应避免在WHERE子句中对已索引的列使用函数,因为这会导致数据库无法使用该索引。
-- 不推荐(假设`order_date`列有索引)
SELECT * FROM orders WHERE YEAR(order_date) = 2023;
-- 推荐
SELECT * FROM orders WHERE order_date >= '2023-01-01' AND order_date < '2024-01-01';
我们将在本课后面更详细地探讨索引。
3. 谨慎使用通配符
在谓词中使用前导通配符也会导致数据库速度下降。一个例子是在WHERE子句中结合LIKE操作符使用以通配符开头的模式。
-- 不推荐(前导通配符阻止索引使用)
SELECT * FROM products WHERE product_name LIKE '%shrub';
-- 推荐(如果可能)
SELECT * FROM products WHERE product_name LIKE 'lucky%';
当搜索匹配带有前导通配符的模式时,MySQL无法在搜索过程中使用该列的索引。
4. 优先使用INNER JOIN
另一种优化数据库的方法是在可能的情况下使用INNER JOIN代替OUTER JOIN。OUTER JOIN会检索两个表中的所有记录,包括那些不包含匹配值的行。这需要MySQL花费更长时间来处理。
INNER JOIN则更高效,因为它只从两个表中检索必要的数据或匹配的记录。这有助于优化你的查询。
-- 假设我们只需要有订单的客户信息
-- 使用INNER JOIN
SELECT c.customer_id, c.name, o.order_id
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id;
5. 明智使用DISTINCT和UNION
在创建SQL查询时,你经常会使用DISTINCT子句来消除重复值,或使用UNION子句来合并多个查询结果。这会减慢查询速度,因为它必须执行排序操作并消除重复记录。
但是,如果你使用UNION ALL代替,则可以省去排序操作,从而加快执行过程。
-- UNION 会去重和排序
SELECT city FROM suppliers
UNION
SELECT city FROM customers;
-- UNION ALL 更快,但可能包含重复项
SELECT city FROM suppliers
UNION ALL
SELECT city FROM customers;

总结
本节课中,我们一起学习了如何优化MySQL的SELECT查询,并熟悉了基本的优化指南。关键要点包括:精确指定查询列、避免在WHERE子句中滥用函数和通配符、优先选择INNER JOIN以及审慎使用DISTINCT和UNION。遵循这些最佳实践,将显著提升你的数据库查询效率。
入门 121:优化SELECT语句
在本节课中,我们将学习如何优化MySQL数据库中的SELECT查询语句。通过分析Lucky Shrub公司的三个实际业务场景,我们将了解常见的查询性能问题及其高效的解决方案,包括避免在WHERE子句中使用函数、优化模糊查询以及选择合适的JOIN类型。
场景一:查询特定送达日期的订单
销售部门需要找出所有预计在9月12日送达的订单。
一种直接的方法是编写一个使用WHERE子句和DATE_ADD函数的SELECT查询。然而,在WHERE子句中使用函数(如DATE_ADD)会让数据库进行大量额外的计算,这会显著增加数据库的负载。
低效查询示例:
SELECT * FROM orders WHERE DATE_ADD(order_date, INTERVAL 7 DAY) = '2023-09-12';
一个更高效的方法是在订单表中预生成一个名为expected_delivery_date(预计送达日期)的自定义列。这个列直接存储每条订单的预计送达日期。
现在,Lucky Shrub只需要扫描该列,查找所有值等于‘2023-09-12’的记录,而不再需要使用函数进行计算。
高效查询示例:
SELECT * FROM orders WHERE expected_delivery_date = '2023-09-12';
通过将计算提前并存储结果,我们避免了查询时的实时计算,从而提升了查询效率。
场景二:查找特定姓氏的客户
销售部门的下一个任务是为一位姓氏为“Eto”的客户处理订单。首先,他们需要在数据库的客户表中找到该客户的详细信息。

一种方法是使用SELECT语句,结合前导通配符和LIKE操作符。但是,当LIKE操作符以通配符(%)开头时,MySQL无法利用索引,导致查询必须进行全表扫描,速度很慢。
低效查询示例:
SELECT * FROM clients WHERE full_name LIKE '%Eto';
解决方案是使用ALTER TABLE语句向客户表添加一个新列,命名为reverse_full_name。这个列包含客户姓名,但是反转存储的。也就是说,客户的姓氏在前,名字在后。
添加列并更新数据:
ALTER TABLE clients ADD COLUMN reverse_full_name VARCHAR(255);
UPDATE clients SET reverse_full_name = CONCAT(SUBSTRING_INDEX(full_name, ' ', -1), ' ', SUBSTRING_INDEX(full_name, ' ', 1));
接下来,使用CREATE INDEX语法在这个新列上创建一个索引。
创建索引:
CREATE INDEX idx_reverse_name ON clients (reverse_full_name);
现在,你可以在reverse_full_name列上使用后导通配符和LIKE操作符来达到相同的查询目的,并且仍然能够利用索引。
高效查询示例:
SELECT * FROM clients WHERE reverse_full_name LIKE 'Eto%';
通过将数据重组并建立索引,我们使得基于姓氏的模糊查询变得高效。
场景三:生成所有订单的财务报告
财务部门需要一份包含所有已下订单的报告。他们可以通过关联数据库中的products(产品)表和orders(订单)表来提取这些信息。
通常,这个任务可以通过使用OUTER JOIN(外连接)查询来完成。然而,这种类型的查询会返回两个表中所有不匹配的记录,即使这些记录并不需要。
一个更高效的查询方法是让Lucky Shrub使用INNER JOIN(内连接),并基于两个表共享的product_id列进行连接。
高效查询示例:
SELECT o.order_id, p.product_name, o.quantity
FROM orders o
INNER JOIN products p ON o.product_id = p.product_id;
INNER JOIN只返回在两个表中都有匹配的记录。对于只需要已下单产品信息的场景来说,这是一种更高效的查询执行方式。
总结

本节课中,我们一起学习了优化MySQL SELECT查询的三个核心技巧:
- 避免在WHERE子句中使用函数:通过预计算并存储结果到新列中,可以消除查询时的计算开销。
- 优化模糊查询:通过反转字符串并建立索引,可以将无法使用索引的前导通配符查询,转换为可以使用索引的后导通配符查询。
- 选择合适的JOIN类型:根据业务需求选择
INNER JOIN而非OUTER JOIN,可以避免返回不必要的非匹配记录,提升查询效率。

掌握这些基本的优化指南,将帮助你编写出更高效、响应更快的数据库查询语句。
入门 122:MySQL索引 🗂️
在本节课中,我们将要学习MySQL索引。索引是一种用于加速数据库查询性能的数据结构。通过创建索引,MySQL可以快速定位到表中的特定数据,而无需扫描整个表,从而显著提高数据检索的效率。
理解索引的概念
上一节我们介绍了索引的基本作用,本节中我们来看看索引的具体构成和工作原理。
索引是一种数据结构,它维护着指向已排序数据的指针。虽然你在数据库中看不到索引,但可以将其想象成一个包含两列的表:一列是指针,另一列是已排序的数据。
例如,Lucky Shrub公司可以使用一个索引,其中一列列出指针,第二列则按顺序列出客户的完整姓名。
MySQL索引的类型
在MySQL数据库中,主要使用两种类型的索引。
- 主索引:也称为聚集索引。这种索引存储在表本身内部。当你创建一个包含主键或唯一键的表时,MySQL会自动生成主索引。该索引在表内部强制规定了行的顺序。
- 次索引:也称为非聚集索引。这种索引需要使用MySQL的
CREATE INDEX语句来创建。
以下是创建次索引的基本语法:
CREATE INDEX index_name ON table_name (column1, column2, ...);
一个常用的命名惯例是,在要创建索引的列名之前加上IDX_作为前缀。
索引可以基于表中的一个或多个列来创建。但你应该只为那些会频繁用于搜索的列创建索引。这是因为当你向表中插入或更新数据时,这些数据也必须同时添加到索引中或随之更新,这个过程需要时间。

为Lucky Shrub创建索引
现在我们已经熟悉了索引的概念,接下来看看如何运用这些新知识来帮助Lucky Shrub公司。
Lucky Shrub的销售部门需要从数据库中检索客户的联系电话。目前,他们需要查找客户“Jane Delgado”的联系方式。然而,数据库中有成千上万的客户记录,MySQL必须扫描所有行直到找到匹配的名字。
让我们先回顾一下MySQL通常执行此查询的过程:
- 首先,使用
EXPLAIN子句来输出解释数据库如何执行查询的数据。通过查看输出结果,可以定位潜在的瓶颈和低效查询。 - 然后,编写一个
SELECT语句,从clients表中选择与“Jane Delgado”匹配的联系电话。

执行查询后,虽然返回了正确的结果,但输出显示MySQL必须扫描并过滤了10条记录才找到匹配值。“possible_keys”列显示为NULL,这意味着没有可用的键或指针来帮助简化搜索过程。
因此,解决方案是为Lucky Shrub创建一个次索引来加速搜索过程。
以下是创建索引的步骤:
- 输入
CREATE INDEX语句。 - 为索引命名,例如在
full_name列前加上IDX_。 - 使用
ON关键字指定目标表为clients。 - 在括号内指定列名
full_name。 - 执行该语句以创建索引。
创建索引后,可以再次使用EXPLAIN语句来测试索引的效率。这次的输出结果显示,MySQL只需要定位一行数据,并且能够使用名为IDX_full_name的索引来找到可能的键。这意味着Lucky Shrub的SELECT查询现在可以通过搜索索引来更快地定位数据,而无需搜索clients表中的所有记录。
总结
本节课中我们一起学习了MySQL索引的核心知识。你现在应该能够解释什么是索引,概述主索引和次索引之间的区别,并描述创建索引的过程。合理使用索引是优化数据库查询性能的关键手段。
入门 123:MySQL事务管理 🛡️
在本节课中,我们将要学习MySQL中的事务管理。事务是确保数据库操作完整性和一致性的关键机制,尤其在进行一系列相关操作时至关重要。通过学习,你将掌握如何使用事务语句来开始、提交或回滚数据库操作,从而避免因错误导致的数据不一致问题。
什么是MySQL事务? 🔄
上一节我们介绍了事务的重要性,本节中我们来看看事务的具体定义。正如Lucky Shrub公司的案例所示,MySQL事务是一个或多个查询的集合,这些查询可以作为一个整体被永久提交到数据库。如果其中任何一个查询未能按要求执行,数据库可以回滚到其原始状态。
MySQL提供了以下一组语句来管理数据库事务:
START TRANSACTIONBEGIN或BEGIN WORKCOMMITROLLBACK
事务管理语句详解 ⚙️
现在我们已经了解了事务的基本概念,接下来详细探讨每个事务管理语句的用法。
开始事务
START TRANSACTION 是启动事务过程的标准SQL语句。其语法标记了如果你决定回滚进程,将返回到的点。
以下是开始事务的语法示例:
START TRANSACTION;
-- 你的SQL语句放在这里
例如,Lucky Shrub公司可以以 START TRANSACTION 语句开始他们的数据库更新,然后在其后列出所需的SQL查询。
然而,START TRANSACTION 并不是在MySQL中开始事务的唯一方式。你也可以使用 BEGIN 或 BEGIN WORK 别名作为启动事务的替代方法。
提交事务
无论你选择哪种方法开始事务,一旦你完成了SQL语句的输入并对结果满意,就是时候将事务提交到数据库了。你可以使用 COMMIT 语句将事务更改永久提交到数据库。
只需在你的代码块末尾键入 COMMIT 语句。
回滚事务
但是,如果你在事务过程中遇到错误怎么办?就像Lucky Shrub公司遇到的网络连接问题,或者你可能键入了错误的代码、执行了错误的语句或输入了不正确的数据。你可以使用 ROLLBACK 命令回滚当前事务并取消对数据库所做的更改。
只需将 ROLLBACK 语句添加到你的SQL语句末尾,即可返回到 START TRANSACTION 点。然而,重要的是要记住,ROLLBACK 语句必须在提交SQL语句之前执行。一旦你回滚了代码,就需要键入正确的SQL语句,并对这些语句满意后,键入 COMMIT 将更改提交到数据库。
事务流程总结 📝
所以,让我们快速回顾一下这个过程:
- 使用
START TRANSACTION开始你的事务。 - 键入你所需的SQL语句。
- 使用
COMMIT将你的更改提交到数据库。 - 如果你遇到任何错误或其他问题,只需使用
ROLLBACK语句返回到你的START TRANSACTION点。

实战演练:帮助Lucky Shrub更新数据 🛒
现在你已经熟悉了MySQL事务及相关语句,让我们看看你是否能帮助Lucky Shrub公司更新其数据库表中的销售和库存水平。
场景:一位ID为CL1的客户刚刚在线订购了10袋人造草。该商品在products表中的产品ID为P1。目前库存有100袋。一旦处理完客户的订单,这个数字必须更新为90。
以下是操作步骤:
- 开始事务:首先,键入
START TRANSACTION来确定如果发生错误可以回滚到的点。 - 添加SQL语句:现在,你需要添加所需的SQL语句。
- 第一条是
INSERT INTO语句:该语句将客户订单的新值集插入到orders表的所需列中。 - 然后键入
UPDATE语句:该语句通过从当前库存水平中扣除10个单位来更新products表中人造草的数量。 - 下一步是使用
SELECT语句:该语句使用两个表共有的product ID键,在orders和products表之间创建内连接。执行此语句以检查事务是否按预期完成。
- 第一条是
模拟错误与回滚:不幸的是,看起来出现了错误。这些更新被应用到了ID为CL11的客户。似乎你在代码中键错了客户ID。
没问题。你可以使用 ROLLBACK 语句恢复数据。现在,再次使用 SELECT 语句检查orders和products表。所有数据都已恢复到其原始状态。
重新执行正确的事务:所以,让我们再次键入 START TRANSACTION,后面跟上与之前相同的SQL语句。只是这一次,确保更新正确的客户详细信息。完成新的SQL语句集后,检查输出是否符合预期。
很好,这次所有细节都正确。你现在可以键入 COMMIT 将更改提交到数据库。
课程总结 🎯

本节课中我们一起学习了MySQL事务管理的核心知识。你现在应该能够使用事务语句来管理MySQL数据库中的事务了。我们了解了事务的定义,掌握了 START TRANSACTION、COMMIT 和 ROLLBACK 等关键语句的用法,并通过一个实战演练模拟了完整的事务流程,包括错误处理和回滚操作。这能确保即使在复杂的多步数据库操作中,数据也能保持完整和一致。干得漂亮。
入门 124:MySQL公共表表达式(CTE)📊
在本节课中,我们将要学习如何使用MySQL的公共表表达式(CTE)来优化复杂的SQL查询。CTE可以将冗长、难以管理的查询语句编译成简单、可重用的代码块,从而提升代码的可读性和可维护性。
什么是公共表表达式(CTE)?
当处理数据库时,您经常需要编写复杂的SQL查询。这些查询可能难以管理。然而,您可以通过使用公共表表达式(CTE)将它们编译成简单的代码块来优化这些查询。
公共表表达式是一种通过将复杂查询编译成简单代码块来优化数据库查询的方法。然后可以通过调用CTE来重写查询。这简化了查询,使其更易于阅读和维护。
CTE的基本语法
上一节我们介绍了CTE的概念,本节中我们来看看如何创建它。公共表表达式可以为单个或多个查询创建。这完全取决于您的数据库需求。
让我们从单个CTE的语法示例开始。
创建单个CTE
单个CTE查询的语法使用 WITH 子句来开始公共表表达式。其后跟随CTE的名称(可以是自定义名称)。然后使用 AS 关键字将括号内的查询与CTE名称关联起来。最后,创建一个 SELECT 语句来查询公共表表达式的名称。
其基本代码结构如下:
WITH cte_name AS (
-- 您的查询逻辑在这里
)
SELECT * FROM cte_name;
创建多个CTE
创建多个查询的语法稍微复杂一些。使用 WITH 子句开始代码块,然后在 WITH 子句下列出查询。确保每个查询都有唯一的名称,并且用逗号分隔。最后,键入您的 SELECT 语句。

以下是多个CTE的代码结构:
WITH
cte_name1 AS ( ... ),
cte_name2 AS ( ... ),
cte_name3 AS ( ... )
SELECT * FROM cte_name1
UNION
SELECT * FROM cte_name2
UNION
SELECT * FROM cte_name3;
要执行CTE,请在 SELECT 语句后键入其名称。或者,您可以一次执行多个CTE。要在单个 SELECT 语句中执行多个CTE,请在语句之间放置 UNION 运算符,以在输出结果中返回所有语句的数据。
实践案例:优化Lucky Shrub的查询
现在,让我们将学到的知识应用到一个实际案例中。Lucky Shrub公司的财务部门需要计算过去三个财年每位客户的平均销售额。他们的当前方法是创建三个独立的 SELECT 语句(每年一个),并使用 UNION 运算符组合它们。
每个语句都使用聚合函数和字符串连接函数来计算平均成本。数据从 orders 表中提取,条件使用 WHERE 子句指定。虽然这些查询能达到目的,但它们相当复杂且难以管理。
我们可以使用公共表表达式来提高它们的可读性。以下是优化的步骤:
- 首先使用
WITH子句。 - 将第一个表达式重写为
average_sales_2020,后跟所需的逻辑。您可以使用AS关键字将其别名为average_sale以提高可读性。 - 然后创建第二个和第三个表达式。使用
AS关键字将表达式与查询关联,并确保每个表达式用逗号分隔。 - 现在,您只需要键入三个
SELECT语句。每个语句使用星号 (*) 符号从三个表达式中提取所有数据。 - 在查询之间放置
UNION运算符以组合结果。 - 最后,执行代码。
优化后的查询输出结果与原始查询相同。然而,这次您创建了一个更优化的查询。所有表达式现在都包含在一个易于阅读和维护的简单代码块中。
总结

本节课中我们一起学习了MySQL公共表表达式(CTE)的使用。您应该已经熟悉了如何使用CTE来优化数据库查询。通过将复杂逻辑封装到命名的临时结果集中,CTE使SQL代码更加清晰、模块化和易于维护。这是一种处理复杂报表和多步骤数据操作的强大工具。
入门 125:MySQL预处理语句 🚀
在本节课中,我们将要学习MySQL中的预处理语句。这是一种高效执行SQL查询的技术,可以避免重复编译相同的SQL语句,从而节省数据库资源并提升性能。
概述
每次创建SQL语句时,MySQL都必须先对其进行编译和解析,然后才能执行。这个过程会消耗大量资源。一种更高效的方法是创建一个预处理语句,该语句可以重复使用,而无需每次都进行编译。
换句话说,您可以创建一个预处理语句,MySQL只需在执行前编译和解析一次。该语句充当一个模板,其中包含未指定的值作为参数。然后可以根据需要添加这些值。每次调用该语句时,MySQL都知道执行是安全的。这是一种更高效、更优化的执行语句方式,无需消耗宝贵的MySQL资源。
上一节我们介绍了SQL语句执行的基本流程,本节中我们来看看如何创建和使用预处理语句来优化这个过程。
创建预处理语句
让我们通过Lucky Shrub数据库的例子,看看如何创建和执行一个预处理语句。
Lucky Shrub需要从其orders表中提取客户订单数据。让我们使用一个优化的预处理语句来帮助他们完成此任务。
该预处理语句必须从数据库的orders表中返回指定记录的以下信息:client_id、product_id、quantity和cost。

第一步是使用PREPARE命令准备语句。然后键入语句名称,这可以是一个自定义名称。在本例中,我们可以将该语句命名为GetOrderStatement。
接着键入FROM关键字,并按照语法在单引号内编写一个SELECT语句。这个SELECT语句根据指定的值从orders表中提取所需数据。然而,您可能已经注意到,当前该值是未指定的,因为它需要一个输入值。稍后,您可以输入任何喜欢的值,用新的参数来处理该语句,而无需等待MySQL编译和解析该语句。
以下是创建预处理语句的代码示例:
PREPARE GetOrderStatement FROM 'SELECT client_id, product_id, quantity, cost FROM orders WHERE order_id = ?';
点击执行该语句。数据库将返回输出结果,即一条确认消息,声明语句已准备就绪。现在,GetOrderStatement已准备就绪,可以使用了。
执行预处理语句
接下来,您需要声明一个名为order_id的变量,并为其分配一个特定的订单ID。让我们使用ID 10。
现在,您可以将此变量与预处理语句一起使用。首先,键入EXECUTE命令,后跟语句名称。此命令用于执行预处理语句。
接着,键入USING关键字,后跟变量名。USING关键字指定要传递给预处理语句中参数的值。
因此,这个预处理语句基本上是指示MySQL提取orders表中与order_id为10相关联的client_id、product_id、quantity和cost数据。
以下是执行预处理语句的代码示例:
SET @order_id = 10;
EXECUTE GetOrderStatement USING @order_id;
点击执行查询并返回结果。
预处理语句的优势
虽然这个预处理语句针对的是order_id为10的记录,但您也可以针对orders表中的任何其他order_id。该语句可以提取相关数据,并且无需等待MySQL编译。
以下是使用预处理语句的主要优势列表:
- 性能提升:SQL语句只需编译一次,后续执行直接使用预编译的模板。
- 安全性增强:通过参数化查询,可以有效防止SQL注入攻击。
- 代码简洁:对于需要重复执行但参数不同的查询,代码更加清晰和易于维护。
- 资源节约:减少了数据库服务器编译SQL语句的开销。

总结

本节课中我们一起学习了MySQL预处理语句。我们了解了其工作原理,即将SQL语句编译一次,后续通过传递不同参数重复执行。我们逐步实践了如何使用PREPARE命令创建预处理语句,如何使用SET定义变量,以及如何使用EXECUTE ... USING来执行带参数的语句。掌握预处理语句是进行高效、安全数据库操作的重要技能。
入门 126:MySQL JSON数据类型 🗃️
在本节课中,我们将要学习如何在MySQL中使用JSON数据类型来优化数据库性能。JSON是一种轻量级的数据交换格式,能够简化不同系统间的数据通信,并减少数据库解析不同类型数据时的资源压力。
什么是JSON? 📄
上一节我们介绍了JSON在数据库优化中的作用,本节中我们来看看JSON的具体结构。
JSON,全称为JavaScript Object Notation,是一种用于存储和传输数据的文本格式。它易于人阅读和编写,同时也易于机器解析和生成。在MySQL中,使用JSON数据类型可以高效地存储结构化的数据,而无需预先定义严格的表结构。
JSON数据由键值对组成,存储在一对大括号 {} 中。以下是一个来自Lucky Shrub数据库的JSON代码示例:
{"client_id": "Cl1", "product_id": "P1", "order": true}
- 键值对:每个属性(如
"client_id")和其对应的值(如"Cl1")被包裹在双引号中,并用冒号分隔。 - 分隔符:每个键值对之间用逗号分隔。
这种格式使得数据组织清晰,且MySQL能够快速处理。

实践:在MySQL中创建JSON表 🛠️
理解了JSON的基本概念后,我们来看看如何在MySQL数据库中实际应用它。Lucky Shrub公司需要追踪客户在网店中的行为,例如浏览产品和下单。使用JSON格式存储这些动态信息非常合适。
以下是创建存储客户活动表的步骤:
- 创建表:首先,创建一个名为
activity的表。 - 定义列:表中包含两列。
- 第一列是
activity_id,使用整数数据类型,作为每条客户活动的唯一标识符。 - 第二列是
properties,将其数据类型定义为JSON。这一列将存储客户活动的具体属性。
- 第一列是
创建表的SQL语句如下:
CREATE TABLE activity (
activity_id INT AUTO_INCREMENT PRIMARY KEY,
properties JSON
);
向JSON表中插入数据 ➕
表结构准备好后,下一步是向其中填充数据。我们将为三个不同的客户ID记录活动,并使用JSON代码来记录详细信息。
以下是插入数据的示例:
INSERT INTO activity (properties) VALUES
('{"client_id": "Cl1", "product_id": "P1", "order": true}'),
('{"client_id": "Cl2", "product_id": "P4", "order": false}'),
('{"client_id": "Cl3", "product_id": "P5", "order": true}');
在这三条记录中,两个客户(Cl1和Cl3)下了订单("order": true),一个客户(Cl2)没有下单("order": false)。
从JSON列中检索数据 🔍
由于properties列是JSON数据类型,我们不能像查询普通列那样直接访问其中的具体属性。我们需要使用MySQL提供的列路径运算符来检索JSON对象内的数据。
列路径运算符使用美元符号 $ 和点号 . 来表示JSON对象中的元素。
例如,要查询所有活动的ID及其完整的JSON属性,可以使用以下语句:
SELECT activity_id, properties FROM activity;
如果只想提取JSON对象中的特定值,比如客户ID,则需要使用路径运算符。以下是查询语句:
SELECT
activity_id,
properties->'$.client_id' AS client_id,
properties->'$.order' AS order_placed
FROM activity;
在这个语句中:
properties->'$.client_id'用于提取client_id的值。properties->'$.order'用于提取order的值。AS关键字为提取出的值指定了易于理解的列别名。
执行此查询将返回一个清晰的结果集,显示每条活动记录对应的客户ID和是否下单的状态。
总结 📝

本节课中我们一起学习了MySQL中JSON数据类型的应用。我们了解到,JSON是一种高效存储半结构化数据的方式,能够减轻数据库处理多种数据类型的压力。通过创建包含JSON列的表、插入JSON格式的数据以及使用列路径运算符($)查询特定信息,我们帮助Lucky Shrub公司建立了一个优化的客户活动数据存储与访问方案。掌握JSON在MySQL中的使用,是数据库工程师进行性能优化的重要技能。
入门 126:数据库优化模块小结 🎯
在本节课中,我们将回顾并总结本模块(数据库优化)所涵盖的核心知识与技能。本模块主要聚焦于如何通过各种技术提升数据库查询与操作的性能与效率。
模块内容回顾 📚
恭喜你完成了本课程的第二个模块。现在,让我们花点时间回顾一下你在本模块课程中获得的一些关键技能。
第一课:查询优化基础
在第一课中,你学习了如何优化数据库查询。你现在理解了数据库优化是一个过程,其目标是最大化数据库在执行查询时的速度和效率。
你了解到优化主要关注两种不同类型的语句:
- 数据检索语句(
SELECT语句):用于从数据库返回数据。 - 数据修改语句(
INSERT,UPDATE,DELETE等):用于更改数据库内的数据。




通过学习优化数据库,你可以更快速、更高效地处理数据。



在本课中,你还学习了如何对SELECT查询实施不同的优化技术。以下是针对SELECT查询的一些关键优化技巧:
- 仅选择所需列:在
SELECT子句中明确指定需要的列,避免使用SELECT *。 - 避免在谓词中使用函数:例如,避免
WHERE YEAR(date_column) = 2023,这可能导致索引失效。 - 避免在谓词中使用前导通配符:例如,避免
WHERE column LIKE ‘%pattern’,这会阻止索引的有效使用。 - 尽可能使用
INNER JOIN:它通常比某些子查询或CROSS JOIN更高效。 - 仅在必要时使用
DISTINCT和UNION:因为它们会增加额外的处理开销。 - 利用索引:索引是指向已排序数据的指针,能显著加快数据检索速度。
在学习索引时,你了解到有两种主要类型的索引:
- 主索引(聚集索引):决定了表中数据的物理存储顺序。
- 二级索引(非聚集索引):独立于数据存储结构,提供额外的查找路径。



你复习了创建二级索引的语法,其基本结构如下:
CREATE INDEX index_name ON table_name (column1, column2, ...);
这条语句使用CREATE INDEX关键字、自定义的索引名,以及ON关键字来指定目标表和列。
第二课:高级优化技术
在第二课中,你探索了进一步的优化技术。完成本课后,你现在能够:
使用MySQL事务语句来管理查询,并在任何查询未能按要求执行时将数据库回滚到原始状态。你可以使用以下语句管理数据库事务:
START TRANSACTION,BEGIN或BEGIN WORK:开始一个事务。COMMIT:提交事务,使所有更改永久化。ROLLBACK:回滚事务,撤销自事务开始以来的所有更改。



你可以使用START TRANSACTION开始事务。如果执行查询时遇到错误,你可以在SQL语句末尾添加ROLLBACK语句,使数据库返回到START TRANSACTION时的状态。


使用MySQL公用表表达式优化SELECT查询。你现在可以使用CTE将复杂的查询编译成简单的代码块。这些代码块可以在需要时通过调用CTE来重写查询,从而简化查询并使其更易于阅读和维护。
CTE的基本语法结构如下:
WITH cte_name AS (
-- 你的查询代码块
SELECT ...
)
SELECT * FROM cte_name;
你使用WITH子句开始代码块,然后在下面列出查询,最后键入你的SELECT语句并跟上CTE的名称。

你还可以使用UNION操作符在语句之间执行多个CTE。

使用MySQL预处理语句。你现在可以利用预处理语句来限制MySQL必须编译和解析代码的次数,从而提高执行效率,特别是在需要重复执行结构相同但参数不同的SQL语句时。
使用JSON数据类型与MySQL数据库交互。你探索了如何在MySQL中存储和查询JSON格式的数据,这为处理半结构化数据提供了灵活性。
学习成果巩固
在学习这些课程的过程中,你还通过阅读材料加深了对主题的理解,在测验环境中测试了对优化技术的掌握程度,并在实验环境中展示了运用MySQL优化技术的能力。
总结 🏁

完成本模块后,你现在应该能够运用广泛的数据库优化技术。你可以部署这些技术来确保你的语句在MySQL中能够被快速、高效地编译、解析和执行。



干得漂亮!你已经掌握了提升数据库性能的关键工具和方法,为构建高效、可靠的数据库系统奠定了坚实基础。
入门 128:数据库分析概述 📊
在本节课中,我们将要学习数据分析在数据库中的角色,并理解数据分析与数据解析之间的紧密关系。我们将探讨如何将数据分析过程中收集的数据转化为有用的信息,以指导未来的商业决策,并了解不同类型的数据分析。
在课程的这个阶段,你应该已经熟悉了数据分析在数据库中所扮演的角色。
同时,理解数据分析与数据解析之间的紧密关系也很重要。
你可以将数据分析过程中收集的数据,转化为能够指导未来商业决策的有用信息。
在接下来的几分钟里,你将探索这是如何运作的,并了解不同类型的数据分析。
Lucy Shrub 公司经历了一个非常成功的假日销售季。他们收集了大量关于销售的数据。
现在,他们需要利用这些数据来为下一个销售期做规划。
Lucy Shrub 可以利用数据解析和相关变量来理解这些数据,并为未来做出有效规划。
因此,Lucy Shrub 对数据的使用,为理解“数据解析”这个术语的含义提供了一个很好的基础。
数据解析通过将收集到的数据转换和处理成有用且有意义的信息,将数据分析向前推进了一步。
这些信息随后被用来指导并对未来事件做出预测。
数据解析还涉及到特殊工具的使用。
你将在本课稍后部分简要了解这些工具。
所以,你的下一个问题很可能是:组织如何利用数据解析?
在 Lucy Shrub 公司,他们可以利用数据分析工具来处理数据,以预测哪些产品最畅销并应保持库存。
哪种类型的特别优惠最能吸引顾客,以及如何最好地管理他们的在线销售。
然而,在进行数据解析之前,你首先需要对你收集的数据进行分析并生成见解。
这些数据是通过数据分析和 SQL 查询收集的。
在数据库中,可以执行不同类型的数据分析。
让我们花点时间来探索这些不同类型的数据分析,并了解它们如何为数据解析提供信息。
以下是不同类型的数据分析:
- 描述性数据分析:以描述性格式呈现数据。换句话说,它描述发生了什么。你可以使用从数据库中提取的数据来解释特定事件。例如,Lucy Shrub 可以分析他们在特定时期内的销售情况。然后,他们可以通过引用最畅销的产品和获得的利润,利用这些数据来描述这个时期。
- 探索性数据分析:试图建立数据库中不同变量之间的关系。换句话说,变量 A 和 B 之间是否存在关系,或者你能否在变量 X 和 Y 之间建立联系。在 Lucy Shrub,他们使用探索性数据分析来确定特定产品销量增长与销售季节之间是否存在任何相关性。例如,假日期间树木销量的增长。
- 推断性数据分析:专注于一小部分数据样本,以对更大的数据总体做出推断并得出一般性结论。Lucy Shrub 经常使用推断性数据分析。他们的数据显示,夏季月份烧烤产品的销量有所增长。因此,他们可以推断这是销售这些商品的最佳时期。
- 预测性数据分析:使用现有或历史数据来识别范式和模式。然后可以利用这些模式来预测未来的表现。例如,Lucy Shrub 的数据显示,当园艺工具打折时,其销量会增加。他们可以利用这些数据预测,进一步的折扣将带来更多销量。
- 因果数据分析:探索不同变量之间关系的因果关系。是变量 A 导致了 B,还是变量 X 对 Y 产生了任何影响?Lucy Shrub 的数据显示,许多购买园艺工具的顾客也购买了户外照明产品。因果数据分析是 Lucy Shrub 尝试识别这些购买之间关系的好方法。
最后,请注意,数据工程师经常交替使用“数据分析”和“数据解析”这两个术语。
尽管它们是独立的概念,但它们是紧密相连的。
没有数据分析,就不可能有数据解析。因此,请务必注意这个事实。


在处理数据解析时,你现在应该理解数据解析的概念,并能够识别不同类型的数据分析。
做得好。
P129:使用MySQL进行数据分析
在本节课中,我们将探讨MySQL与数据分析之间的关系,并了解MySQL作为数据分析工具的优势与局限性。
通过前面的学习,你应该已经熟悉了数据分析的概念及其与数据处理的区别。本节中,我们将具体看看MySQL如何应用于数据分析场景。
MySQL在数据分析中的应用
Lucky Shrub公司利用MySQL来存储数据并进行数据分析。他们的数据库每天处理大量数据,包括在线订单、客户信息以及产品数据。MySQL为他们提供了一套有效的工具来管理和处理这些数据。
接下来,我们将了解Lucky Shrub如何利用MySQL来分析这些数据。
MySQL的优势
随着课程的深入,你已经了解到MySQL的强大功能。MySQL的另一个优势在于,它为数据库工程师提供了对数据库中数据进行数据分析所需的工具。
然而,与其他更高级的数据分析工具相比,MySQL也存在其局限性。让我们花点时间来探讨这些方面。


关系型模型
MySQL数据库基于关系型数据库模型构建。正如你在先前课程中学到的,关系模型将数据集组织在相互关联的表中,这些关联表使得访问、检索和分析相关信息变得容易。

通过MySQL,Lucky Shrub可以使用外键来连接他们的数据库表。这意味着他们可以利用一个表来定位另一个表中的信息。例如,orders表和products表通过product_id键连接。这种关系帮助Lucky Shrub识别每位客户订购了哪些产品。
开源与成本
MySQL是一个免费、开源的数据库管理系统。因此,在使用MySQL管理数据库时,无需考虑许可或知识产权成本。这对Lucky Shrub非常有益,因为它降低了业务运营成本。
广泛使用
由于其容量和可访问性,MySQL是一个非常广泛使用的数据库管理系统。大量企业、政府和其他组织使用MySQL来收集、存储和处理数据。这使得这些组织之间更容易沟通数据并改进其数据分析。
例如,Lucky Shrub的供应商也使用MySQL管理数据。因此,Lucky Shrub可以通过从数据库的products表中发送数据,让供应商及时了解其库存水平信息。


MySQL的局限性
尽管有上述优势,MySQL也存在一些局限性。
分析能力有限
MySQL执行数据分析的能力比其他更高级的数据分析工具有限得多。使用其他工具,数据库工程师可以借助强大的人工智能执行更复杂的数据分析。
缺乏数据可视化功能
MySQL缺乏数据可视化功能。其他数据库分析工具为数据库工程师提供了如条形图、曲线图和地图等可视化功能。与仅以表格形式呈现数据相比,这些工具是传达信息的更有效方式。借助这些可视化工具,Lucky Shrub可以快速发现数据趋势并识别任何重大问题。
总结
本节课中,我们一起学习了将MySQL用作数据库管理系统的一系列广泛优势:它是免费开源的、能在关系系统中存储大量数据,并且被各种组织广泛使用。


然而,与其他更先进的数据分析工具相比,其数据分析和可视化能力较为有限。理解这些优势和局限,有助于你在实际工作中为不同的数据分析任务选择合适的工具。
入门 130:使用SQL查询在MySQL中进行数据分析 📊
在本节课中,我们将学习如何在MySQL数据库中使用SQL查询进行数据分析。我们将探讨如何通过不同的SQL技术(如子查询、连接和视图)来访问数据、提取相关信息,并最终为业务决策提供支持。
SQL查询与数据分析的关系 🔗
上一节我们介绍了数据分析的基本概念。本节中我们来看看SQL查询如何支持这一过程。
数据分析涉及从数据库中收集和呈现数据。在MySQL中,可以使用多种SQL查询来收集数据。以下是几种关键的技术:
- 连接:用于将两个或多个表的数据合并在一起。
- 子查询:在一个查询内部嵌套另一个查询。
- 视图:用于创建虚拟表,简化复杂查询。
- 函数与运算符:用于执行复杂操作和过滤所需数据。
因此,在MySQL中使用SQL查询进行数据分析的基本流程如下:
- 使用一个或多个SQL查询从数据库中提取所需数据。
- 使用进一步的SQL查询来呈现数据分析结果的描述。
- 基于这些初步结果,通过数据分析工具获得更深入的业务洞察。
数据分析流程示例 🧪
现在,让我们通过一个具体示例来理解这个流程。
假设Lucky Shrub公司需要一份销量达到或超过100件的所有产品清单。他们可以使用子查询来提取这些数据。
核心步骤:
- 创建一个SQL子查询,定位并筛选所需数据。
- 通过执行查询,从数据库中提取出这些数据(即最畅销产品列表)。
- 利用这些数据,结合更复杂的查询和数据分析工具,生成进一步的业务洞察,例如调整采购策略或制定促销方案。
所有这些洞察和潜在策略的实现,都依赖于通过SQL查询收集到的数据。
实践:使用子查询提取数据 💻
了解了基本流程后,是时候付诸实践了。Lucky Shrub需要对客户订单进行数据分析。
他们需要一份销量达到或超过10件的所有产品列表。相关数据位于数据库的orders表中。
以下是提取该数据的SQL语句:
SELECT ProductID
FROM orders
WHERE ProductID IN (
SELECT ProductID
FROM orders
WHERE Quantity >= 10
);
代码解释:
- 外部
SELECT语句从orders表中选择ProductID。 WHERE子句使用一个子查询来筛选出那些在orders表中Quantity(数量)大于等于10的ProductID。
执行此语句后,MySQL将输出一个包含所需记录的表。
使用连接进行数据分析 ⛓
连接是MySQL中执行数据分析的另一种有效方法,可用于探索数据间的关系。
例如,Lucky Shrub需要分析过去10天内客户及其订单数据,但这些数据分别存在于orders和clients两个表中。
我们可以使用内连接来帮助他们分析:

SELECT c.ClientName, o.OrderID, o.ProductID, o.OrderDate
FROM orders o
INNER JOIN clients c ON o.ClientID = c.ClientID
WHERE o.OrderDate BETWEEN '2023-10-01' AND '2023-10-10';
代码解释:
INNER JOIN将orders表(别名o)和clients表(别名c)通过ClientID字段连接起来。WHERE子句使用BETWEEN关键字过滤出指定日期范围内的订单。
使用视图进行数据分析 👓
视图对于分析数据也很有帮助,它可以创建专注于特定数据类型的虚拟表。
假设Lucky Shrub需要分析销售数据并提取前五名最畅销产品。我们可以创建一个视图来简化这项任务。
以下是创建该视图的SQL语句:
CREATE VIEW TopProducts AS
SELECT p.ProductName, SUM(o.Quantity) AS TotalQuantity, SUM(o.Quantity * p.Price) AS TotalCost
FROM products p
INNER JOIN orders o ON p.ProductID = o.ProductID
GROUP BY p.ProductID, p.ProductName
ORDER BY TotalQuantity DESC
LIMIT 5;
代码解释:
CREATE VIEW语句创建了一个名为TopProducts的虚拟表。- 内部的
SELECT语句使用INNER JOIN合并了products和orders表的数据。 GROUP BY对产品进行分组,SUM函数计算总销量和总销售额。ORDER BY ... DESC按总销量降序排列,LIMIT 5只取前五条记录。
视图创建后,你可以使用简单的SELECT * FROM TopProducts;来查询其中的数据,以进行进一步分析。
总结 📝
本节课中,我们一起学习了在MySQL中使用SQL查询进行数据分析的核心方法。

我们了解到,数据分析始于通过合适的SQL查询(如子查询、连接和视图)从数据库中提取目标数据。随后,可以对这些数据进行进一步处理和解读,从而获得支持业务决策的洞察。
关键要点:
- 子查询适合在查询内部进行条件筛选。
- 连接用于合并多个相关表中的数据。
- 视图可以创建可重用的虚拟表,简化复杂查询。
- 选择哪种SQL技术,完全取决于你需要提取和分析的数据类型,以及你希望通过分析达到的目标。
现在,你应该对使用SQL查询在MySQL中执行数据分析有了基本的了解。出色的工作!
入门 131:在MySQL中模拟全外连接 🧩
在本节课中,我们将学习如何在MySQL中模拟“全外连接”(Full Outer Join)。全外连接是一种能够同时返回两个表中所有记录(包括匹配和不匹配的记录)的查询方式。由于MySQL本身不直接支持FULL OUTER JOIN语法,我们将通过组合LEFT JOIN、RIGHT JOIN和UNION(或UNION ALL)操作符来实现相同的效果。
什么是全外连接?
在SQL中,全外连接会返回左表和右表中的所有记录。当在两个表之间找到匹配项时,它会返回匹配的记录;如果没有找到匹配项,它也会返回不匹配的记录,并用NULL值填充缺失侧的列。
然而,MySQL数据库并不原生支持FULL OUTER JOIN。因此,我们需要通过其他方法来模拟这一功能。
模拟全外连接的方法
要模拟全外连接,核心思路是分别获取左连接和右连接的结果,然后将它们合并。以下是两种主要的合并方式:
- 使用
UNION ALL操作符:合并两个查询的结果集,并保留所有重复的记录。 - 使用
UNION操作符:合并两个查询的结果集,并自动去除重复的记录。
接下来,我们详细看看这两种方法的语法结构。
方法一:使用 UNION ALL 保留所有记录
以下是使用UNION ALL模拟全外连接的基本语法框架:
SELECT [所需列]
FROM 左表
LEFT JOIN 右表 ON 左表.匹配列 = 右表.匹配列
UNION ALL
SELECT [相同顺序的所需列]
FROM 左表
RIGHT JOIN 右表 ON 左表.匹配列 = 右表.匹配列;
语法解析:
- 第一个
SELECT语句使用LEFT JOIN,会返回左表的所有记录,以及右表中匹配的记录(不匹配的右表列显示为NULL)。 UNION ALL操作符将直接拼接两个结果集,即使存在完全相同的行也会保留。- 第二个
SELECT语句使用RIGHT JOIN,会返回右表的所有记录,以及左表中匹配的记录(不匹配的左表列显示为NULL)。 - 两个
SELECT语句选择的列必须数量相同且数据类型兼容。
方法二:使用 UNION 去除重复记录
如果希望结果集中不包含重复的行,可以使用UNION操作符。其语法与UNION ALL非常相似,只需替换关键字即可:
SELECT [所需列]
FROM 左表
LEFT JOIN 右表 ON 左表.匹配列 = 右表.匹配列
UNION
SELECT [相同顺序的所需列]
FROM 左表
RIGHT JOIN 右表 ON 左表.匹配列 = 右表.匹配列;
核心区别:UNION会自动对合并后的结果集进行去重,而UNION ALL则不会。
实战演练:为Lucky Shrub公司提取数据

现在,让我们通过一个实际案例来应用上述知识。假设Lucky Shrub公司需要一份完整的报告,包含:
- 所有新订单及其对应的客户信息。
- 所有客户的信息,包括那些尚未下过订单的客户。
相关数据存储在clients(客户)表和orders(订单)表中。我们将使用UNION操作符来获取不重复的完整记录。
以下是具体的SQL查询语句:

SELECT
clients.ClientID,
clients.FullName,
clients.ContactNumber,
orders.OrderID,
orders.Cost,
orders.Date
FROM clients
LEFT JOIN orders ON clients.ClientID = orders.ClientID
UNION
SELECT
clients.ClientID,
clients.FullName,
clients.ContactNumber,
orders.OrderID,
orders.Cost,
orders.Date
FROM clients
RIGHT JOIN orders ON clients.ClientID = orders.ClientID;
语句执行效果:
- 查询结果将展示所有的
ClientID及其关联的OrderID。 - 对于成功匹配的订单和客户,所有字段都有值。
- 对于没有下过订单的客户,其
OrderID、Cost和Date字段将显示为NULL。 - 对于(理论上)没有对应客户信息的订单,其客户信息字段将显示为
NULL(尽管外键约束通常避免这种情况)。 - 由于使用了
UNION,完全相同的行(即匹配成功的记录)只会出现一次。
执行此语句后,Lucky Shrub公司便能获得他们所需的来自两个表的所有记录。
总结
本节课中,我们一起学习了如何在MySQL中模拟全外连接。我们了解到,虽然MySQL不直接支持FULL OUTER JOIN,但可以通过LEFT JOIN、RIGHT JOIN配合UNION或UNION ALL操作符来实现相同的功能。关键步骤是:
- 编写一个
LEFT JOIN查询以获取左表全部记录及匹配的右表记录。 - 编写一个
RIGHT JOIN查询以获取右表全部记录及匹配的左表记录。 - 使用
UNION ALL合并两者以保留所有记录,或使用UNION合并以去除重复记录。
掌握这一技巧,你就能灵活处理需要同时分析两个表全部数据的复杂查询场景了。
入门 132:使用联接从多个表中提取数据 📊
在本节课中,我们将学习如何使用SQL的JOIN操作,从多个数据库表中提取和整合数据。我们将通过一个具体的商业案例,演示如何编写查询来满足复杂的业务需求。
在上一模块中,我们已经熟悉了数据分析的基本流程及其如何指导决策。本节中,我们来看看如何在MySQL中通过联接多个表来执行实际的数据分析。
业务场景概述
Lucky Shrub公司需要识别出所有在2020年9月5日之后,购买了特定产品线10件或以上商品的客户,以便向他们发送特别优惠,鼓励再次购买。同时,为了确保所有优惠都能被兑换,该产品当前库存必须至少有50件。
数据库表结构

以下是包含所需数据的三个数据库表:
orders表:包含每笔订单的信息。clients表:包含每位客户的关键信息。products表:存储商店中所有产品的数据。
构建查询语句

我们可以使用INNER JOIN来联接这些表,并提取以下目标数据:来自clients表的ClientID和ContactNumber列,来自orders表的OrderID、Quantity和Date列,以及来自products表的NumberOfItems列(我们将其重命名为ItemsInStock)。
让我们开始构建查询。首先使用SELECT语句,并通过点符号指定要从每个表中选取的列。
SELECT
clients.ClientID,
clients.ContactNumber,
orders.OrderID,
orders.Quantity,
orders.Date,
products.NumberOfItems AS ItemsInStock
接下来,使用FROM关键字指定clients表作为主表,然后使用INNER JOIN子句在括号内将其与orders表和products表联接起来。
FROM clients
INNER JOIN (orders, products)
第一个联接基于clients表和orders表中共有的ClientID列创建。第二个联接基于orders表和products表各自的ProductID列创建。
ON clients.ClientID = orders.ClientID
AND orders.ProductID = products.ProductID
现在,添加WHERE子句来设置我们的筛选条件。在括号内,声明以下三个条件:
- 客户必须购买了10件或以上的商品。
- 所有购买必须发生在2020年9月5日之后。
- 该商品当前库存必须至少有50件。
WHERE (orders.Quantity >= 10)
AND (orders.Date > '2020-09-05')
AND (products.NumberOfItems >= 50);
最后,执行查询。MySQL将从相关表中提取符合条件的数据并显示在屏幕上。
查询结果与应用
通过执行上述数据分析,你成功地从Lucky Shrub数据库的三个表中整合了信息。利用这些结果数据,公司可以精准地识别出符合条件的目标客户,并向他们发送特别优惠。

本节课中,我们一起学习了如何使用INNER JOIN联接多个数据库表,并结合WHERE子句实现复杂条件的数据查询。这是进行跨表数据分析、支持业务决策的核心技能。
入门 133:MySQL数据分析模块小结 🎯
在本模块中,我们学习了如何评估MySQL在数据分析中的应用,并掌握了使用MySQL进行数据分析的核心技能。本节将对整个模块的关键知识点进行回顾和总结。
模块概述 📋
在模块三的课程中,我们主要探讨了MySQL在数据分析领域的角色与应用。我们首先学习了如何评估MySQL是否适合进行数据分析,然后深入实践了使用SQL查询进行数据分析的各种技术。

关键技能回顾
以下是你在本模块课程中获得的核心技能总结。
第一课:评估MySQL用于数据分析
在第一课中,你学习了如何评估MySQL用于数据分析。你现在能够解释,数据分析是通过将收集到的数据转换和处理成有用且有意义的信息,从而更进一步。这些信息随后被用来指导决策并对未来事件进行预测。


接着,你学习了数据分析的主要类型。以下是这些类型:
- 描述性数据分析:以描述性格式呈现数据。
- 探索性数据分析:用于建立不同变量之间的关系。
- 推断性数据分析:用于对更大的数据总体进行推断并得出一般性结论。
- 预测性数据分析:识别范式与模式。
- 因果性数据分析:探索不同变量之间关系的因果关系。


你还学习了使用MySQL作为数据库管理系统的优势,特别是在支持组织内决策者方面。MySQL的主要优势包括:
- 它是免费且开源的。
- 它能在关系系统中存储大量数据。
- 它在各种组织中广泛使用。
- 它为数据库工程师提供了对数据库中数据执行分析所需的工具。

同时,你也了解到MySQL在执行数据分析能力方面存在一些局限性。例如,它比其他一些工具功能稍弱,并且缺乏数据可视化工具。
第二课:在MySQL中执行数据分析
在第二课中,你学习了如何在MySQL中执行数据分析。完成本课后,你应该能够使用SQL查询执行基本的数据分析。在这个过程中,你使用一个或多个SQL查询从数据库中提取所需数据。这些SQL查询用于呈现数据分析结果的描述,并通过数据分析从这些初步结果中获得更深入的见解。
然后,我们探讨了可用于执行数据分析的不同类型的SQL查询。以下是核心操作:

- 你可以模拟全外连接,以在识别左右表匹配时返回两个表中的所有记录。这包括匹配的记录和不匹配的记录。
- 你还学习了可以使用
UNION ALL运算符返回重复记录,或使用UNION运算符仅检索唯一记录。







然而,MySQL本身不支持全外连接,因此你必须使用左连接和右连接来模拟它。
你还可以使用函数来执行复杂的操作并返回不同的结果,并使用运算符过滤所需数据。以下是高级技术:
- 你可以利用子查询在一个查询中创建另一个查询。
- 你可以部署视图来创建虚拟表。
在学习这些课程的过程中,你还通过阅读材料加深了对主题的理解,在测验环境中测试了对优化技术的掌握程度,并在实验环境中展示了运用数据分析技术的能力。






总结 🏁
完成本模块后,你现在应该能够评估MySQL用于数据分析,并在MySQL中执行数据分析。出色的工作!我期待在下一模块中继续指导你学习。
MetaP134:高级MySQL课程回顾
在本节课中,我们将回顾《高级MySQL》课程的核心内容。课程涵盖了函数与存储过程、数据库优化技术以及MySQL在数据分析中的应用等关键主题。让我们一起总结所学知识。
模块一:高级MySQL编程
上一节概述了课程目标,本节中我们来看看模块一的具体内容。本模块主要介绍了MySQL中的高级编程对象。
函数与存储过程 🛠️
在这一课中,你学习了如何在MySQL中创建和使用函数以及存储过程,以便复用或调用代码块来执行特定操作。
以下是本课的核心知识点:
- 创建函数与存储过程:你学会了使用
CREATE FUNCTION和CREATE PROCEDURE语句来封装可重用的逻辑。 - 使用变量与参数:你掌握了如何利用变量和参数来创建更复杂的存储函数和过程,使其更加灵活。
- 开发用户定义函数:当MySQL的内置函数无法满足项目需求时,你学会了如何开发自定义函数(UDF)。
触发器与事件 ⏰
接着,你学习了如何使用MySQL的触发器和事件来自动化数据库任务。
以下是本课的核心知识点:
- 理解触发器:你了解到MySQL触发器是一种存储程序形式的一组操作,当特定事件(如INSERT、UPDATE、DELETE)发生时会被自动调用。
- 创建触发器:你熟悉了
CREATE TRIGGER命令的语法,包括定义触发器名称、类型,并使用BEGIN ... END块来封装触发器的执行逻辑。 - 使用计划事件:你理解了如何利用计划事件来确保数据库任务在特定时间自动执行。
模块二:数据库优化核心
在掌握了高级编程技巧后,我们进入模块二,学习提升数据库性能的核心规则与指南。
优化数据库查询 ⚡
本课首先探讨了如何优化数据库查询,理解了数据库优化的概念及其为MySQL数据库带来的优势。
以下是本课的核心知识点:
- 优化SELECT语句:你回顾了优化SELECT语句的技术,例如仅选择必需的列、避免使用复杂函数,以确保查询快速高效执行。
- 使用索引:你学习了如何在MySQL中使用索引来加速数据检索查询的性能。
高级优化技术 📈
本模块的第二课概述了更多高级优化技术。
以下是本课的核心知识点:
- 管理事务:你学会了如何使用MySQL事务语句(如
BEGIN,COMMIT,ROLLBACK)来管理数据库事务,确保数据一致性。 - 使用公共表表达式:你发现了如何利用公共表表达式(CTE)将复杂的SQL查询组织成单个代码块,提高可读性和可维护性。
- 使用预处理语句:你学会了如何使用预处理语句(Prepared Statements)来限制MySQL编译和解析代码的次数,提升效率。
- 使用JSON数据类型:你探索了如何利用MySQL的JSON数据类型来存储和查询半结构化数据。
模块三:MySQL与数据分析
最后,我们进入模块三,探索MySQL与数据分析之间的关系。

评估MySQL用于数据分析 📊
本课首先帮助你理解了数据库分析与MySQL之间的关系,并学习了如何将数据分析过程中收集的数据转化为能为未来决策提供依据的有用信息。
以下是本课的核心知识点:
- 数据分析类型:你探索了可以在数据库中执行的不同类型的数据分析。
- MySQL的利弊:你了解了MySQL作为数据分析工具的优势与局限性。

在MySQL中执行数据分析 🔍
在第二课中,你学习了如何使用SQL查询在MySQL中执行实际的数据分析。
以下是本课的核心知识点:
- 使用SQL进行数据分析:你掌握了使用连接(JOIN)、子查询和视图等SQL查询来进行数据分析。
- 模拟全外连接:你探索了如何在MySQL中模拟全外连接(FULL OUTER JOIN),以提取两个表中的所有记录,包括不匹配的记录。
- 从多表提取数据:你最终学会了如何使用JOIN方法从多个表中提取和整合数据。
总结
在本节课中,我们一起回顾了《高级MySQL》课程的核心内容。你学习了如何通过函数、存储过程、触发器和事件来增强MySQL的编程与自动化能力;掌握了优化数据库查询和使用索引、事务、CTE等高级技术来提升性能;并探索了如何利用MySQL进行有效的数据分析。


课程回顾至此结束。现在,是时候在分级评估中尝试运用你所学的知识了。祝你好运!😊
入门 135:课程总结 🎉
在本节课中,我们将对Meta数据库工程师课程中关于MySQL的学习旅程进行总结,回顾已掌握的核心技能,并展望未来的学习路径。
你已经通过努力的学习到达了这里,并在此过程中掌握了许多新技能。你在MySQL的学习之旅中取得了巨大的进步,现在应该已经理解了MySQL中的高级主题。

你能够在实验项目中展示部分所学知识,以及你实用的MySQL技能集。现在,你应该能够在MySQL环境中部署函数和触发器,优化数据库,并使用SQL查询进行数据分析。随后的分级评估进一步检验了你对这些技能的掌握程度。

然而,你仍有更多知识需要学习。如果你觉得本课程有帮助并希望探索更多内容,那么为何不注册下一门课程呢?在每一门数据库工程师课程中,你都将持续发展你的技能集。
在最终的实验项目中,你将运用所学的一切知识,创建属于自己的功能完整的数据库系统。无论你是刚起步的技术专业人士、学生还是商业用户,课程结束时的项目都能证明你对数据库系统价值和能力的理解。
该实验通过实际应用来巩固你的能力。但实验还有另一个重要的益处:这意味着你将拥有一个可以放入作品集的、完全可操作的数据库。这可以向潜在雇主展示你的技能,不仅表明你积极主动且富有创新精神,也充分体现了你作为个人以及你新获得的知识。
当你完成本专业的所有课程后,你将获得一份证书。😊
数据库工程。该证书也可作为进阶到其他基于角色的证书的跳板。根据你的目标,你可以选择深入学习高级的基于角色的证书,或者在获得此证书后学习其他基础课程。

感谢你。很荣幸能与你一同踏上这段探索之旅。
祝未来一切顺利。😊

本节课总结
在本节课中,我们一起回顾了整个MySQL学习阶段的成果,包括掌握了部署函数与触发器、数据库优化和SQL数据分析等高级技能。我们了解了课程最终项目对巩固技能和构建作品集的重要性,并展望了获得证书后的持续学习路径。你的努力已为成为一名数据库工程师奠定了坚实的基础。
Python 1:课程介绍 🐍
在本节课中,我们将要学习Meta《数据库工程师》课程中Python编程部分的整体介绍。我们将了解Python语言的特点、应用领域以及本课程的核心模块内容。
Python是一种多用途的高级编程语言,可在多种平台上使用。它是一种被各种规模的公司用来构建多样化应用程序的语言。Python的应用领域包括Web开发、数据分析和商业预测。Python编程语言的语法与英语非常相似,它很直观,初学者通常能快速理解其逻辑。对于有经验的程序员来说,Python也是一个绝佳选择,他们会欣赏其强大功能和适应性。由于Python是一个非常流行的软件开发工具,作为新开发者,了解其工作原理并掌握如何使用它进行编码非常重要。
本课程涵盖了开始Python编程所需了解的关键要点。
模块一:Python入门与基础概念
从模块一开始,您将开始学习Python编程语言及其相关的基础概念。
以下是您将在模块一中学习的主要内容:
- 您将学习识别Python的常见应用。
- 您将能够解释基础的软件工程概念。
- 您将使用运算符来编程输出。
- 您将使用控制流和循环来解决编码问题。


模块二:核心概念与数据处理




上一节我们介绍了入门基础,本节中我们来看看Python的核心概念。
在模块二中,您将在第一个模块的基础上,学习支撑Python编程语言的核心概念:变量和不同的数据类型。您将学习使用控制流和循环在特定条件下执行代码。

这个模块还会向您介绍如何在Python中使用函数和数据结构。


以下是模块二的其他关键学习点:
- 识别错误,确定其原因并决定如何处理它们。
- 在文件中创建、读取和写入数据。

模块三:编程范式与高级特性


在掌握了核心概念后,模块三将带您进入更高级的编程领域。

在模块三中,您将学习函数式编程和面向对象编程的编程范式。您将使用函数来探索算法思维。此外,您还将学习如何在Python中处理对象、类和方法。

模块四:模块、包与开发工具
了解了编程范式,接下来我们将学习如何利用现有资源提升开发效率。


在模块四中,您将学习如何处理模块、包、库和工具。在这里,您将学习如何查找、导入和使用流行的Python模块和包。您将利用强大的工具来优化编程工作流程。您将发现不同类型的测试及其特点,并且能够使用测试工具来编写测试。

模块五:结业评估与展望


最后,我们将通过实践来检验学习成果。
模块五是分级评估,您可以在此展示您的Python编码能力。您将能够运用本课程所学的技能和知识,并有机会反思课程内容以及您未来的学习路径。

您可能在本视频中遇到了一些尚未完全理解的概念或术语。现在不必担心。本课程旨在解决所有此类问题,并为您打下坚实的Python编码基础。
本节课中我们一起学习了Python编程课程的完整结构,从基础语法到核心概念,再到高级编程范式和实用工具,最后以实践评估收尾。希望您享受这门课程。
Python 2:Python在现实世界中的应用 🐍
在本节课中,我们将了解Python编程语言的起源,聆听一位资深工程师的经验分享,并探索Python在当今科技行业中的广泛应用。我们将看到,Python不仅是一门简洁易学的语言,更是驱动众多流行服务和尖端技术的核心力量。
Python的命名起源
Python的创造者非常喜欢英国喜剧团体“蒙提·派森的飞行马戏团”。因此,他选择了“Python”作为这门编程语言的名字,认为它简短且神秘,而不是指代蛇类。
工程师视角:Leilla Risby的经验
我是Leilla Risby,是Instagram后端团队的一名软件工程师,在旧金山工作。我使用Python编程已有10年之久。Python是我学习的第一门编程语言。我在Meta的日常工作中每天都会使用Python。它是我最喜欢的编程语言,因为它非常易于使用且简单。
我第一个需要用Python编写的应用程序是一个计算器。由于Python是我学习的第一门语言,构建我的第一个Python应用程序对我来说有些棘手。学习如何缩进、如何空格、学习语法、理解什么是循环以及所有这些核心的计算机科学概念对我来说非常困难。但我努力尝试,最终成功了。
Python在日常生活中的应用
以下是一些你在日常活动中可能已经接触到的、由Python驱动的重要应用:
- 使用Instagram。
- 使用Facebook。
- 使用Google或Spotify。

Python是一门如此普遍的语言,无论你是否意识到,你很可能都已经使用过它。

Python在工业与科技领域的应用
Python也被用于TensorFlow,这是一个机器学习框架。Airbnb用它来对图像进行分类,一些医疗保健公司用它来对MRI数据进行分类。
在Meta,Python被用于Instagram的后端。它被用于我们的广告机器学习算法。它也被我们的生产工程师用来维持服务的存活和运行。
学习Python的建议
即使学习过程可能充满挑战,你也应该坚持学习Python。因为它是一门相对容易学习的语言,它很简单。它拥有大量支持库,这使得构建更多功能变得更加容易。因为已经有很多工程师在使用它,所以可以更快地开发功能。使用Python,你可以更快地看到成果。
总结

本节课中,我们一起学习了Python命名的有趣起源,了解了资深工程师Leilla Risby从初学者到专家的学习路径。我们探讨了Python如何渗透到我们的日常生活(如Instagram、Facebook)以及工业界(如TensorFlow、Meta的广告系统)的方方面面。最后,我们明确了学习Python的价值:其简洁性、丰富的库和庞大的社区支持,使其成为快速开发和取得成果的强大工具。感谢观看今天的视频,祝你成为一名软件工程师的旅程顺利!
Python 3:2_编程简介
概述
在本节课中,我们将要学习编程的简要历史,并了解计算机编程的基本工作原理。我们将从早期的计算设备开始,逐步深入到计算机如何理解指令,以及编程的本质是什么。


编程历史的开端 🕰️
计算机及其程序以我们难以想象的规模融入了我们的生活。

在过去的20年里,我们在分布式计算、云计算以及人工智能(如语音和面部识别、自动驾驶汽车)等领域见证了技术的巨大飞跃。
接下来,让我们简要回顾一下编程的历史,并学习编程的基本工作原理。

早期计算设备


计算的历史可以追溯到很久以前。1822年,查尔斯·巴贝奇在英国剑桥大学学习期间,致力于改进导航图和天文表等计算设备,这些设备在当时被许多海上船只使用。
巴贝奇意识到,所有这些计算设备都包含不同程度的人为错误,他思考是否存在更好的解决方案。


差分机与分析机
他的解决方案是差分机。差分机使用机械齿轮,齿轮的间隙上刻有数字0到9,由齿轮齿分隔。它的关键功能是执行一个通过手动摇动手柄计算的操作,直到最终答案显现。
在建造了一个工作原型后,巴贝奇花费多年时间进一步改进他的设计,并构建了原始想法的改进版本。他创造了另一个名为差分机2号的设备,但最终提出了一个更新、更好的概念——分析机。


分析机被广泛认为是现代计算的基础。
巴贝奇的朋友艾达·洛夫莱斯发表了一份文件,描述了分析机如何执行一系列计算,这本质上就是计算机程序所做的。然而,分析机从未完成,而且像许多开发者一样,巴贝奇也没有在良好的文档记录上投入精力。

计算机如何工作?💡
上一节我们介绍了编程的早期历史,本节中我们来看看计算机在最基本层面是如何工作的。
在解释编程之前,了解计算机在最基本层面的工作原理是有帮助的。
二进制:计算机的语言
计算机只理解二进制代码,它由两个数字组成:0 和 1。

这起初可能看起来很奇怪,但稍作解释就会明白。0和1对应不同的电状态,类似于电灯开关:0等于关闭,1等于开启。
例如,在编程中,当你计算数字、成本或进行任何算术运算时,你主要使用十进制数字。
每个编写的程序都需要转换为二进制代码或机器代码。

以下是一个十进制到二进制转换的例子:
- 十进制 1 是二进制 1。
- 十进制 2 是二进制 10。
- 十进制 3 是二进制 11,依此类推。

从代码到执行

计算机通过称为晶体管的微小电导体来表示二进制代码。这些晶体管位于中央处理器(CPU)内部,CPU本质上是计算机的大脑。

当使用任何类型的语言编写程序时,它需要被编译或解释。

其目的是将我们可读的编程代码转变为计算机可读的编程代码。
人类阅读和理解二进制极其困难,因此使用它容易出错。对我们来说,阅读和编写编程语言要容易得多。


什么是编程?🧑💻

上一节我们了解了计算机的底层语言,本节我们来探讨编程的本质。
编程的定义
编程是以计算机能够理解的特定语言为其提供一组指令,并让它执行这些操作或任务的能力。

换句话说,你需要以一种计算机能够理解的格式化语言告诉它你想要它做什么。

编程的特点


编程是一项技能,你练习和学习得越多,你就会变得越好。

起初,编写简单的程序可能需要相当长的时间。随着你的进步,你会更加熟悉语言以及如何应用逻辑和条件。
编程也是一项创造性技能。这是因为你可以编写计算机程序,以多种不同的方式解决问题。

总结
本节课中,我们一起学习了编程的简要历史,从巴贝奇的差分机和分析机开始。我们探讨了计算机如何通过二进制(0和1)工作,以及程序如何被编译或解释为机器代码。最后,我们定义了编程的本质:它是一种为计算机提供可执行指令的创造性技能。理解这些基础概念是成为一名程序员的第一步。
Python 4:为什么选择Python 🐍
在本节课中,我们将探讨Python编程语言的核心优势及其适用场景。我们将了解Python为何在众多领域广受欢迎,以及它如何帮助开发者高效地完成任务。
你是否希望能够在不同平台(例如Windows、Mac和Linux)上,使用一种语法类似英语的简易语言进行编程?那么Python是你的解决方案。它是一种高级编程语言,可在多种不同平台上运行。通过本视频的学习,你将了解学习Python的好处,并理解Python的用武之地。


Python由Guido Van Rossum创建,并于1991年发布。它的设计目标是易于阅读,并且在英语语言和数学之间借鉴了许多相似之处。

自发布以来,Python的受欢迎程度大幅提升,并支持丰富的框架和库选择。目前,它是当今最受欢迎的编程语言之一。

Python广泛应用于商业的各个领域,例如Web开发、人工智能、机器学习、数据分析和各种不同的编程应用。

Python也非常易于学习和入门。鉴于其语法类似于英语,这使得它更易于阅读和理解。

与C或Java等编程语言相比,用Python编写的程序通常需要更少的代码。Python的一个关键优势是它使开发人员效率非常高,并允许项目更快地完成。

创建被许多人使用的好软件是困难且非常耗时的。Python的简洁性为开发者抽象掉了大量复杂性,使他们能够专注于手头的任务。鉴于该语言相当容易理解和掌握,对于刚开始编程的新手来说,它可以成为一条更快捷的途径,让他们在更短的时间内产出成果。
与其他一些语言相比,Python的学习曲线要平缓得多。它很好地契合了“写更少的代码,做更多的事”的理念。
既然你已经了解了学习Python的好处以及它的应用领域,那么知道Python开发人员需求旺盛也是有益的。成为一名Python开发者是一个不错的职业选择。




总结
本节课我们一起学习了Python的核心优势。我们了解到Python是一种语法类似英语、跨平台的高级编程语言,以其易读性和简洁性著称。它在Web开发、人工智能、数据分析等多个领域应用广泛,并且因其“写更少,做更多”的高效特性,成为初学者入门和开发者提高生产力的优秀选择。掌握Python技能在当前的就业市场上也极具竞争力。
Python 5:Windows环境检查与Python配置 🖥️
在本节课中,我们将学习如何在Windows操作系统上,为Visual Studio Code(VS Code)集成开发环境配置正确的Python解释器。这是开始Python开发前至关重要的一步,确保你的代码能够被正确执行。
概述
开始使用Python时,确保它在你的操作系统和选定的集成开发环境中正常工作非常重要。本教程将演示如何在Windows上设置VS Code,并确保它指向正确的Python解释器。
打开Visual Studio Code
首先,我们需要打开VS Code编辑器。点击任务栏上的Windows图标,这会弹出一个菜单。在搜索栏中输入“Visual Studio code”。搜索结果中的最佳匹配是Visual Studio Code应用程序,点击它即可打开。
现在,VS Code已经成功打开。

开始Python开发设置
接下来,在VS Code界面中选择“Get Started with Python Development”。这是一个在VS Code IDE上设置Python的有用指南。
安装与验证Python
指南的第一步是安装Python。如果你已经安装了Python,可以通过在终端中输入特定命令来验证。要打开终端,请选择顶部菜单栏中的“Terminal”选项卡,然后选择“New Terminal”。
在终端中输入以下命令并按回车键:
python --version
如果终端显示类似“Python 3.10”的版本信息,则说明Python已正确安装。
创建Python文件
指南的第二步是创建一个Python文件。点击指南菜单中的“Create a Python file”选项,然后点击出现的“Create Python file”按钮。
现在,输入一个简单的打印语句:
print("Hello world")
我们将在后续阶段详细解释print函数,目前你只需知道它用于在终端内部打印输出值。
保存Python文件


接下来,将这个文件保存为Python文件。点击菜单栏的“File”,然后选择“Save As”。在保存对话框中,输入文件名helloworld.py。
.py是保存Python文件时必须使用的文件扩展名。
选择Python解释器
上一节我们创建了Python文件,本节中我们来看看如何为它选择正确的解释器。指南的下一步是选择Python解释器。点击指南菜单中的这个选项,然后点击出现的“Select Python interpreter”按钮,这会列出你已安装的所有Python版本。
进行此操作是为了确保在运行Python脚本时,VS Code会选择正确的解释器。出现的版本是Python 3.10,我将其设置为解释器,因为它是最新版本。
运行与验证配置
为了测试和验证一切是否正常工作,我们需要运行Python文件。在屏幕的右上角,你会注意到一个播放按钮。为了更好地显示,可以关闭指南窗口。
播放按钮有一个下拉菜单,其中包含“运行Python文件”或“在调试中运行”的选项。点击“Run Python file”选项。
请注意,在终端窗口中,它已使用Python 3.10作为解释器运行了该文件,并且我们得到了“Hello World”的输出。
这意味着我现在已经设置好可以直接在IDE中使用Python,从而可以运行和调试我的脚本。
总结

本节课中,我们一起学习了在Windows系统上为VS Code配置Python开发环境的核心步骤。你现在已经知道如何创建和保存Python文件,以及如何在VS Code中选择正确的Python解释器来运行你的文件。这是开启Python编程之旅的坚实基础。
Python 6:Mac环境检查 🍎
在本节课中,我们将学习如何在Mac操作系统上,为Visual Studio Code(VS Code)设置正确的Python解释器,并验证其是否能正常运行Python脚本。这是开始Python开发前的重要一步。
检查Python安装
上一节我们介绍了课程目标,本节中我们来看看如何确认Python已正确安装在你的Mac上。

首先,需要打开终端来检查已安装的Python版本。在VS Code中,你可以通过点击界面左下角的按钮,然后选择“终端”标签页来打开内置终端。


在终端中,输入以下命令并按回车键:
python --version
该命令会返回当前系统默认的Python版本号。请注意,Mac系统通常预装的是Python 2.7版本,但现代开发通常需要使用更新的Python 3版本。因此,你需要确认命令返回的是类似 Python 3.10.x 这样的版本信息。
设置VS Code与Python解释器
确认Python安装后,下一步是确保VS Code指向正确的Python解释器。
在VS Code的欢迎界面,通常有一个“开始使用Python开发”的引导指南。如果主界面没有显示,你可以通过点击“更多”选项来找到它。该指南能帮助你验证所有设置是否正确。
以下是设置解释器的关键步骤:
- 在引导指南中,点击“选择Python解释器”。
- 这会打开一个下拉菜单,显示你系统上所有已安装的Python版本。
- 从列表中选择通过Homebrew或其他方式安装的最新Python 3版本(通常会被标记为“推荐”)。


你也可以通过快捷键 Command + Shift + P 打开命令面板,然后输入 Python: Select Interpreter 来快速打开解释器选择菜单。
创建并运行Python文件
设置好解释器后,我们可以创建一个简单的Python文件来测试环境是否工作正常。
在“开始使用Python开发”引导中,点击“创建Python文件”。在新文件中,输入以下代码:
print("Hello World")
print() 是一个Python内置函数,用于在终端中输出指定的值。现在,你需要保存这个文件。
点击菜单栏的 文件 -> 另存为,将文件命名为 hello_world.py。.py 是Python源文件的标准扩展名。
文件保存后,即可运行它。在VS Code编辑器界面的右上角,你会看到一个三角形的“播放”按钮,其旁边有一个下拉菜单。
点击下拉菜单,选择“运行Python文件”,然后点击播放按钮。程序运行后,你会在下方的终端面板中看到输出的结果:Hello World。
至此,你已经成功验证了VS Code正确指向了你想要使用的Python版本,并且能够在IDE中直接运行和执行脚本。

总结

本节课中我们一起学习了在Mac上配置Python开发环境的核心步骤。你学会了如何检查Python版本、在VS Code中设置正确的Python解释器、创建并保存Python文件,以及最终运行一个简单的脚本。这些是开始任何Python项目前的基础准备工作。
Python 7:命令行与IDE运行代码 🖥️
在本节课中,我们将学习运行Python代码的两种主要方式:通过命令行/终端,以及通过集成开发环境(IDE)。我们将探讨每种方法的核心差异、适用场景以及具体操作步骤。
概述
Python程序可以通过两种主要方式执行:在命令行/终端中直接运行,或使用集成开发环境(IDE)。理解这两种方法的区别和各自的优势,对于高效编写和测试代码至关重要。
运行Python程序的两种主要方式
上一节我们概述了课程内容,本节中我们来看看运行Python代码的具体方法。主要有以下两种途径:
- 使用Python Shell
- 直接从命令行终端运行Python文件
1. 使用Python Shell
Python Shell适用于运行和测试小型代码片段。它允许你直接输入并执行代码,而无需创建新的 .py 文件。
以下是使用Python Shell的步骤:
- 打开命令行(Windows)或终端(Mac/Linux)。
- 输入
python命令并按下回车键,进入Python交互式环境。 - 在此环境中,你可以直接输入代码并立即看到执行结果。
例如,在Shell中输入:
print("Hello World")
按下回车后,会立即输出 Hello World。
2. 直接从命令行运行Python文件

现在,让我们探索第二种方法:直接从命令行或终端运行Python文件。任何扩展名为 .py 的文件都可以通过以下命令运行。
操作命令的通用格式是:
python 文件名.py
例如,要运行名为 hello_world.py 的文件,你需要在终端中输入:
python hello_world.py
然后按下回车键。
为什么选择使用IDE(如VS Code)?
虽然可以使用Python Shell或终端直接运行代码,但使用IDE(例如Visual Studio Code)通常是更好的选择。因为它不仅包含了上述两种运行方式,还提供了大量增强功能,能显著提升编码体验。
VS Code提供的核心功能包括:
- 自动补全:帮助你快速编写代码。
- 调试工具:便于查找和修复代码错误。
- 语法高亮:使代码结构更清晰易读。
- 空格与缩进辅助:确保代码格式符合Python规范。
在VS Code中运行Python程序的演示
接下来,我将演示在VS Code中运行Python程序的不同方法。在VS Code中,你同样可以通过终端运行,也可以使用IDE内置的便捷按钮。
方法一:通过VS Code内置终端运行
首先,从IDE内部打开终端窗口。点击“终端”菜单,选择“新建终端”。

然后,在终端中直接运行Python脚本。输入命令:
python hello_world.py
按下回车键,结果将输出 Hello World。
此外,你也可以在终端中启动Python Shell。只需输入 python 并回车,即可进入交互模式,直接执行代码。输入 exit() 并回车可以退出Shell,返回命令行窗口。
方法二:使用VS Code的运行按钮
关闭终端窗口,我们来看看更便捷的方式。你可以直接在IDE中运行Python脚本。

操作步骤如下:
- 在代码编辑界面,找到屏幕右上角的运行按钮。
- 点击下拉菜单,可以选择“运行Python文件”或“调试Python文件”。
- 点击运行按钮,终端会自动打开并显示执行结果,例如打印出
Hello World。
![]()
总结
本节课中,我们一起学习了运行Python代码的两种核心方式:通过命令行/终端,以及通过集成开发环境(IDE)。你现在已经了解了从命令行运行代码与通过IDE运行代码的核心区别,并且能够演示如何使用Python来运行程序。掌握这些方法将为你后续的Python学习和项目开发打下坚实的基础。
Python 8:7_Python语法空格很重要
概述
在本节课中,我们将要学习Python语法中空格和缩进的重要性。你将了解空格如何影响代码的执行,以及如何正确使用缩进来构建代码块。这些知识是编写正确、可读Python代码的基础。

空格在语句中的作用
在Python中,空格用于分隔语句中的不同元素。然而,不当使用空格可能导致语法错误。
以下是一个简单的打印语句示例:
print("hello")
在VS Code中运行此代码,终端会输出“hello”。
现在,假设我们想在同一行添加另一个打印语句来输出“world”。我们可能会这样写:
print("hello") print("world")
但运行此代码会产生语法错误:“syntax error invalid syntax”。这是因为解释器无法识别新语句的开始位置。
有两种方法可以解决这个问题。
第一种方法是将第二个打印语句移到新的一行:
print("hello")
print("world")
运行此代码,会分别在两行输出“hello”和“world”。
第二种方法是在两个语句之间使用分号和一个空格进行分隔:
print("hello"); print("world")
运行此代码,同样会输出“hello”和“world”。
空格在表达式中的影响
上一节我们介绍了语句间的空格问题,本节中我们来看看空格在表达式中的影响。
首先,声明一个变量并赋值:
x = 1 + 2
print(x)
运行此代码,会输出结果3。
现在,在加号周围添加一些空格:
x = 1 + 2
print(x)
运行此代码,仍然会输出3。这说明表达式内部的空格通常不会影响计算结果。
但是,如果我们将表达式拆分成多行,情况就不同了。尝试以下代码:
x = 1 + 2
+ 3
print(x)
运行此代码,只会输出3。解释器执行了第一行的1 + 2,但忽略了第二行的+ 3。
为了解决这个问题,我们可以使用反斜杠来强制换行:
x = 1 + 2 \
+ 3
print(x)
运行此代码,会输出正确的结果6。
总结来说,一行内的任何空格或缩进都是可以的。但如果你将代码拆分成多行,就需要明确指示新行的开始位置。
Python中的缩进
上一节我们探讨了空格在表达式中的作用,本节中我们来看看缩进在Python中的关键作用。
缩进在Python中用于定义代码块,例如在条件语句和循环中。
以下是一个使用if语句的示例:
name = "John"
if name == "John":
print(name)
运行此代码,会输出“John”。注意,print语句前面有四个空格的缩进,这是VS Code自动添加的。
现在,如果我们删除缩进:
name = "John"
if name == "John":
print(name)
运行此代码,会产生缩进错误:“indentation error expected an indented block”。这个错误信息告诉我们,在应该缩进的地方没有找到缩进。
幸运的是,错误信息通常会指向检测到问题的具体行,这样我们就可以轻松地修复代码。
在编写Python程序时,养成阅读错误输出的习惯是很好的。错误信息通常会告诉你哪里出了问题以及具体是什么问题。

总结
本节课中我们一起学习了Python语法中空格和缩进的重要性。我们了解到:
- 语句之间需要正确的分隔,可以使用换行或分号。
- 表达式内部的空格通常不影响计算,但跨行表达式需要使用反斜杠来明确指示。
- 缩进是Python中定义代码块的关键,错误的缩进会导致程序无法运行。

掌握这些基本概念,将帮助你编写出正确且结构清晰的Python代码。
Python 9:变量 🧮
在本节课中,我们将要学习编程中的一个核心概念:变量。变量是存储各种类型数据的基本单元,可以说是编程的基石。它们允许你处理和操作数据,因此,学会识别变量并理解其用法至关重要。
什么是变量?
变量是编程中必不可少的部分,它们用于存储各种不同类型的数据。可以说,变量是编程的基石。这是因为它们允许你处理和操作数据。因此,能够识别变量并理解其使用方式非常重要。
在Python中声明变量非常简单。你只需要声明一个名称并为其赋值。变量这个词指的是可以改变的东西。在Python中,要改变一个已声明的变量,你只需要重新赋值或重新声明它。
变量命名的重要性
到目前为止,示例中使用的都是简单的命名约定,例如X、Y和Z。当与其他开发人员合作项目时,了解这些变量的含义或所指内容会变得越来越困难。作为一名程序员,随着时间的推移,你会编写大量代码。如果过了几个月,你很可能不记得代码的具体功能了。
使用像X和Y这样的通用变量,无法提供关于该变量及其用途的任何信息。为变量赋予在给定上下文中有意义的名称,将使你和其他程序员能够轻松理解代码的意图。
变量的核心功能

作为一名程序员,理解数据在程序生命周期中会发生变化这一点很重要。无论是通过网页表单获取用户输入,还是在代码内部处理变量,变量的关键功能都是保持对某种值的引用。
核心概念:变量是一个指向某个值的引用。其基本操作是赋值,例如:
x = 10
变量命名规范
现在你对变量及其在Python中的作用有了基本了解,接下来让我们更实际地演示变量及其使用方法。
我将演示如何在Python中使用变量,但首先我想简要谈谈命名规范。作为开发人员,在命名变量时,你有不同的选择。
一种选择是驼峰命名法。第一个单词的首字母小写,之后每个单词的首字母大写,单词之间没有空格。例如,如果我有一个变量叫myName,我会将my的m小写,name的n大写,其余字母小写,单词之间没有空格。
另一种方法是蛇形命名法。使用蛇形命名法时,所有字母都保持小写,但单词之间使用下划线连接。所以,如果我想创建变量my_name,使用这种方法的结果就是my_name。
尽管作为开发人员你有不同的选择,但在整个程序中创建变量时保持一致是一个好主意。
变量的声明与使用
让我清空屏幕以便开始。在Python中,我通过初始化一个变量并为其赋值来创建变量。我只需要命名变量即可,例如,如果我输入x = 5,我就声明了变量并为其赋值。
我也可以通过调用print语句并传入变量名(本例中为x)来打印变量的值。所以我输入print(x)。当我运行程序时,我得到值5,这是我赋予初始变量的值。
让我再次清空屏幕。在声明变量时,你有几个选项。你可以声明任何不同类型的变量值。例如,x可以等于一个名为“hello”的字符串。为此,我输入x = "hello"。然后我可以再次打印该值,运行它,我发现输出是单词“hello”。
在幕后,Python会自动为你分配数据类型。你将在后续关于数据类型的视频中了解更多信息。
多重赋值与变量操作
你也可以声明多个变量并将它们赋值为同一个值。例如,让a、b和c都等于10。我通过输入a = b = c = 10来实现。我分别打印所有三个值,当我再次点击运行按钮时,我发现所有这三个赋值都具有值10。
同样,在继续下一个示例之前,我清空屏幕。
你还有另一个选项,即进行多重赋值。例如,我输入用逗号分隔的a, b, c,等于用逗号分隔的1, 2, 3。通过这种方式,我将每个值分配给了对应的字母,所以a等于1,b等于2,c等于3。为了测试这一点,我可以打印所有三个变量。点击运行,我会发现值1、2、3与上面的声明相对应。
变量的重新赋值与删除
你应该了解的另一个重点是变量赋值以及如何更改它。变量是可以改变的。在程序的生命周期中,你将更改变量的值或赋值本身,因此你需要知道如何操作。让我们探讨另一个例子。
我输入a = 10并打印该值。之后,我将a的值更改为5,并再次打印该值。当我点击运行按钮时,第一行打印出10,第二行打印出5,因为值被重新赋值了。
最后,你需要知道如何删除变量。我的变量是a,它的值是10,我已经打印出来了,然后在新的一行我输入删除命令del,后跟一个空格和字母a,它代表我的变量。然后我使用print函数打印该变量,接着我点击运行按钮。首先给出的值是10,因为变量仍然存在,但在删除之后,它显示一个错误,说a未定义。
总结

本节课中我们一起学习了变量的核心知识。
你刚刚学习了变量命名规范。现在你知道如何声明变量并为其赋值。你也知道如何声明不同类型的变量值。你可以声明多个变量并将它们赋值为同一个值,也可以进行多重赋值。最后,你还学习了如何删除变量。
这为我们带来了本视频的结尾。你现在可以识别变量并了解如何在Python中使用它们了。
Python 10:基本数据类型
在本节课中,我们将要学习Python编程语言中的基本数据类型。理解数据类型是编程的基础,它决定了计算机如何解释和处理数据。我们将逐一介绍Python的五种主要字面量数据类型,并通过示例说明它们的特点和用法。
概述

计算机系统需要解释编程中不同的数据值,数据可以有不同的类型。数据类型是与数据相关联的属性,它告诉计算机系统如何解释其值。了解使用何种数据类型可以确保数据以期望的格式被收集和处理,同时保证每个属性的值符合预期。
数据类型简介

Python提供了原始数据类型,允许将数据赋值给变量或常量。五种主要的字面量数据类型包括:数值型、序列型、字典型、布尔型和集合型。

其中一些数据类型可以进一步细分。例如,数值型数据类型可以包含整数、浮点数和复数。现在,让我们从数值型开始,更详细地讨论这些数据类型。
数值型数据类型
在编程中,你需要决定哪种类型适合你的需求。例如,在处理货币时,你很可能会使用浮点数类型,因为它允许计算小数位。为了确定变量的类型,Python提供了一个名为 type 的函数,它将根据传入的变量返回其类型。
Python提供了三种不同的数值类型:整数、浮点数和复数。
- 整数:
int类表示任何非分数数字,即没有小数位的整数。这些数字可以是正数或负数,例如10或-10。 - 浮点数:
float类是包含小数位的数字。例如10.5或6.7。 - 复数:
complex类用于表示复数,由实数和虚数部分组成。例如a = 10 + 10j。
序列型数据类型

上一节我们介绍了数值型,本节中我们来看看序列型数据类型。序列类型被归类为容器类型,它们在一个有序列表中包含一个或多个相同类型的元素。序列中的元素可以根据其索引进行访问。


Python有三种不同的序列类型:字符串、列表和元组。

以下是每种类型的简要说明:
- 字符串:字符串是由单引号或双引号括起来的字符序列。字符串由
str类表示。 - 列表:列表是一个或多个不同或相似类型的序列,本质上是一个数组,数据存放在方括号
[]内。每个项目都可以通过其索引访问。 - 元组:元组在许多方面与列表相似,它包含一个或多个类型的有序序列,但主要区别在于它是不可变的。这意味着元组内的值不能被修改或更改。元组由
tuple类表示,数据包裹在圆括号()内。
字典型数据类型
接下来要探讨的数据类型是字典。字典以键值对的对象结构存储数据。每个值都可以通过其键直接访问。字典也可以存储任何数据类型。
例如,假设你声明一个名为 Ed 的变量并为其分配一个字典。该字典包含一组键值对:第一对是 ‘a’: 22,其中 ‘a’ 是键,22 是值;第二对是 ‘b’: 44.4,其中 ‘b’ 是键,44.4 是值。然后,你可以通过访问其键 ‘a’ 来输出值 22。
布尔型数据类型
现在,让我们探索布尔数据类型,它简单地表示为 True 或 False。结合逻辑运算符,布尔值用于检查条件是真还是假。
在这个例子中,我检查值 True 和 False 的底层数据类型,返回的类是 bool,意味着它是布尔型。
集合型数据类型
最后一个数据类型是集合,它是一个无序、无索引且不包含重复值的集合。
让我演示一下这个数据类型的一个例子。假设我将一组四个项目赋值给名为 example_set 的变量。然后,我通过将其传递给 type 函数来检查 example_set 变量中存储的值的类型。Python报告说,example_set 变量保存的底层数据类型是一个集合。

变量与类型推断
在编程中,数据类型是一个重要的概念。变量可以存储不同类型的数据,而不同类型的数据可以做不同的事情。让我们更详细地探讨这些。

每当你在Python中声明一个变量时,数据类型会根据该变量的值自动分配给你。
让我通过输入一个名为 a 的变量并将其赋值为 10 来演示这一点。为了检查Python分配的数据类型,我选择 print 并使用 type 函数,然后将变量 a 作为参数传入并运行。从终端的输出中,我可以看到分配了 int 类。
这是另一个例子:我使用变量 b 并为其分配一个小数值 2.3。为了检查Python分配的数据类型,我打印出 type(b) 并运行。从终端的输出中,我可以看到分配了 float 类,因为这里有一个小数点。这与标准的整数赋值不同。
要声明一个字符串变量,我用单引号或双引号将文本括起来。再次运行带有 type 函数的 print 语句,并将变量 c 作为参数传入。当我运行时,终端中的输出现在显示类 int、float 和 str。
这个序列也适用于其他数据类型。例如,我可以使用变量 d 并通过赋值 [1, 2, 3, 4] 来创建一个数字列表。当我运行带有 type 函数的 print 语句并将变量 d 作为参数传入时,在我点击运行后,会显示 list 类。
每次我为特定变量赋值时,Python在后台会自动分配该变量的正确数据类型。


总结
本节课中我们一起学习了Python中的不同数据类型。我鼓励你在练习代码中开始尝试使用这些数据类型。掌握它们是进行有效Python编程的关键第一步。
Python 11:字符串操作 🧵
在本节课中,我们将要学习Python中一个非常重要的数据类型:字符串。你将了解如何声明和使用字符串,理解字符串作为字符序列的特性,并掌握访问序列中单个元素的方法。
什么是字符串?
在Python中,字符串是一个由字符组成的序列,需要用单引号或双引号括起来。
你可能知道,计算机只能理解由0和1组成的二进制代码。这意味着字符需要被转换成计算机能够解释的形式,这个过程被称为编码。Python使用一种名为Unicode的编码标准与计算机进行通信。
如何声明字符串?
Python提供了几种声明字符串的方式。
以下是声明字符串的两种主要方法:
- 单引号声明:将字符放在单引号内。例如:
a = 'hello' - 双引号声明:将字符放在双引号内。例如:
b = "hello"
两种引号类型都是有效的声明方法,选择哪一种主要取决于个人偏好。但最好在代码中保持一致性。
单行字符串与多行字符串
字符串可以是单行的,也可以跨越多行。
一个单行字符串的示例如下:
a = 'This is a single line.'
然而,有时字符串可能非常长,为了增强代码的可读性,我们希望将其分成多行。这时,可以在每行的末尾添加一个反斜杠 \ 来创建一个多行字符串。
例如:
b = 'This is a multi \
line string example.'
请注意,我在单词 line 前输入了一个空格,以便它与上一行字符串的最后一个单词分开。当我打印 b 时,反斜杠会将两个部分连接起来,使输出显示为一个完整的字符串。

字符串的重新赋值
如果需要,你可以重新为字符串变量赋值。例如,变量 name 的字符串值是 'John',但你想将其值改为 'Paul'。这可以通过简单地输入 name = 'Paul' 来完成。现在,当你打印 name 时,这个更新就会反映出来。
字符串作为字符序列
了解字符串本质上是一个字符序列非常重要,这意味着它本质上是一个数组。序列中的每个字符都可以根据其索引进行访问。
例如,Python字符串使用零索引,这意味着你可以使用方括号内的数字 0 来访问第一个字符,或者使用数字 2 来访问第三个字符。
如果你需要检查字符串的长度,Python提供了 len() 函数来帮助你。你可以将这个函数应用于一个具有字符串值的变量,它将返回一个代表字符串中字符数量的数字。
字符串操作示例
现在我们已经了解了Python中字符串的基本概念,让我们通过一些代码示例来探索字符串的实际应用。
首先,我来演示声明字符串的两种方法。

第一种方法是将字符放在单引号内。我输入 a = 'hello'。在下一行,当我输入 print(a) 并点击运行按钮时,我的代码返回字符串 hello 作为输出。
第二种方法类似,但使用双引号。我输入 b = "hello"。当我再次运行 print 函数时,它也返回字符串 hello。
接下来,我们看看单行和多行字符串。一个单行字符串的例子是:
a = 'This is a single line.'
当我运行打印 a 的值时,它按照我声明的方式打印出来。
为了创建一个多行字符串,我输入 b = 'This is a multi',在继续之前,我在这一行的末尾添加了一个反斜杠。在下一行,我输入字符串的延续部分 line string example.。现在,当我打印 b 时,反斜杠起到了连接两个部分的作用,使输出显示为一个单一的字符串。
字符串拼接
你可以对字符串进行的另一个操作是拼接,即将单独的字符串连接起来。
为了演示这一点,我首先创建两个新变量:
a = 'Hello '
b = 'there.'
请注意,我在 a 的末尾添加了一个空格。这次,我在括号内输入 print(a + b),然后得到两个连接在一起的字符串。加号 + 通常用作算术运算符,但当应用于字符串时,它会将它们组合起来。
访问字符与获取长度
关于字符串,还有一点需要知道:它们被视为字符的集合。这意味着,就像数组一样,你可以基于索引访问单个字符,也可以使用 len() 函数检查字符串的长度。
举个例子,我创建一个名为 name 的变量,其字符串值为 'John'。
现在,我只想打印这个字符串的第一个字符。为此,我运行 print(name[0])。Python中的字符串是零索引的,意味着序列计数从0开始,所以我将数字 0 放在方括号中。当我点击运行时,我得到字母 J。如果我将数字改为 3 并再次运行,我会得到字母 n,即字符串 John 中的第四个字符。
接下来,让我们使用 len() 函数检查这个字符串中有多少个字符。我启动一个 print 函数,在其中输入 len(name)。当我运行它时,它返回 4 作为长度。


总结
在本节课中,我们一起学习了Python中的字符串。具体来说,你现在知道了如何声明和使用字符串,并理解了它们是字符的序列。我们探讨了单引号和双引号声明、单行与多行字符串、字符串重新赋值、字符访问、长度获取以及字符串拼接等核心概念。掌握这些基础知识是进行更复杂文本处理的关键。下节课再见!😊
Python 12:类型转换 🎯
在本节课中,我们将要学习Python中的类型转换。类型转换是编程中一个基础且重要的概念,它允许我们在不同的数据类型之间进行转换,以满足数据处理和计算的需求。
概述
Python使用不同的数据类型来有效地处理和使用信息。有时,在收集了变量的值之后,你需要改变其数据类型。例如,用户在网站上提交表单,其中一个字段是整数,但数据以字符串形式传递。这是一个问题,因为要对以字符串形式保存的数字进行计算,唯一的方法是将其转换为整数数据类型。为此,你可以在Python中使用类型转换。
什么是类型转换?🤔
类型转换是将一种数据类型转换为另一种数据类型的过程。Python有两种不同的类型转换方式:隐式转换和显式转换。
上一节我们介绍了类型转换的基本概念,本节中我们来看看这两种转换方式的具体细节。
隐式类型转换

隐式数据类型转换由Python编译器自动执行,以防止数据丢失。例如,如果它检测到插入的值是小数,它会将int转换为float。

需要注意的是,Python只能在数据类型兼容的情况下转换值。int和float是兼容的,但string和int不兼容。
如果数据类型不兼容,Python将抛出类型错误。
显式类型转换
或者,开发者可以使用显式数据类型转换来执行类型转换。这是通过使用Python提供的函数来完成的。函数有很多,但一些最常见的是string、integer和float。
以下是Python中一些常用的显式类型转换函数及其用法:
str()函数:此函数用于将任何数据类型转换为字符串数据类型。要使用此函数,请键入str,后跟要转换的值,并用括号括起来。例如:str(123)。int()函数:要使用此函数,请键入int,后跟要转换的值,并用括号括起来。例如:int("123")。float()函数:这是另一种常见的类型转换函数。同样,键入单词float,并在括号内添加要转换的值。例如:float(123)。
Python还有更多的类型转换函数,它们也具有类似的结构。以下是其他一些函数:
ord():返回一个表示底层Unicode字符的整数。hex():将给定的整数转换为十六进制字符串。oct():接受一个整数并返回表示八进制数的字符串。- 还有
tuple()、set()、list()和dict(),你将在课程后面学到更多关于它们的内容。

总结
在本视频中,你学习了Python中的类型转换。重要的是要记住,数据类型并非不可改变。如果需要,你可以使用Python提供的函数来转换数据类型。掌握类型转换是进行有效数据处理和确保程序正确运行的关键一步。
Python 13:用户输入与控制台输出
在本节课中,我们将要学习Python中两个核心功能:如何从用户那里获取输入,以及如何将数据输出到控制台。掌握输入和输出是编写交互式程序的基础。
概述:输入与输出
与其他编程语言一样,Python专注于从用户或其他服务获取输入并提供输出。Python提供了许多辅助函数,使得执行这两项操作变得非常容易。
你可能还记得,我们使用 print 函数来输出变量和其他值。在本节中,你将更深入地了解 print 函数,并学习如何使用另一个新函数——input。
输入函数:input
input 函数旨在从输入源获取数据,它可以有多种使用方式。例如,其最基本的用途之一是获取用户在键盘上键入的数据,然后可以将此输入打印到屏幕上。
在许多情况下,你需要直接从用户那里获取输入。例如,当你询问用户的电子邮件地址时,假设你想使用 input 函数提示用户输入他们的电子邮件地址,然后将该输入保存到一个名为 email 的变量中。
email = input("请输入您的邮箱地址:")
如果你运行这段代码,用户将看到一个提示,要求输入邮箱。然后,email 变量将包含该邮箱地址。

输出函数:print
现在,让我们切换回用于Python输出的 print 函数。它可以用于打印所有不同类型的数据,并允许更复杂的格式化。
print 函数本身接受任意数量的参数。例如,可以使用逗号分隔来按顺序打印数字,使用算术运算来打印方程式的输出,以及使用字符串连接来将两个字符串连接在一起。
Python的 print 函数还有一些可以作为附加参数传递的保留关键字。这些包括:
objects:即要打印到屏幕上的值。sep:定义被打印对象之间的分隔方式。end:定义在末尾打印什么。file:指定值打印到哪里,默认是标准输出(sys.stdout)。flush:一个布尔表达式,用于刷新缓冲区,本质上是将数据从临时存储移动到计算机的永久内存存储。
例如,假设你可以向 print 函数传递三个参数:字符串 "Hello"、另一个字符串 "World",以及内置参数 sep,其值被设置为包含逗号和空格的字符串 ", "。这将用作 "Hello" 和 "World" 字符串之间的分隔符,输出结果是 Hello, World。
在编程时,你经常需要知道变量的值并将其输出到屏幕上。Python允许在 print 语句内部直接进行格式化。你也可以通过在花括号内指定数字来控制顺序。例如,如果你打印两次相同的语句,但交换了数字,输出将会不同。
实践应用:代码示例
上一节我们介绍了输入和输出的基本概念,本节中我们来看看如何通过具体的代码示例来应用这些知识。
我将演示如何在Python中使用输入和输出。首先从演示 input 函数开始。
1. 基本输入
我首先输入 input(),然后点击运行命令。你会注意到它运行了输入函数,并为我提供了一个可以实际输入内容的控制台。我输入 hello 并按回车。因为没有收集数据,所以什么也没发生,我只是触发了输入函数,默认情况下它会打开命令行或控制台并允许我输入数据。
2. 带提示的输入
我还可以向 input 函数添加提示。例如,我可以向用户提问,比如“请输入一个数字”。我在 input 后面的括号内键入“请输入一个数字”。清除控制台后再次点击运行。现在输出会要求我输入一个数字。我输入 5 并按回车。同样,从输出角度看没有任何显示,因为我还没有对输入值做任何处理,只是演示了 input 函数的工作原理。
3. 保存输入值
如果我想获取输入的值,需要将其赋值给一个变量。所以我输入 num = input("请输入一个数字:")。再次清除控制台并点击运行按钮。它在控制台中要求我输入一个数字,这次我输入数字 6。现在,num 变量将包含数字 6。但为了看到它,我必须将该变量输出到屏幕。我可以使用另一个叫做 print 的函数来实现。
4. 输出变量
在这种情况下,我通过在输入后键入 print(num) 来打印这个数字。再次清除屏幕并点击运行。这次当被要求输入数字时,我输入了数字 7。按回车后,你会注意到输出打印了 7。
5. 多个输入
我想展示你可以收集多个输入,因为输入是按顺序工作的。所以我将这个变量称为 num1,并在下一行输入另一个名为 num2 的变量。这个变量的输入提示是“请输入第二个数字”,而我将第一个变量的输入提示改为“请输入第一个数字”,以使指令更清晰。我打印出 num1 和 num2 的值。print 语句接受这两个变量,因为它们用逗号分隔,并且会按顺序打印出来。再次清除控制台并点击运行。我输入 4 作为第一个数字,按回车,然后输入 5 作为第二个数字,再次按回车。你会注意到打印出了 4 和 5。
6. 在打印中进行算术运算
你也可以在 print 语句中进行算术运算。换句话说,你可以进行加法、减法、标准乘法和除法。所以,在 print 语句中不使用逗号,而是输入 num1 + num2。再次清除屏幕并点击运行。我再次输入数字 5 和 4,然后得到 54。现在,这并不是我原本想做的,原因是两个变量都是字符串。这回到了你之前学过的关于数据类型的知识。如果我想进行算术计算,首先需要将每个变量转换为整数。
7. 类型转换
所以我可以在 num1 和 num2 上使用 int() 函数。再次点击运行按钮,输入相同的两个数字 5 和 4,但现在我得到的结果是 9。如果我想查看输入的类型,可以使用 type 函数检查数据类型。为此,我输入 print(type(num1))。让我清除屏幕。点击运行并在控制台中再次输入数字 5 和 4,它显示类型是 str(字符串)而不是 int(整数),而整数才是我真正想进行算术运算的类型。所以请注意,当你使用 input 时,得到的是一个字符串。你很可能需要使用显式的数据类型转换将其转换为所需的数据类型。
8. 字符串连接
print 语句也可以用于字符串连接。所以,我将 num1 改为 str1,对 num2 也做同样的操作,改为 str2。然后我将输入提示修改为“请输入您的名字”对应 str1,以及“请输入您的姓氏”对应 str2。之后,我打印出 "Hello ",然后使用连接,以便用户可以用他们的名字和姓氏来问候。现在我想运行这个程序,快速清除终端,然后点击运行。在控制台中,我为名字输入 Tom,为姓氏输入 Jones。结果是输出了 Hello Tom Jones,所以连接也可以与 print 语句一起使用。
9. 字符串格式化
最后,你还可以改变分配变量的方式,不必使用连接,可以直接使用字符串替换。为此,我将使用Python中的一个叫做 format 的函数。根据括号的顺序,你可以传入想要替换的变量,在这个例子中是 str1 和 str2。再次点击运行,我输入用户名 Tom Jones,然后打印出 Hello Tom Jones。
总结

本节课中我们一起学习了Python中的输入和输出功能。我们深入探讨了如何使用 input 函数从用户那里获取数据,以及如何使用 print 函数以多种方式(包括基本打印、变量输出、算术运算、字符串连接和格式化)将数据输出到控制台。记住,input 函数默认返回字符串类型,因此在需要进行数值计算时,务必进行类型转换。掌握这些基础是构建更复杂、交互性更强的Python程序的关键一步。
Python 14:数学与逻辑运算符 🧮
在本节课中,我们将要学习Python中的运算符。运算符是告诉Python执行特定操作的符号,就像现实生活中的路标一样。它们可以帮助我们进行数学计算、逻辑判断,从而控制程序的流程。理解运算符是编写有效Python代码的基础。
什么是运算符?
运算符是告诉Python执行特定操作的符号。你可以把它们想象成现实生活中的路标。例如,假设你正在一条危险的路上行驶,你看到一个警示牌要求减速,然后遇到一个停车标志,最后是一个指示你右转的标志。你可能没有意识到自己正在一条危险的路上,但这些符号通过指示你执行特定操作来保证你的安全。同样地,当Python在代码中遇到你放置的运算符时,它也会执行那个特定的操作。这些操作可以是数学运算、逻辑运算和比较运算。
数学运算符
上一节我们介绍了运算符的基本概念,本节中我们来看看数学运算符。数学运算符用于简单和复杂的计算,本质上与标准计算器上的功能相同。
以下是Python中常用的数学运算符及其用法:
- 加法运算符 (
+): 加号是相加数字时必须使用的符号。例如:2 + 3。 - 减法运算符 (
-): 使用减号来相减数字。例如:3 - 2。 - 除法运算符 (
/): 用于除法的符号是正斜杠。除法是一个数除以另一个数的运算。例如:35 / 5。 - 乘法运算符 (
*): 用于乘法的符号是星号或星键。用它来使数字相乘。例如:7 * 4。
逻辑运算符
了解了基本的数学运算后,我们进入逻辑判断的领域。逻辑运算符在Python中用于条件语句,以确定结果为真(True)或假(False)。
以下是Python中主要的逻辑运算符:
- 与运算符 (
and): 此运算符检查所有条件是否都为真。例如:a > 5 and a < 10。 - 或运算符 (
or): 此运算符检查至少有一个条件为真。例如:a > 5 or b > 10。 - 非运算符 (
not): 此运算符在结果为真时返回假值。例如:not (a > 5)。
运算符通常与条件语句结合使用,以控制满足特定条件的程序流程。例如,假设一家餐厅根据以下两个条件提供折扣:客户是否是忠诚计划成员,以及消费是否超过100美元。为了确定这一点,你可以使用逻辑运算符编写代码来检查客户是否在忠诚计划中以及他们是否消费超过100美元。你将在后续课程中了解更多关于条件语句的内容。
实践演示

现在,让我演示如何在Python中使用数学和逻辑运算符。
数学运算符示例
数学运算符基本上提供了与标准计算器相同的功能,因此你可以执行加法、减法、除法和乘法等操作。
我从一个简单的加法示例开始。我使用print语句,以便输出显示在我的控制台中。我输入print,然后在括号内加上2 + 2,我期望返回的值是4。当我运行此语句时,终端中显示的值是4。
对于减法,我将加号改为减号。我点击运行按钮,显示的值是0。如果我计算2 - 2,答案是0。
对于除法,我将减号改为正斜杠。我在括号内输入35 / 5。我点击运行按钮,结果是值7.0。请注意,返回的值是浮点数(float)而不是整数(integer)。
现在让我们介绍乘法。我将正斜杠改为代表乘法的星号。我输入25 * 5。我点击运行按钮,得到返回值175。
逻辑运算符示例
以上是对数学运算符的简短介绍,接下来你将探索逻辑运算符。逻辑运算符用于控制应用程序的流程,逻辑运算符是and、or和not。让我们介绍每种的不同组合。
在这个例子中,我声明两个变量:A = True 和 B = True。基于这些变量,我使用一个if语句。我输入 if A and B:,在下一行我输入 print,并在括号和双引号内输入 "all true"。你很快就会学到if语句。但现在,只需知道只有当A和B都为真时,才会执行此print语句。终端中显示了"all true"的打印语句。
如果我将B的值改为False并再次运行该语句,则不会打印任何内容。原因是and语句作为一个条件,需要A和B都为真,它才会打印出该语句。
现在让我们介绍or运算符。所以我把and改成or,然后点击运行按钮。"all true"值再次被打印出来,原因是对于or运算符,如果A或B中有一个为真,if语句就为真。
如果我将两个变量的值都设置为False并点击运行按钮,则不会打印任何内容。这是因为A为假且B为假,所以if语句中的条件未得到满足。
在最后一个例子中,我将演示not运算符。我将保留or运算符,然后输入 if (not A) or (not B):。我点击运行按钮,返回的值是"all true"。它的作用是寻找A的否定,所以not A(不是假)就是真,以及B的否定,结果也是真。or条件检查其中任何一个是否为真。
现在我将A和B都改为True。我点击运行,没有打印任何内容。原因是它再次检查if not A,本质上是如果A不为真。在这种情况下,A为真,其否定为假,所以它不会满足那个条件。或者not B也导致假,同样不满足那个条件,因为两者都是真的否定。这仍然不会打印出任何值,因为同样,没有任何条件得到满足。
这就是在Python中使用数学和逻辑运算符的简要介绍,恭喜你。

总结
本节课中我们一起学习了Python中的数学和逻辑运算符。数学运算符(+, -, /, *)用于执行基础算术运算。逻辑运算符(and, or, not)则用于组合条件,进行布尔逻辑判断,是控制程序流程的关键。掌握这些运算符是编写更复杂Python程序的第一步。如果你想了解更多关于Python中数学运算符的信息,本课末尾有额外的阅读材料。
Python 15:控制流 if else else if 🔄
在本节课中,我们将要学习如何在Python编程中控制代码的执行顺序,即“控制流”。我们将重点介绍如何使用 if、else 和 elif 等条件语句来根据不同的情况执行不同的代码块。
什么是控制流?🤔
控制流指的是程序中指令执行的顺序。所有程序都需要根据不同的情况做出决策,并因此执行不同的操作或走向不同的分支。在Python中,有两种主要的控制流结构:条件语句(如 if、else、elif)和循环(如 for 循环和 while 循环)。本节我们将重点探讨条件语句。
条件语句详解
条件语句允许程序根据特定条件的真假来决定执行哪部分代码。以下是核心概念:
if语句:如果条件为真(True),则执行其下的代码块。if condition: # 条件为真时执行的代码else语句:捕获所有未被前面if或elif条件捕获的情况。else: # 所有前述条件均为假时执行的代码elif语句(即else if):如果前面的条件不成立,则尝试检查此条件。elif another_condition: # 前一个条件为假,且此条件为真时执行的代码
上一节我们介绍了控制流的基本概念,本节中我们来看看如何通过一个餐厅折扣系统的实际例子来应用这些条件语句。
实践:餐厅折扣系统 💰
假设一家餐厅希望根据顾客的消费金额应用不同的折扣。我们将编写代码来实现这个逻辑。

首先,我们定义一个变量来表示顾客的账单总额。
bill_total = 114
第一步:使用 if 语句
如果账单金额大于100,我们打印一条消息并应用一个折扣。
以下是实现此逻辑的步骤:
- 创建一个折扣变量。
- 使用
if语句检查条件。 - 在条件满足时,更新账单总额并打印信息。
- 最后,打印最终账单。
discount1 = 10
if bill_total > 100:
print("账单大于100")
bill_total = bill_total - discount1
print("总账单是:" + str(bill_total))
运行此代码,输出为:
账单大于100
总账单是:104
第二步:引入 else 语句
如果账单金额不大于100呢?我们需要处理这种情况。将 bill_total 改为95并运行代码,你会发现只输出了总金额。为了更清晰,我们添加一个 else 语句来打印另一条消息。
bill_total = 95
discount1 = 10
if bill_total > 100:
print("账单大于100")
bill_total = bill_total - discount1
else:
print("账单小于等于100")
print("总账单是:" + str(bill_total))
现在运行代码,输出为:
账单小于等于100
总账单是:95
到目前为止,你已经学会了使用 if 和 else 来控制程序的流程。接下来,我们让这个流程更进一步。
第三步:使用 elif 添加更多条件
现在,餐厅希望为消费超过200的账单增加一个更大的折扣。我们需要添加一个新的条件。
以下是实现此功能的步骤:
- 定义第二个折扣变量。
- 修改第一个
if条件,使其只处理100到200之间的账单。 - 使用
elif语句添加处理大于200的账单的条件。 - 在
elif代码块中应用第二个折扣。
bill_total = 210
discount1 = 10
discount2 = 20
if bill_total > 100 and bill_total < 200:
print("账单大于100且小于200")
bill_total = bill_total - discount1
elif bill_total > 200:
print("账单大于200")
bill_total = bill_total - discount2
else:
print("账单小于等于100")
print("总账单是:" + str(bill_total))
运行此代码,输出为:
账单大于200
总账单是:190

程序流程发生了变化:第一个条件(bill_total > 100 and bill_total < 200)为假,因此代码检查第二个 elif 条件(bill_total > 200)。该条件为真,所以打印了相应消息并应用了 discount2。由于前面的 elif 条件已满足,程序跳过了最后的 else 块。
总结 📝
本节课中我们一起学习了Python中控制流的核心——条件语句。你掌握了如何使用 if、else 和 elif 来根据不同的条件引导程序执行不同的路径。编写条件语句是编程的基本功,建议你在自己的代码中多加练习。下次当你需要做出决策时,可以思考一下其中涉及的条件,并尝试用Python代码将它们表示出来。
Python 16:match-case语句
在本节课中,我们将要学习Python中的match-case语句。这是一种用于替代多重if-elif-else条件判断的语法,它能让代码在处理多个条件时更加清晰和简洁。
从if语句到match语句
上一节我们介绍了如何使用if、else和elif语句来测试变量是否符合某些条件。
但在某些情况下,你需要测试一个变量是否符合许多条件。为了处理这种情况,你可以使用一种叫做match-case的语句。
在本节中,我们将学习如何将match语句作为if语句的替代方案。
一个对比示例:HTTP错误消息
现在让我们考虑一个例子,来对比match语句和if语句。假设你想编写代码,根据错误代码打印HTTP错误消息。
如果使用if语句,你需要编写if条件、多个elif条件,以及一个最终的else条件。像if、elif和else这样的条件语句在条件数量较少时工作得很好,但当条件数量很多时,你的代码会变得庞大、复杂且混乱。

幸运的是,使用match语句有一种更简洁的方法可以达到相同的结果。Python中的match语句是在3.10版本中引入的。使用match语句,你可以实现更清晰、更易读的代码,同时拥有与if控制语句完全相同的功能。
使用match语句的要点
以下是使用match语句时需要记住的几点:
- 你可以使用
|(或)运算符在条件语句中组合多个条件。 case _本质上是默认情况,如果所有case检查都没有匹配到,就会执行它。它相当于if代码块中的else。
代码演示与对比
现在让我用代码来演示这个例子。
# 使用if语句
http_status = 200
if http_status == 200:
print("success")
elif http_status == 201:
print("success")
elif http_status == 400:
print("bad request")
elif http_status == 500 or http_status == 501:
print("server error")
else:
print("unknown")
# 使用match语句
match http_status:
case 200 | 201:
print("success")
case 400:
print("bad request")
case 500 | 501:
print("server error")
case _:
print("unknown")
我们首先编写了一个简单的if语句来检查HTTP状态码。如果变量http_status的值匹配其中一个条件,它将打印出相应的消息。
现在,我在if语句下面添加一个match语句,以便进行清晰的比较。我将用相同的值测试同一个变量。
我输入match,然后是变量http_status和一个冒号。在下一行,我输入case,这相当于if,后面跟着值200。在另一行,我重复了if语句中针对200的操作,即打印单词“success”。换句话说,变量将与值200进行匹配,如果值相等,它将打印出“success”。
注意,此时http_status的值确实是200。让我们运行代码,看看if和match语句在终端中是如何处理的。单词“success”被打印了两次,因为http_status的值在我的代码中被匹配了两次:一次是针对if语句,一次是针对match语句。
现在,让我们将http_status的值改为201,然后再次运行代码。在这种情况下,“success”只打印了一次。你认为这是为什么?
因为在if语句中有一个针对值201的条件,但在match语句中没有。要在match语句中实现等效操作,你需要使用|(或)运算符。所以,我将光标放在200和冒号之间,添加一个|字符和值201。
我清理屏幕,然后再次点击运行。现在“success”又被打印了两次。所以在match语句中,|命令是if的简写形式。很棒的一点是,你可以在一个match语句中添加许多case语句。
但是,如果没有任何值与变量的值匹配呢?现在让我们将http_status的值改为,比如说550,看看会发生什么。我点击运行,这次打印了单词“unknown”。你可能想知道为什么。因为else语句就像一个“兜底”选项。如果值不匹配if或elif语句中的任何内容,默认将执行else语句,在本例中,它有一个打印单词“unknown”的函数。
同样,match语句也有一个默认情况,你可以通过输入case _:来添加它,然后在下一行打印“unknown”。让我们再次运行代码。很好,输出是“unknown, unknown”,这意味着if语句和match语句中的默认语句都被执行了。
我的match语句进展顺利,但它仍然需要一些调整,才能使其行为与给定的if语句完全一致。为此,我将添加更多case语句,用于测试与elif语句相同的值。
我输入case 400:,然后添加一个带有单词“bad request”的print命令。我添加另一个case和值500,并且我还需要像上面的elif语句一样测试501。所以,我再次添加一个|字符并输入501:。在下一行,我添加我想要打印的错误消息,即“server error”。
match通过组合|语句节省了一些空间,因此你不必像在if语句中那样每次都进行变量比较。让我们再次将http_status的值更改为501。我清理屏幕,然后点击运行,“server error”为两个语句都打印了。

现在你知道了两者之间存在一些差异,但match语句的功能与if语句完全相同。

总结
本节课中我们一起学习了match-case语句。总而言之,match语句将一个值与几个不同的条件进行比较,直到满足其中一个条件为止。
所以,你现在知道了如何使用match语句作为if语句的替代方案,来测试变量是否符合许多可能的值。match语句对于Python来说相对较新,在3.10版本之前,开发人员必须发挥创造力,编写自己的解决方案。在本课程后面,你将了解更多关于这些替代方法的知识。
Python 17:循环结构 🔄
在本节课中,我们将要学习Python中的循环结构。循环是一种强大的编程工具,它允许我们重复执行一段代码,直到满足特定条件为止。就像反复播放一首喜欢的歌曲一样,循环让程序能够高效地处理重复性任务。我们将重点介绍两种主要的循环类型:for循环和while循环,并通过简单的示例来理解它们的工作原理。
循环的基本概念
上一节我们介绍了循环的比喻,本节中我们来看看循环在Python中的具体含义。
循环用于遍历序列并访问其中的每个元素。在Python中,字符串、列表等都被视为序列。一个序列就是一个有序的集合。
使用for循环遍历字符串
让我们从一个使用字符串的基本循环示例开始。
首先,声明一个名为str的字符串类型变量。在Python中,字符串是一个序列,这意味着你可以遍历字符串中的每个字符。
以下是for循环的基本结构:
str = "looping"
for item in str:
print(item)

变量item是一个占位符,用于存储序列中的当前字符。你可能还记得,可以通过索引访问序列中的任何字符。for循环以同样的方式访问字符,并将当前值赋给item变量。这使我们能够访问当前字符并将其打印输出。
当代码运行时,输出将是单词“looping”的每个字母,每个字母单独占一行。
探索for循环与while循环
现在你已经了解了Python中的循环结构,让我通过一些代码示例来进一步演示它们如何工作,以输出一系列美味的甜点。
Python为我们提供了多种进行循环的方式,你现在将学习for循环以及while循环。
简单的for循环
让我们从简单的for循环基础开始。
要声明一个for循环,我使用for关键字。现在需要一个变量来存放值,这里我使用i。我还使用in关键字来指定要遍历的范围。我添加了一个名为range的新函数来指定范围内的项目数量,这里以10为例。
接下来,我通过按回车键移动到新行来执行一个简单的打印语句。我选择print函数,并在括号内输入文本“looping”和变量i的值。然后我点击运行按钮。
输出表明迭代循环遍历了0到9的范围。需要注意三个要点:
- 迭代从0开始,这是基于项目本身的索引。
- 每个
for循环通常从0开始。 - 大多数数组从0开始,因为它是数组中的第一个项目或索引中的第一个项目。在这种情况下,数组或索引中的最后一项将是9。
遍历列表的for循环
现在我想改变循环遍历的内容作为示例,我将在上方输入一个简单的数组并称之为favorites。
为此,我首先移除favorites前面的注释符号。接下来,我将当前for循环中的range函数替换为favorites以进行遍历。作为for循环一部分声明的i可以更改为任何值,这里我使用item。
我现在更改我的打印语句,在打印循环中包含item。我还将文本更改为“I like this dessert”。我点击运行按钮来打印输出流。
在这种情况下,它会依次调用五个甜点名称中的每一个,我们的打印语句将它们组合成一个句子。
使用while循环
接下来讨论的循环选项是while循环。
while循环与for循环略有不同。为了演示这种循环,我首先注释掉屏幕上的for循环。
让我们从使用while关键字开始。与for循环一样,我需要指定一个条件,根据值本身使循环运行n次。
首先,我需要声明一个计数器。我通过在循环语句上方输入count = 0来实现。接下来,我在while关键字后输入count,后跟小于号<和单词favorites。现在我插入函数len()来提供favorites的长度。这意味着循环将在count小于favorites长度时运行,换句话说,就是小于5时。
为了打印循环语句的值,我按回车键移动到新行。然后我选择print函数,在括号内输入文本“I like this dessert”。这里的关键区别在于,我需要使用索引来访问favorites数组中的项目。为此,我输入favorites[count]来表示索引。
重要的是,我现在需要递增count,以便它基本上与循环语句匹配。如果我不递增count,最终会陷入所谓的无限循环。这意味着它将一直循环下去,直到编译器因内存耗尽而停止它。
为了递增count,我按回车键移动到新行并添加count += 1。我清空屏幕并点击运行按钮。我得到了与for循环相同的打印输出。
在for循环中获取索引
需要注意的是,在标准的for循环中,我无法直接访问索引,但我可以使用enumerate函数来实现。
因此,我更改当前的for循环语句,添加idx,它变为for idx, item in enumerate(favorites):。在下一行,为了打印输出,我将文本“I like this desserts”替换为idx,然后点击运行按钮。
结果显示数组内项目的索引和值。

总结
本节课中我们一起学习了Python中的循环结构。我们探讨了for循环如何用于遍历序列(如字符串和列表),以及while循环如何在满足特定条件时重复执行代码块。我们还了解了如何避免无限循环,以及如何使用enumerate函数在for循环中同时获取元素的索引和值。掌握这些循环结构是进行有效编程和数据处理的基础。
Python 18:嵌套循环及对算法复杂度的影响 🔄
在本节课中,我们将要学习Python中的嵌套循环。嵌套循环是解决更复杂问题的强大工具,例如遍历多维数据结构。我们将详细拆解嵌套循环的工作原理,并通过代码示例直观展示其执行过程。同时,我们也会探讨嵌套循环对程序运行时间的影响,即算法的时间复杂度问题。
嵌套循环的工作原理
上一节我们介绍了基本的循环结构,本节中我们来看看如何将一个循环放置在另一个循环内部,即嵌套循环。
在Python中,嵌套循环通过在外层循环内部缩进编写内层循环来实现。其执行流程如下:
- 首先,外层循环开始执行。
- 然后,程序进入内层循环。
- 内层循环会一直运行,直到达到其自身的范围限制(例如,循环10次)。
- 一旦内层循环执行完毕,程序会返回到外层循环,进行下一次迭代。
- 接着,程序再次进入内层循环。
- 这个过程会持续进行,直到外层循环也达到其自身的范围限制。
嵌套循环示例:遍历两个列表
为了更具体地理解嵌套循环,让我们看一个遍历两个列表的例子。

假设我们有两个包含1到9整数的列表,以及一个初始值为0的计数器变量。我们使用两个循环:外层循环遍历第一个列表,内层循环遍历第二个列表。
以下是代码逻辑的简化描述:
list_one = [1, 2, 3, 4, 5, 6, 7, 8, 9]
list_two = [1, 2, 3, 4, 5, 6, 7, 8, 9]
count = 0
for i in list_one: # 外层循环运行9次
for j in list_two: # 内层循环运行9次
count += 1 # 每次内层循环迭代,计数器加1
运行此代码后,计数器count的输出结果为81。让我们来分解一下:
- 外层循环总共运行 9 次。
- 对于外层循环的每一次迭代,内层循环都会完整地运行 9 次。
- 因此,内层循环总共运行的次数是 9 × 9 = 81 次。
为了可视化这个过程,我们可以稍微修改循环代码,使其打印出每次迭代的索引。
代码演示:构建二维网格
现在,让我们在代码编辑器中实际编写一些嵌套循环的例子。
首先从一个简单的例子开始,编写一个for循环:
# 外层循环
for i in range(10):
# 内层循环
for j in range(10):
print(0, end=" ") # 打印0并以空格结尾,保持输出整齐
print() # 打印空行,使每次外层迭代后换行
如果运行这个for循环,系统会打印出一个10x10的、由0组成的二维数组网格。这演示了嵌套循环如何工作。
- 当外层
i循环开始时,程序会进入内层j循环。 - 内层循环必须完全执行完毕(打印10个0)后,程序才会返回到外层循环开始下一次迭代(
i增加1),然后再次进入内层循环。
我们可以通过修改外层循环的范围来验证这一点。例如,将外层循环改为range(2),则只会打印出两行0。
嵌套循环与时间复杂度
使用嵌套循环时需要考虑的一个重要问题是复杂度,通常被称为时间复杂度。
数组(或循环范围)越大,代码运行所需的时间就越长。让我通过为一个更大范围的循环添加时间戳来展示这一点。
以下是测量代码运行时间的示例:
import time
# 记录开始时间
start_time = time.time()
# 嵌套循环
for i in range(100):
for j in range(100):
pass # 执行某些操作,这里用pass省略
# 记录结束时间并计算耗时
end_time = time.time()
elapsed_time = end_time - start_time
print(f"代码运行耗时:{round(elapsed_time, 2)} 秒")
运行后,可能会输出类似0.0秒的时间,因为循环较小,运行极快。
现在,让我们逐步增加循环范围,观察时间变化:
- 情况一:
range(100)和range(100)-> 耗时约0.01秒。 - 情况二:
range(100)和range(1000)-> 耗时增加到约0.04秒。 - 情况三:
range(100)和range(10000)-> 耗时显著增加到约0.45秒。
由此可见,数组或循环范围越大,程序完成所需的时间就越长。在处理大型数据集时,这种影响会非常巨大。
因此,始终牢记如何优化代码以提高运行效率,并考虑代码运行所需的时间,是非常重要的。
总结
本节课中我们一起学习了嵌套循环及其对算法复杂度的影响。
我们首先了解了嵌套循环的基本概念和执行流程,即内层循环在外层循环的每次迭代中完整执行一次。接着,我们通过遍历两个列表的例子和构建二维网格的代码演示,直观地看到了嵌套循环的工作方式。最后,我们探讨了嵌套循环带来的核心问题——时间复杂度,并通过实验验证了循环范围(数据规模)的增大会导致运行时间显著增加,这强调了编写高效代码和进行算法优化的重要性。

你刚刚学习了嵌套for循环,并了解了时间复杂度这一重要问题。
Python 19:模块小结 🎉
在本节课中,我们将对“Python入门”模块进行总结,回顾从编程基础到控制流与条件语句的所有核心知识点。

恭喜你完成了控制流与条件语句的学习,也标志着“Python入门”模块的结束。让我们来回顾一下你所学到的内容。
模块知识回顾 📚

现在你已经掌握了以下核心技能:

编程基础与Python概述
上一节我们介绍了控制流,本节我们来回顾整个模块的起点。你学会了如何解释编程的历史及其一般工作原理。你也能够描述Python的优势及其应用场景。


开发环境与执行方式
以下是关于环境设置与代码执行的关键点:
- 评估你的系统是否正确设置了Python开发环境。
- 识别通过命令行与集成开发环境运行代码的差异。

Python语法与核心概念
Python的语法规则是编程的基石。你理解了语法和空格在Python中的重要性。你也学会了描述变量是什么以及如何使用它们。

数据类型与操作
以下是关于数据类型及其处理的核心内容:
- 识别Python中的数据类型。
- 解释如何声明和使用字符串。
- 描述两种类型的类型转换及其应用方法。
- 描述用户输入和终端输出的基础知识。

运算符与程序控制
你能够识别Python中的数学和逻辑运算符。更重要的是,你学会了使用条件语句来控制程序流程,并使用match case语句作为if语句的替代方案。

循环结构
最后,我们深入了重复执行代码的机制。你能够解释循环结构及其使用方法,并理解嵌套循环的工作原理及其运作方式。

总结 🏁

本节课中,我们一起学习了Python编程的基础结构与核心规则。你现在已经准备好创建自己的程序了。
出色的工作,下次见。
Python 20:函数

在本节课中,我们将要学习Python中的函数。函数是编程中的核心概念,它允许我们将代码组织成可重用的模块,从而提高代码的效率和可读性。
🧩 什么是函数?
在最基本的层面上,函数可以被视为一组指令,它接收输入并返回输出。
例如,print函数的主要任务是打印一个值。这个值通常被打印到屏幕上,并作为参数传递给print函数。在我们这里的例子中,字符串“hello world”就是传递给print函数的值。
在本视频结束时,你将能够:
- 在Python中声明一个函数。
- 向函数传递数据。
- 从函数返回数据。
🔧 如何声明函数?
上一节我们介绍了函数的基本概念,本节中我们来看看如何声明一个函数。
一个Python函数是一个模块化的代码块,可以被重复使用。在本课程中,你已经使用过一些Python函数,例如print和input。两者都是函数,并且各自都有要完成的特定任务或动作。input函数会接受参数,但也会接受来自用户的输入。

函数使用def关键字声明,后跟函数名和要完成的任务。可选参数也可以在函数名后的一对圆括号内添加。
以下是创建一个将两个值相加的函数的示例:
def sum(x, y):
return x + y
- 键入
def关键字。 - 后跟函数名
sum。 - 然后输入
x和y作为参数。 - 最后输入
return x + y作为要完成的任务。
💡 函数实战演示
现在我将对函数进行一个实际演示,展示如何声明它们、如何使用它们,以及它们如何通过将代码放入可重用的结构中来简化你的代码。
让我们从一个简短的例子开始,解释如何根据账单的总价值为客户计算税额。
我将从声明两个变量开始。我键入第一个名为bill的变量,并为其分配数字175.00。我知道这将是一种称为浮点数的数据类型,因为我使用了小数点,这是货币的惯例。
第二个变量是税率,这是应适用于账单的百分比税率。所以我输入15。
然后我想做的是计算账单本身的税额。我将其添加到另一个名为total_tax的变量中。然后进行计算,即bill乘以tax_rate,然后除以100以获得美元金额。为了输出这个值,我打印total_tax并传递total_tax变量,然后运行程序。
总税额是26.25,这是175的15%。在现实世界中,每个客户的账单价值都不同,税率也可能变化。每次更新每个变量是低效的。为了克服这个问题,我将创建一个可重用的函数。
要开始创建函数,我使用def命令。然后我会给它一个与其执行任务相关的名称,所以在这种情况下,它将是calculate_tax。使用函数,你可以传入参数,其目的是使其更具动态性。
因此,考虑我需要接收的参数,我将接收一个bill(账单本身的总价值),以及一个tax_rate(税率)。然后像之前一样,我将通过取bill,乘以tax_rate,然后除以100来计算总税额。
好的,然后我执行return (bill * tax_rate) / 100。
现在我可以删除之前为变量和计算所做的声明。对于函数,如果你按原样运行当前代码,它将不会返回任何内容,因为函数只有在实际被调用时才会运行。
我来演示一下。如果我执行一个print,我可以调用calculate_tax,然后像之前一样传递参数,175是总账单,税率将是15。
我还会放入一个total_tax,然后点击运行,总税率是26.25。
如果我想改变税率,我可以重用同一个函数。我将再次调用函数calculate_tax,给它一个不同的账单值,比如164.33。这次我将税率改为22%。清空屏幕,然后点击运行,我的第二项总税额是36.1526。
为了让输出更整洁、视觉上更吸引人,我将放入一个round函数,它允许控制我想要返回的小数位数。在这种情况下,我将设置为两位,然后重新运行代码。这样就整洁多了,结果是36.15。
函数的一个优点是,你可以一次性更新它,任何调用该函数的代码部分都会获得这些更改。

📝 总结
本节课中我们一起学习了Python中的基本函数,包括如何声明函数,以及如何向函数传递数据和从函数返回数据。函数是构建模块化、可维护代码的基石,掌握它们对任何程序员都至关重要。
Python 21:变量作用域 🐍
在本节课中,我们将要学习Python中一个至关重要的概念——变量作用域。理解作用域能让你更好地控制代码中的元素,减少因意外修改而导致的错误。课程结束时,你将能够理解Python作用域的基础知识,并识别四种不同类型的作用域。
概述:什么是作用域?
在深入探讨作用域的细节之前,首先需要明确一点:Python拥有不同类型的作用域。作用域的目的是保护变量,使其不会被代码的其他部分意外更改。例如,如果你在全局作用域中声明了变量A,那么你可以在局部代码中调用它;但反过来,在局部作用域中声明的变量,则无法从外部直接访问。
四种作用域类型
以下是Python中四种作用域,按照覆盖范围从小到大排列:
- 局部作用域
- 闭包作用域
- 全局作用域
- 内置作用域
它们合称为 LEGB。位于内置作用域和全局作用域中的变量,可以从代码的任何位置访问。
作用域规则详解

上一节我们介绍了四种作用域类型,本节中我们来看看它们的具体规则和访问权限。
- 全局与局部访问:全局变量可以在局部代码中被调用。但局部变量无法从外部访问。
- 嵌套访问:最内层的函数可以访问外部几乎所有内容(即可以访问闭包变量和全局变量)。
- 外部限制:从外部无法访问嵌套或闭包作用域中的变量(包括局部变量和闭包变量)。
通常,在应用程序中不鼓励使用全局变量,因为它会增加输出出错的可能性。
实践演示:四种作用域
现在,我将通过一个实际的代码演示来探索Python的四种不同作用域。
首先,我声明一个全局变量 my_g 并赋值为10。
my_g = 10 # 全局变量
接下来,我声明一个名为 fn1 的函数。
def fn1():
在这个函数内部,我声明另一个变量,称之为局部变量 local_v,并赋值为5。
local_v = 5 # 局部变量
为了展示全局变量可以从任何地方访问,我可以执行一个打印语句。
print("访问全局变量:", my_g) # 可以访问全局变量my_g
要运行这个函数,我需要显式地调用它。
fn1() # 调用函数
运行后,全局变量 my_g 的值10被打印出来。但是,如果我尝试在函数 fn1 外部打印其内部的局部变量 local_v,则会返回一个错误。
print(local_v) # 这将导致 NameError: name 'local_v' is not defined
这是因为 local_v 只能在函数 fn1 的局部作用域内访问。
接下来,为了说明闭包作用域,我将在 fn1 内部声明第二个函数 fn2。
def fn1():
local_v = 5
print("访问全局变量:", my_g)
def fn2(): # 内部函数,创建闭包作用域
enclosed_v = 8 # 闭包变量
print("访问闭包变量:", enclosed_v) # 在fn2内部可以访问enclosed_v
print("访问全局变量(从fn2):", my_g) # 也可以访问全局变量
fn2() # 在fn1内部调用fn2
fn1() # 调用fn1
运行上述代码,会打印出“访问全局变量: 10”和“访问闭包变量: 8”。这演示了内部函数 fn2 可以访问其外部的闭包变量 enclosed_v 以及全局变量 my_g。
然而,同样的规则对外部依然适用。如果我尝试在 fn1 外部访问变量 enclosed_v 或 local_v,会得到变量未定义的错误。
最后一种作用域是内置作用域,你在编写Python代码时一直在使用它。内置作用域指的是诸如 print 和 def 之类的保留关键字。内置作用域覆盖了Python的所有语言特性,这意味着你可以在最外层的作用域或函数、类的最内层作用域中访问它。

总结
本节课中我们一起学习了Python变量作用域的核心概念。我们了解到作用域通过限制变量的可访问范围来保护数据,并详细探讨了四种作用域类型:局部、闭包、全局和内置(LEGB)。记住,内部代码可以访问外部变量,但外部代码通常无法访问内部变量,且应谨慎使用全局变量以避免意外错误。掌握这些知识,将帮助你编写出更健壮、更易维护的Python代码。
Python 22:列表 🗂️
在本节课中,我们将要学习Python中一个非常重要的数据结构——列表。列表是存储和管理数据序列的强大工具,我们将了解它的基本概念、创建方法以及如何对列表进行增删改查等操作。
列表的基本概念
列表是一个包含一个或多个相同或不同数据类型的元素序列。在Python中,列表本质上是一个可以容纳任何数据类型的动态数组。

创建与访问列表


上一节我们介绍了列表的基本概念,本节中我们来看看如何创建列表并访问其中的元素。

以下是声明列表的几种方式:
list1 = [1, 2, 3, 4, 5]:创建一个包含整数的列表。list2 = [“A”, “B”, “C”]:创建一个包含字符串的列表。list3 = [“string”, 100, True, 3.14]:创建一个包含多种数据类型的列表。列表可以存储任何数据类型,存储方式相同。
需要记住的是,列表是基于索引的。索引从0开始计数。
例如,要访问list1中的数字3,因为索引从0开始,所以数字3的索引是2。访问它的代码如下:
list1[2]
执行print(list1[2])会输出值3。

列表还支持嵌套,即一个列表中可以包含另一个列表。例如:
list4 = [1, [2, 3, 4], 5, 6]
任何数据类型都可以存储在列表中,包括列表本身。

向列表添加元素



了解了如何创建和访问列表后,我们来看看如何向列表中添加新元素。Python提供了几种方法来实现。

以下是向列表添加元素的几种方法:

1. 使用 insert() 函数
insert()函数需要指定插入位置的索引和要插入的值。例如,在列表末尾插入数字6:
list1.insert(len(list1), 6)
这里len(list1)用于获取列表的当前长度,从而确定末尾的索引位置。


2. 使用 append() 函数
append()函数更简单,它直接将元素添加到列表末尾,无需指定索引。
list1.append(6)

3. 使用 extend() 函数
extend()函数用于将一个列表中的所有元素添加到另一个列表的末尾。它可以一次性添加多个元素。
list1.extend([6, 7, 8, 9])

从列表中移除元素


学会了添加元素,自然也需要知道如何移除元素。Python同样提供了多种从列表中删除元素的方式。
以下是从列表中移除元素的几种方法:


1. 使用 pop() 函数
pop()函数通过索引移除并返回一个元素。如果不指定索引,默认移除最后一个元素。
list1.pop(4) # 移除索引为4(即第5个)的元素
2. 使用 del 关键字
del关键字直接根据索引删除列表中的元素,但不返回该元素的值。
del list1[2] # 删除索引为2(即第3个)的元素


遍历列表
列表的一个主要用途是存储大量数据并对其进行处理。遍历列表是访问其中每个元素的基本操作。

我们可以使用简单的for循环来遍历列表。以下是遍历list1并打印每个元素的示例:
for x in list1:
print(x)
执行这段代码会依次打印出列表中的所有值。

本节课中我们一起学习了Python列表的核心知识。你了解了Python中的列表如何作为动态数组工作,探索了列表的创建和索引访问,并学习了如何使用列表的内置函数来访问、修改、添加和移除列表中的元素。列表是Python编程中最基础且最常用的数据结构之一,熟练掌握它对后续学习至关重要。
Python 23:元组
概述
在本节课中,我们将要学习Python中的元组。元组是一种用于存储多种类型数据的数据结构,它能帮助我们创建结构良好、性能优异的代码。我们将学习如何声明元组、访问其中的元素、使用相关方法,并理解其与列表的关键区别。
声明元组
要声明一个元组,首先需要定义一个变量,然后使用赋值运算符=,最后用圆括号()来包裹元组内的元素。

代码示例:
my_tuple = (1, "strings", 4.5, True)
一个元组可以接受任何数据类型的混合,范围可以从整数(如1)、字符串、浮点数(如4.5)到布尔值(如True)。
访问元组元素
要访问元组中的任何元素,可以使用与列表类似的方法,即通过索引来引用。
代码示例:
print(my_tuple[1])
记住,索引总是从0开始。运行上述代码,它将返回字符串”strings”。
确定元组类型
Python提供了type函数来确定变量的类型。
代码示例:
print(type(my_tuple))
运行此代码,将得到<class ‘tuple’>,表明这是一个元组类。
元组的替代声明方式
我们也可以不使用圆括号来声明元组,它会产生相同的效果,并且仍然被归类为元组。然而,最佳实践是使用圆括号,以提高代码的可读性。
元组的方法
元组提供了count和index两种主要方法。
以下是count方法的使用示例,它用于查找某个值在元组中出现的次数。
代码示例:
print(my_tuple.count("strings"))
运行此代码,将返回计数1。
接下来,我们看看index方法。它用于返回某个值在元组中首次出现的索引位置。
代码示例:
print(my_tuple.index(4.5))
运行此代码,将返回索引2,这意味着浮点数4.5位于元组的索引2位置。
遍历元组
我们也可以对元组进行循环遍历,即迭代其中的所有值并打印出来。
代码示例:
for x in my_tuple:
print(x)
运行此代码,将依次输出:1、”strings”、4.5和True,即元组中的所有值。
元组与列表的关键区别
元组与列表的一个关键区别在于,元组的值是不可变的。这意味着一旦元组被创建,其中的元素就不能被修改。
为了证明这一点,我们尝试修改元组中的第一个元素。
代码示例:
my_tuple[0] = 5

运行此代码,将会得到一个错误:TypeError: ‘tuple’ object does not support item assignment。这是因为元组中声明的任何内容都是不可变的。
总结

本节课中,我们一起学习了Python中的元组。我们了解了如何声明元组、访问其内容、使用count和index方法,以及如何遍历元组。最重要的是,我们理解了元组的不可变性是其与列表的核心区别,这决定了元组适用于那些不应在程序运行过程中被修改的数据集合。
Python 24:集合操作入门指南 🧮
在本节课中,我们将要学习Python中的集合(Set)。集合是一种非常有用的数据结构,它可以帮助我们以特定的格式存储某些类型的数据。我们将了解如何创建集合、它与列表的区别,以及如何使用集合进行各种数学运算。
创建与打印集合

首先,我们来声明一个集合。我们可以通过声明一个名为setA的简单变量,然后使用花括号来定义集合本身。
以下是创建集合的代码:
setA = {1, 2, 3, 4, 5}
然后,我们可以进行一个简单的打印来证明我们拥有一个集合。
print(setA)
点击运行后,我们会得到打印出的值1到5。
集合与列表的区别
集合与列表略有不同,因为它不允许重复值。
我们可以通过放入另一个5来演示这一点。
setA = {1, 2, 3, 4, 5, 5}
print(setA)
当我点击运行时,会发现第二个5没有在列表中打印出来。
集合的常用方法
集合也有一些我们可以使用的方法。
我可以使用一个方法来添加新内容。如果我使用setA.add(6),就可以添加数字6。
setA.add(6)
print(setA)
点击运行后,会发现值6被添加到了集合中。
我也可以使用remove方法。
setA.remove(2)
print(setA)
当我点击运行时,会发现数字2从集合中被移除了。
还有一个discard方法,它的作用基本上与remove相同。
setA.discard(3)
print(setA)
使用discard方法,当我点击运行时,会得到相同的输出效果。
在继续之前,让我先清空控制台。
集合的数学运算
还有一些有用的方法可以与集合一起使用,以执行数学运算。现在我来演示其中一些。
首先,我将创建一个新的集合setB,并重置setA的值为原始值。
setA = {1, 2, 3, 4, 5}
setB = {4, 5, 6, 7, 8}
有两种方式可以使用数学运算符。例如,对于并集(union),我可以这样做:
print(setA.union(setB))
然后我可以点击运行按钮看看会发生什么。我发现它将两个集合连接在一起,并去除了像4和5这样的重复值。并集将它们合并为一个集合,所以你得到了一个集合{1, 2, 3, 4, 5, 6, 7, 8}。
对于并集的其他选项,我可以使用竖线符号|,它的工作方式相同。
print(setA | setB)
在继续之前,让我先清空控制台。
交集运算
我可以使用的另一个运算是交集。我可以通过编写setA.intersection(setB)并将其应用于setA。
print(setA.intersection(setB))
当我点击运行时,我得到了setA和setB中都匹配的所有项。这里我们得到了4和5。
交集也可以用&符号表示,并且工作方式相同。
print(setA & setB)
当我点击运行时,我也得到了4和5。
在继续之前,让我再次清空控制台。
差集运算
我可以使用的另一个数学运算是集合差集。要使用这个,我将打印setA.difference(setB)。
print(setA.difference(setB))
这应该会返回所有只在setA中而不在setB中的元素。当我点击运行时,我们得到了正确的输出{1, 2, 3}。
我也可以用减号-来表示差集。
print(setA - setB)
当我点击运行时,我也会得到相同的值{1, 2, 3}。
对称差集运算
我将讨论的最后一个运算叫做对称差集。这由symmetric_difference函数表示,使用方式类似。
print(setA.symmetric_difference(setB))
当我点击运行时,我得到了{1, 2, 3, 6, 7, 8}。换句话说,就是所有存在于setA或setB中,但不同时存在于两个集合中的元素。
对称差集也可以用^运算符表示。
print(setA ^ setB)
当我点击运行时,我得到了相同的值。
集合的无序性
关于集合,另一个重要的事情是,集合是一个没有重复项的集合,但它也是一个无序项的集合,不像列表那样可以基于索引打印内容。
如果我尝试打印setA[0]来获取集合中的第零个元素,我会得到一个错误。
print(setA[0])
在尝试打印此输出之前,让我先清空控制台。当我点击运行时,我得到一个类型错误,提示集合对象不可下标。
这意味着集合不是一个序列。它不包含内部所有元素的有序索引。
总结

本节课中我们一起学习了Python集合的基础知识。我们了解了如何创建集合,它与列表的关键区别在于不允许重复值且元素无序。我们练习了使用add、remove和discard方法来修改集合。更重要的是,我们探索了集合的四种核心数学运算:并集(union 或 |)、交集(intersection 或 &)、差集(difference 或 -)和对称差集(symmetric_difference 或 ^)。最后,我们明白了由于集合的无序性,不能像列表那样通过索引访问其元素。掌握这些操作将帮助你在处理需要唯一值或进行集合运算的数据时更加得心应手。
Python 25:字典
概述
在本节课中,我们将要学习 Python 中的字典。字典是一种高效的数据结构,它允许我们通过键来存储和访问值,而不是像列表那样通过索引位置。我们将探讨字典的基本概念、操作方法以及它与列表相比的性能优势。
什么是字典?
Python 中的字典在很多方面类似于一本真实的字典。在一本普通字典中,要查找一个单词,你需要通过首字母查找,然后利用字母顺序系统找到它的位置。
同样地,Python 字典经过优化,可以快速检索值。你可能还记得 Python 列表在访问一系列值时非常有用。字典则基于键来访问值,而不是索引位置,因此在操作上更快、更灵活。
字典的核心概念:键值对
在 Python 字典中,一个键被分配给一个特定的值。这被称为键值对。这种方法的优点是它比使用传统列表快得多。
要在一个列表中查找一个项目,你需要不断检查列表直到找到该项目。但在 Python 字典中,你可以通过使用其键直接找到你需要的项目。
字典也是可变的,这意味着值可以被更改或更新。例如,你可以声明数字 1 作为键,“咖啡”作为项目,然后将其更改为任何其他数字或饮料项目。
如何访问字典中的项目?
要访问或定位 Python 字典中你需要的项目,需要使用键。
为了演示这一点,我将访问 Python 字典中的“咖啡”项目。首先,我声明我的字典名称为 sample_dictionary,然后在等号后面用一对花括号写一系列键值对。
我还确保用逗号分隔每个配对。然后我输入 print 函数,后面跟上我的字典名称。我需要访问键为 1 的“咖啡”项目,所以我在方括号中插入数字 1。
我运行 print 函数,它返回“咖啡”作为结果,正如我所期望的。
更新字典
我也可以通过用一个项目替换另一个项目来更新字典。我只需要使用键来引用它,同时使用赋值运算符 = 来分配新值。
例如,我可以将字典中的 item2 从“茶”更改为“薄荷茶”。我只需写一行以字典名称开头的新代码,后面跟上我想在方括号中更改的键。
然后我添加一个等号运算符,后面跟上新项目的名称。
这段代码的意思是:将 sample_dictionary 中的 item2 更改为“薄荷茶”。当我运行这个函数时,它改变了该项目。
从字典中删除项目
要从字典中删除一个项目,我写一行带有 del 函数的代码,后面跟上我的字典名称。
然后我在方括号中添加要删除的项目的键。在这个例子中,我想删除项目三“果汁”。
当我运行这个删除函数时,它将从我的字典中移除“果汁”值。
迭代字典的方法
最后,我还可以使用三种不同的方法来迭代字典:标准的迭代方法、.items() 函数或 .values() 函数。

让我们更详细地探讨这些迭代方法和其他字典操作函数。
创建和操作字典
要创建我的字典,我将首先声明一个名为 my_d 的简单变量,然后使用赋值运算符和花括号。
它可以与集合相同,但默认情况下,它被归类为空字典。我可以通过使用 print 语句、type 函数,然后传入 my_d 变量来打印它。
类实际上返回为字典类型,所以接下来我将在字典中添加一些值,我需要分两部分进行。
字典包含所谓的键和值。键可以是数字,也可以是字符串,但为了表示赋值,我使用冒号,然后放入我想要的任何值。在这种情况下,我将放入一个简单的字符串值“test”。
为了表示我可以更改或拥有不同的键、字符串、整数等,我放入一个字符串键“name”,然后值是“Jim”。
我使用 print 函数打印出我的字典。现在我有了一个基本的字典设置,键为 1 和 “name”,值分别为 “test” 和 “Jim”。
访问字典中的键
要访问字典中的键,我只需要使用方括号,然后传入键值。所以在这个数字 1 的情况下,我将传入数字 1。
对于字符串值,我只需要传入实际的字符串值本身,即 “name”。点击运行,我得到 “test” 和 “Jim”,它们是每个对应键的值。
添加或更新键
如果我想在字典中添加一个新键或更新它,我可以简单地执行 my_d,然后添加一个新的赋值,例如 2: "test2"。点击运行,该键随后被添加到当前字典中。
要更新一个键,我必须调用我想要的值。我将更新第一个键,即数字 1,将其值从 “test” 改为 “not a test”。
点击运行,它在屏幕上更新了。
关于字典的注意事项
关于字典需要注意的另一件事是,如果我尝试放入一个重复的键,它不允许这样做。所以如果我放入一个数字 1 和 “not a test”,点击运行,该键实际上会被最新的一个覆盖。
因此,数字 1 只出现一次输出,它不允许打印出两个键,因为它不允许设置重复的值。
从字典中删除键
如果我想从字典中删除一个键,我使用 del 操作符。现在我输入 my_d,然后指定我想删除的键,在这个例子中是数字 1,它随后从字典中移除。
迭代字典
对于字典,我也可以迭代。例如,我可以使用 for x in my_dictionary,然后打印出 x 的值。点击运行,我得到 1。
这只打印出键。在很多情况下,我可能需要访问两者。为此,我使用一个名为 .items() 的方法。
这样,我就可以访问键和值的赋值。所以我在这里打印,key + value。我将使用一些连接来打印出键和值。
点击运行,我必须注意,因为我正在使用整数和字符串,所以我用 str() 包装它,再次点击运行,我得到字典中每个项目的键和值。

总结
本节课中,我们一起学习了 Python 字典的目的和功能,以及它们在性能方面的优势。你现在应该理解字典如何通过键值对高效地存储和访问数据,以及如何执行创建、访问、更新、删除和迭代等基本操作。
Python 26:*args 与 **kwargs

概述
在本节课中,我们将要学习 Python 函数中两个强大的特性:*args 和 **kwargs。它们允许函数接收任意数量的参数,从而使函数更加灵活和通用。
从固定参数到可变参数
首先,我们来看一个简单的加法函数。它接受两个参数 a 和 b,并返回它们的和。
def sum_of(a, b):
return a + b
print(sum_of(4, 5)) # 输出:9
这个函数工作得很好。但是,如果我们想计算三个或更多数字的和,比如 sum_of(4, 5, 6),运行代码就会得到一个错误,提示函数只接受两个位置参数,但我们传入了三个。
为了解决这个问题,我们需要一种方法来接收任意数量的参数。这就是 *args 的用武之地。
使用 *args 接收任意数量的非关键字参数
*args 允许函数接收任意数量的非关键字(位置)参数。在函数定义中,我们使用一个星号 * 后跟一个参数名(习惯上使用 args)来定义它。
下面,我们重写 sum_of 函数,使其能够处理任意数量的参数。
def sum_of(*args):
total = 0
for number in args:
total += number
return total
在这个函数中:
*args将所有传入的位置参数收集到一个名为args的元组中。- 我们初始化一个变量
total为 0。 - 使用
for循环遍历args元组中的每个数字。 - 将每个数字累加到
total中。 - 最后返回总和。
现在,我们可以传入任意数量的参数了:
print(sum_of(4, 5)) # 输出:9
print(sum_of(4, 5, 6)) # 输出:15
print(sum_of(4, 5, 6, 7, 8)) # 输出:30
使用 **kwargs 接收任意数量的关键字参数
上一节我们介绍了如何使用 *args 处理多个非关键字参数。本节中我们来看看 **kwargs,它用于处理任意数量的关键字参数。
**kwargs 允许函数接收任意数量的关键字参数(即带有参数名的参数)。在函数定义中,我们使用两个星号 ** 后跟一个参数名(习惯上使用 kwargs)来定义它。kwargs 将这些参数收集到一个字典中。
假设我们要计算餐厅账单的总金额,顾客点了咖啡、蛋糕和果汁,每样东西都有不同的价格。我们可以用 **kwargs 来优雅地处理。
def calculate_total(**kwargs):
total = 0
for item, price in kwargs.items():
total += price
return round(total, 2) # 四舍五入到两位小数
bill = calculate_total(coffee=2.99, cake=4.55, juice=2.99)
print(bill) # 输出:10.53
在这个函数中:
**kwargs将所有传入的关键字参数收集到一个名为kwargs的字典中,其中键是参数名(如coffee),值是参数值(如2.99)。- 我们使用
kwargs.items()方法来同时获取字典中的每一项的键和值。 - 在循环中,我们将每一项的价格(
price)累加到total中。我们不需要键(item),因为它只是一个字符串标签。 - 最后,使用
round(total, 2)将结果四舍五入到两位小数,这是货币计算的常见做法。
总结
本节课中我们一起学习了 Python 函数中两个重要的概念:
*args:用于在函数定义中接收任意数量的非关键字参数。这些参数在函数内部被封装成一个元组。**kwargs:用于在函数定义中接收任意数量的关键字参数。这些参数在函数内部被封装成一个字典。

使用它们可以极大地提高函数的灵活性,使其能够适应不同数量和类型的输入,是编写通用和可复用代码的强大工具。
Python 27:什么是异常 🐍
在本节课中,我们将要学习Python编程中两个非常重要的概念:错误(Errors)和异常(Exceptions)。理解它们之间的区别以及如何处理它们,是每位新开发者成长的关键一步。
错误与异常概述
错误是编码过程中不可避免的一部分,它们可能由多种原因引发。让我们从探索两种主要类型开始:语法错误(Syntax Errors)和异常(Exceptions)。语法错误通常由人为失误导致,而异常则是已知的、需要在代码中处理的问题。

语法错误
上一节我们介绍了错误的基本分类,本节中我们来看看第一种类型——语法错误。这类错误通常由开发者造成,可能是代码中的拼写错误或打字错误。


通常,这类错误的影响较小,因为大多数集成开发环境(IDE),例如Visual Studio Code,会警告开发者并提供修复线索。


以下是Python初学者常见的语法错误示例:

-
遗漏冒号:在学习Python时,一个常见错误是在条件语句或循环语句末尾忘记添加冒号。
if x > 5 # 错误:缺少冒号 print("x is greater than 5")如果使用具有语法检查功能的代码编辑器,此类错误会在出错点被高亮显示。运行代码将导致
SyntaxError: invalid syntax。 -
缩进问题:Python使用缩进来定义代码块,因此缩进不正确也会导致语法错误。
def my_function(): print("Hello") # 错误:函数体内的语句需要缩进这将引发
IndentationError。


随着你不断学习Python,你将越来越少地遇到这类错误,因为你会变得更擅长编写和分析自己的代码。
异常

现在让我们继续学习异常错误。它们发生在代码执行期间,对于未经训练的眼睛来说很容易被忽视。


但是,异常需要由开发者来处理。开发者需要处理代码库中任何潜在的问题,以防止应用程序失败。



让我们来探索一个抛出异常的例子。你的代码可能在语法上是完全正确的,但如果它试图执行一个无意义的操作,例如除以零,就会引发异常。

result = 5 / 0 # 这将引发 ZeroDivisionError
从数学上讲,任何数除以零是没有意义的。因此,当你运行这段程序时,会抛出 ZeroDivisionError 异常。



幸运的是,Python默认内置了许多异常类型,你可以利用它们来捕捉代码中的潜在问题。
总结
本节课中我们一起学习了Python中错误与异常的基础知识。我们区分了由开发者失误导致的语法错误和在程序运行时发生的异常。理解这些概念是朝着成为一名更优秀的Python程序员迈出的正确一步。记住,处理异常是构建健壮、稳定应用程序的关键技能。
Python 28:异常处理 🐍
在本节课中,我们将要学习如何在Python中处理异常。你将了解如何改变错误信息,以及如何使用 try 和 except 语句来包装你的代码,从而让程序在遇到问题时更加健壮和用户友好。
概述

程序在运行时可能会遇到各种意外情况,例如除以零、文件不存在等。这些情况被称为“异常”。如果不加处理,程序会崩溃并显示复杂的错误信息。通过异常处理,我们可以优雅地捕获这些错误,并给出清晰的提示,从而提升用户体验和程序的稳定性。
上一节我们介绍了函数的基本概念,本节中我们来看看如何让函数在面对错误输入时也能妥善应对。
一个简单的除法函数
首先,我们创建一个简单的数学函数作为例子。
我定义了一个名为 divide_by 的新函数,它接受两个参数 A 和 B。这个函数的目的是返回两个数字相除的结果。
def divide_by(A, B):
return A / B
现在,我添加一个打印语句来调用这个函数。在打印语句内部,我传入数值40和4。
print(divide_by(40, 4))
我点击运行,返回的值是10,这是正确的,因为40除以4等于10。
触发异常
现在,让我们测试一下如果传入40和0会发生什么。
print(divide_by(40, 0))
当我点击运行时,我得到了一个错误,或者说一个“异常”。这个异常显示为 ZeroDivisionError: division by zero。它给出这个错误是因为在数学中,任何数都不能除以0。
你可能会同意,让用户看到这种晦涩的错误信息会让他们感到困惑。那么问题来了:如何以更友好的方式处理错误?
使用 Try 和 Except 语句
如何防止用户看到实际打印出来的异常呢?你可以使用Python的 try 和 except 语句来实现。
基本语法是:输入 try:,然后在下一行输入 except:。你将想要运行的代码放在 try 语句块中。
我删除底部的打印语句,并将 divide_by 函数调用包裹在 try 语句中。
try:
ans = divide_by(40, 0)
except:
print("Something went wrong.")
让我清空终端以便你能专注于输出。我点击运行,现在打印出来的是我们自定义的错误语句。
那么发生了什么?try 语句会尝试执行你添加在其中的代码。如果发生异常,它将触发 except 行,并执行 except 语句块下的任何代码。
捕获特定异常信息
但是Python允许你让 except 语句更具体。如果你想捕获异常本身,可以在 except 后面添加基类 Exception。基类 Exception 用于Python中编写的所有异常。
你可以通过使用 as E 来访问异常信息。变量 E 充当异常的别名。我可以在打印语句中使用 E 来打印出异常。
让我们编辑打印语句。我在错误信息的末尾添加 E。
try:
ans = divide_by(40, 0)
except Exception as e:
print("Something went wrong.", e)
我按下运行,会发生什么?我们的自定义消息被打印出来,同时 e 的内容也被打印了。所以这次它显示:Something went wrong. division by zero。
在Python中,你还可以访问实际发生的异常类型或类。为此,我添加另一个打印语句:e.__class__。
try:
ans = divide_by(40, 0)
except Exception as e:
print("Something went wrong.", e)
print(e.__class__)
我再运行一次这个语句。这次,输出也包含了错误的类,即 <class ‘ZeroDivisionError’>。
让我再次清空终端。
提供更具体的用户反馈
让我们更进一步,为最终用户提供更具体的反馈。
在 except 语句中,我将基类 Exception 替换为实际打印出来的错误,即 ZeroDivisionError。我将更改打印语句,首先通过在该语句开头添加 e 来打印实际错误,然后添加一些用户友好的文本,说明“我们不能除以0”。
try:
ans = divide_by(40, 0)
except ZeroDivisionError as e:
print(e, "We cannot divide by zero.")
我点击运行,现在的输出是:division by zero We cannot divide by zero.。
到目前为止,你已经了解了如何用 try 和 except 语句包装你的代码,以及如何优化用户看到的消息。
处理多个异常
但是,如何在不提前知道它们是什么的情况下处理多个异常呢?
幸运的是,你可以通过添加另一个 except 语句来更改异常处理结构。假设代码没有在第一个 except 语句中触发零除错误,你可以添加另一个 except 语句来测试通用异常。
现在我将再次添加基类 Exception。我添加一个带有 e 和包含一些通用信息的消息的打印语句。
try:
ans = divide_by(40, 0)
except ZeroDivisionError as e:
print(e, "We cannot divide by zero.")
except Exception as e:
print(e, "A general error occurred.")
我点击运行,在这种情况下,因为仍然存在数学错误,函数仍然会在第一个 except 语句处被捕获。但这让你很好地了解了如何测试更多的异常情况。

以下是处理多个异常时的结构要点:
- 顺序很重要:特定的异常(如
ZeroDivisionError)应放在通用的异常(如Exception)之前。 - 兜底处理:通用的
except Exception可以捕获所有未被前面特定except块处理的异常。 - 保持清晰:为每种异常类型提供清晰的错误信息,有助于调试和用户体验。
总结

本节课中我们一起学习了Python异常处理的核心知识。你知道了程序运行中难免会出现意外,而异常处理机制就是应对这些意外的安全网。我们通过一个除法函数的例子,逐步探索了如何使用 try 和 except 语句来捕获错误,如何从异常对象中获取详细信息,以及如何为不同的异常类型提供定制化的友好提示。记住,良好的异常处理不仅能防止程序崩溃,还能极大地改善用户的体验。恭喜你,现在你已经知道如何用 try 和 except 语句包装代码,以处理代码中所有潜在的异常了。
Python 29:Python中的文件处理 📂
概述
在本节课中,我们将要学习Python中文件处理的核心概念与操作方法。文件处理是Python编程的重要组成部分,它允许我们创建、读取、写入和操作存储在文件中的数据。这对于处理大量数据、配置文件或任何需要持久化存储的信息至关重要。
文件处理基础
文件处理是学习Python的关键部分。Python提供了多个内置函数来创建和操作文件。文件处理包括打开、读取、写入以及其他文件操作。作为开发者,你可能会处理大量数据,而文件处理使这项工作变得更加容易。因此,学习如何操作文件非常重要。
无论你是在处理计算机上的数据、网络数据还是云端数据,这些数据很可能以某种文件形式保存。Python中有两个主要的文件处理函数:open和close。让我们首先探索open函数。
open函数
open函数用于读取、写入和创建文件。它接受两个参数:
- 第一个参数是文件名和/或文件路径。
- 第二个参数是模式。
模式指明了所需的操作,例如读取、写入或创建。它还指定了你希望文件以文本格式还是二进制格式输出。
以下是Python中可用的文件处理模式:
r:以文本格式打开并读取文件。rb:以二进制格式打开并读取文件。r+:打开文件用于读取和写入。w:打开文件用于写入。注意:w模式会覆盖现有文件。a:打开文件用于编辑或追加数据。
close函数
close函数用于关闭已打开的文件连接。注意:它不接受任何参数。
在Python中,还有另一种打开和关闭文件的方式,那就是使用with open语句。使用它的优势在于它会自动关闭文件,我们稍后会进行演示。
文本格式与二进制格式
到目前为止,你已经了解了如何为特定操作打开文件,但你可能想知道以文本格式和二进制格式打开文件有什么区别。
在Python中,你通常以两种方式处理文件:文本格式或二进制格式。
- 文本格式对用户更友好,因为人类可以阅读它。
- 你无法直接阅读二进制格式的文件,但它们更加紧凑,因此能带来更好的性能。
现在,让我们介绍如何在Python中指定文件处理的类型。
Python默认使用文本格式进行文件处理。因此,仅传递任何用于读取或写入的模式都会自动将其设置为文本格式。
若要将文件处理设置为二进制格式,你需要在读取或写入选项后加上字母b。

例如:
open('文件名', 'rb')用于以二进制格式读取文件。open('文件名', 'ab')用于以二进制格式追加或添加数据到文件。
代码实践
上一节我们介绍了文件处理的理论基础,本节中我们来看看如何在代码中实际操作文件。
首先,我将声明一个名为file的简单变量,并将open函数赋值给它以获取对文件的访问权限。但在使用open函数之前,我需要先创建一个用于测试的新文件,我们称之为test.txt。在这个文本文件中,我添加了一行简单的文本:“hello there”。
现在回到Python文件。在open函数的括号内,我可以添加第一个参数,即字符串'test.txt'。对于第二个参数,我输入mode='r',表示以读取模式打开。
至此,名为file的变量将能够访问test.txt的内容。但要实际读取文件,你需要添加readline()或readlines()函数。readline()只返回文件的第一行,而readlines()会输出一个包含多行的数组。
由于我们的文件中只有一行文本,我将使用readline()函数。我输入file.readline()并将其赋值给一个新变量data。然后我添加一个print语句来打印data的内容。最后,我添加close()函数来关闭对test.txt文件的访问。
file = open('test.txt', mode='r')
data = file.readline()
print(data)
file.close()
我点击运行,文件的内容(即“hello there”)被打印出来。
接下来,我将演示在Python中访问文件的另一种方式:将open函数改为with open语句。
为什么要使用with open函数?with open语句能更好地处理异常,并且会自动为你关闭文件。
与之前类似,我创建第二个变量data,使用readline(),然后打印data的内容。
with open('test.txt', mode='r') as file:
data = file.readline()
print(data)
我点击运行,和之前一样,文件的内容被打印出来。

总结
本节课中我们一起学习了如何在Python中处理文件。这包括用于创建和操作文件的内置函数,以及打开、读取和写入文件的函数。我们探讨了open和close函数,了解了不同的文件打开模式(如r、w、a及其二进制变体rb、wb等),并比较了文本格式与二进制格式的区别。最后,我们通过代码示例实践了使用标准open()和更推荐的with open语句来安全地读取文件内容。掌握这些基础知识是进行有效数据管理和后续更复杂数据库操作的第一步。
Python 30:创建文件 📄
在本节课中,我们将要学习如何在Python中创建文件,并探索向新文件中插入内容的不同方法。文件用于永久存储数据。代码变量中的数据仅存在于随机存取存储器(RAM)中。由于计算机关闭时RAM会丢失数据,因此能够创建文件以保存数据供将来使用或作为永久记录至关重要。
在Python中,我们可以使用 open 函数并启用正确的模式来创建新文件。
使用 open 函数创建文件
让我们从一个简单的例子开始。我将使用 with 语句。

以下是创建文件的基本语法:
with open('new_file.txt', mode='w') as file:
# 对文件进行操作
open 函数接受两个主要参数:文件名和模式。模式 'w' 代表“写入”。如果文件不存在,Python会创建它;如果文件已存在,'w' 模式会覆盖原有内容。
一种简写模式的方法是直接输入代表所需模式的单个字符。例如,可以用 'w' 代替 mode='w',两者含义相同。
现在,我可以通过变量 file 访问新创建的文件,并开始使用写入函数向其中添加内容。
向文件写入内容
上一节我们介绍了如何创建文件,本节中我们来看看如何向文件中写入内容。
写入单行内容
使用 write() 方法可以向文件写入字符串。以下是具体步骤:
with open('new_file.txt', 'w') as file:
file.write('This is a new file created.')
运行此代码后,会在当前目录下生成一个名为 new_file.txt 的文件,其中包含指定的文本。
写入多行内容
如果需要向文件写入多行内容,而不是单行,可以使用 writelines() 方法。
writelines() 方法接受一个列表作为参数。在Python中,列表由方括号 [] 表示,列表项之间用逗号分隔。
以下是写入多行内容的示例:
with open('new_file.txt', 'w') as file:
file.writelines(['This is a new file created.', 'This is another line to be added.'])
运行此代码后,new_file.txt 文件中将包含由 writelines() 函数创建的两行文本。
但是,输出结果可能不符合预期。Python会严格按照列表中指定的格式添加内容。如果希望内容在新行上显示,需要在字符串中指定换行符 \n(无空格)。
以下是修正后的代码:
with open('new_file.txt', 'w') as file:
file.writelines(['This is a new file created.\n', 'This is another line to be added.'])
现在,当运行代码时,new_file.txt 文件的内容将更易读,每个句子都在单独的一行。
文件写入模式:覆盖与追加
每次运行写入模式('w')的脚本时,它都会替换当前文件的内容。例如,如果在第一行文本中插入数字“2”并运行脚本,新的文件内容将覆盖旧文件,只保留修改后的第一行。
另一方面,如果希望向文件添加内容而不是每次替换它,需要更改模式的行为。将字母 'w' 替换为 'a',它代表“追加”(append)。
以下是追加模式的示例:
with open('new_file.txt', 'a') as file:
file.write('This line will be appended.\n')
如果运行此代码多次,每次都会将新行添加到文件末尾,而不是覆盖原有内容。
然而,追加时可能不会完全按照预期换行。原因是在第一句之前没有指定换行符。因此,可以在字符串开头添加 \n 来确保新内容从新行开始。
如果需要先清空文件再写入,可以将模式改回 'w' 以确保覆盖最后一个文件。之后,若想再次追加内容,再将模式改回 'a'。
处理文件操作异常
在文件操作中,处理可能出现的异常至关重要。我们可以使用 try 和 except 语句来捕获和处理异常。
以下是如何在文件操作中添加异常处理的示例:
try:
with open('sample/new_file.txt', 'w') as file:
file.write('Testing exception handling.')
except FileNotFoundError as e:
print(f'Error: {e}')
为了触发错误,可以尝试访问一个不存在的目录。例如,如果请求的目录 sample 在当前目录中不存在,Python将引发 FileNotFoundError。
运行上述代码后,终端将打印出错误信息:“Error: [Errno 2] No such file or directory: 'sample/new_file.txt'”。
因此,在创建文件时,请确保要放置文件的目录确实存在。在这种情况下,必须确保目录已存在,或者从Python内部创建目录,然后在其中创建文件。
总结

本节课中我们一起学习了在Python中创建文件的核心知识。我们介绍了如何使用 open 函数以及 'w'(写入)和 'a'(追加)模式来创建和操作文件。我们探讨了如何向文件中写入单行和多行内容,并强调了使用换行符 \n 来格式化输出的重要性。最后,我们了解了文件操作中异常处理的重要性,特别是使用 try-except 块来捕获 FileNotFoundError 等常见错误,从而编写出更健壮、可靠的代码。
Python 31:读取文件 📖
在本节课中,我们将学习如何在Python中读取文件的内容。掌握读取文件是处理存储数据的基础,Python提供了多种内置函数来简化这一过程。
概述
我们将探索三种主要的文件读取方法:read()、readline()和readlines()。理解这些方法的区别以及如何在不同场景下使用它们,是有效处理文件数据的关键。
三种文件读取方法
Python提供了几种灵活的方式来读取文件内容,每种方法适用于不同的需求。
1. read() 方法
read()方法将文件的全部内容作为一个字符串返回。这个字符串包含文件中的所有字符。
您也可以向read()方法传递一个整数参数,以指定仅返回文件中前N个字符。其基本语法如下:
file.read([size])
2. readline() 方法
上一节我们介绍了如何读取整个文件,本节中我们来看看如何逐行读取。readline()函数每次调用只返回一行文本作为字符串。
例如,如果一个文件有两行文本:“这是第一行”和“这是第二行”,那么第一次调用readline()将返回“这是第一行”。
readline()函数同样可以接受一个整数参数,用于返回该行上指定数量的字符。例如,readline(10)将返回该行的前10个字符。
3. readlines() 方法
除了逐行读取,我们还可以一次性获取所有行。readlines()方法会读取文件的全部内容,并将其作为一个有序列表返回,列表中的每个元素对应文件中的一行。
这允许您遍历整个列表,或者根据特定条件挑选出某些行。例如,对于一个包含四行文本的文件,readlines()会返回一个包含这四个字符串的列表。
文件路径:绝对路径与相对路径
文件存储在目录中,并通过路径来定位。从同一目录读取文件很简单,只需要文件名即可。然而,当处理不同位置的文件时,理解绝对路径和相对路径的区别至关重要。
以下是两种路径类型的关键区别:
- 绝对路径:包含一个前导斜杠(在Unix/Linux/macOS中)或驱动器标签(在Windows中)。绝对文件路径包含了定位文件所需的全部信息,无论您当前是否在该文件所在的目录中。
- 相对路径:通常不包含对根目录的引用,而是相对于当前调用文件所在的目录。相对文件路径只包含在当前工作目录中定位文件所需的信息。
实战演示

现在,我将演示如何在Python中实际使用这些方法来读取文件。我将使用一个简单的示例文本文件(sample.txt),其内容如下:
The quick brown fox jumps over the lazy dog.
This is a second line of text.
我将使用with open()语句安全地打开文件。
演示1:使用 read() 读取全部内容
首先,我们尝试打印文件的全部内容。
with open(‘sample.txt‘, ‘r‘) as file:
print(file.read())
运行此代码会将文件的全部内容原样打印出来。
演示2:使用 read(N) 读取指定字符数
接下来,我们看看如何只打印文件的一部分。例如,如果我们只想打印“The quick brown fox jumps over the lazy dog.”这句话,它恰好是44个字符。
我们可以向read()函数传递参数44,指示函数只读入前44个字符。
with open(‘sample.txt‘, ‘r‘) as file:
print(file.read(44))
运行此代码将只打印出第一行。其原理是从索引0开始,44是需要打印出的最后一个字符的索引。
演示3:使用 readline() 读取单行
有时我们只需要处理一行。readline()方法会读取文件中的第一行。
with open(‘sample.txt‘, ‘r‘) as file:
print(file.readline())
运行此代码将只打印该文件中的第一行文本。
演示4:使用 readlines() 获取行列表
readlines()方法将返回一个包含所有行的列表。
with open(‘sample.txt‘, ‘r‘) as file:
print(file.readlines())
运行此代码,您会注意到文件中的文本现在被包裹在方括号[]中,表明它是一个列表。
演示5:遍历 readlines() 返回的列表
因为readlines()返回一个列表,我们可以将其赋值给一个变量并进行遍历。
with open(‘sample.txt‘, ‘r‘) as file:
data = file.readlines()
for x in data:
print(x)
运行此代码,列表项将逐行打印出来。
一个需要注意的地方是,当使用with open() as file:时,文件对象本身也是可迭代的。因此,我们可以直接遍历file变量,效果与遍历readlines()的结果相同。
with open(‘sample.txt‘, ‘r‘) as file:
for line in file:
print(line)

总结
本节课中,我们一起学习了在Python中读取文件的核心方法。您现在应该能够:
- 描述如何使用
read()、readline()和readlines()函数读取文件。 - 区分绝对路径和相对路径的概念。
- 在代码中演示如何输出文件的不同格式(完整内容、指定字符数、单行或行列表)。
- 理解并安全地使用
with open()语句来处理文件。
这些方法是Python文件操作的基础,熟练掌握它们将为处理更复杂的数据任务打下坚实的基础。
Python 32:模块小结 🎯
在本节课中,我们将对Python基础编程模块的核心内容进行回顾与总结。我们将梳理函数、数据结构、错误与异常处理以及文件操作的关键知识点。
模块内容回顾 📝

上一节我们完成了Python基础编程模块的学习。在这个模块中,我们系统性地介绍了Python函数、数据结构、错误与异常处理以及文件操作。
以下是本模块涵盖的核心主题:
- Python函数
- 数据结构
- 错误、异常与文件处理
函数基础与作用域 🔧

本节中我们来看看Python函数的基础概念。函数是Python中创建操作的基础单元。

以下是关于函数声明与作用域的核心要点:
- 声明函数:使用
def关键字。def function_name(parameters): # 函数体 return value - 向函数传递数据:通过参数实现。
- 从函数返回数据:使用
return语句。 - 解释基本层面的作用域:理解变量在代码不同部分的可访问性。
为了在项目中高效使用函数,理解其在不同代码层级中的可访问性至关重要。

在本课中,你还学习了如何识别四种作用域,描述函数如何在不同层级控制作用域。
数据结构 📊

接下来,我们回顾用于组织和存储数据的数据结构。Python提供了多种内置数据结构来帮助你组织和存储数据,以便轻松访问。

以下是本模块介绍的主要数据结构及其概念:
- 列表:有序、可变的元素集合。
my_list = [1, 2, 3, 'a', 'b'] - 元组:有序、不可变的元素集合。
my_tuple = (1, 2, 3) - 集合:无序、不重复的元素集合。
my_set = {1, 2, 3} - 字典:键值对的无序集合。
my_dict = {'key1': 'value1', 'key2': 'value2'}
成功完成第二课后,你现在应该能够识别列表方法,解释列表中可以存储的数据类型,描述如何遍历列表,并阐述元组、集合、字典和队列的主要用途。
文件操作与异常处理 📁
最后,我们总结模块中关于文件处理和异常的主题。Python文件处理和异常是本模块最后一课的内容。
完成本课后,你应该能够掌握以下技能:
- 使用
open函数创建和操作文件。file = open('filename.txt', 'r') # 以读模式打开文件 - 描述如何在Python中读取文件。
- 演示如何输出不同格式并将文件内容存储到数据结构中。

总结 ✨
本节课中我们一起学习了Python基础编程模块的核心内容。本模块为你提供了开始进行基本Python编程的机会,这是向成为Python开发者迈出的又一步。
Python 33:什么是过程编程 🧩
在本节课中,我们将要学习过程编程的基本概念。这是一种通过编写一系列逐步执行的指令来构建程序的方法,是迈向面向对象编程的重要基石。我们将了解其核心思想、优势、劣势,并通过具体示例来理解如何应用。
概述
开发者可以用多种不同的方式来组织代码。Python 支持面向对象、过程和函数式编程模型,这些通常也被称为编程范式。本节视频将重点介绍过程编程,它类似于编写程序逐步执行的指令。对于新开发者而言,学习过程编程非常重要,它是理解更复杂编程范式的重要一步。
编程模型的主要目的是结构化你的代码。这种结构使得更新代码和在代码中创建新功能变得更加容易。

但是,并不存在一种完美的模型能解决所有代码结构问题。有时,结合多种方法效果最佳。


过程编程的核心
过程编程将代码组织成过程,有时也称为子程序或代码的功能部分。


由于这种方法,代码由完成特定任务的逻辑步骤组成。例如,将两个数字相加并返回它们的和。

我可以使用一小段代码将数字 5 和 10 相加。
现在我想将数字 8 和 4 相加。然而,我写的代码是专门用于将 5 和 10 相加的。对于新的数字,我必须创建另一段类似的代码来进行计算。这不是一种高效的编码方式。
因此,我将代码改为一个函数,该函数将接受两个数字作为参数并返回它们的和。
def sum(a, b):
return a + b
在这个函数中,我没有将实际数字声明为变量,而是使用了参数 a 和 b,所需的代码更少。但更重要的是,我现在有了一个名为 sum 的函数,我可以随心所欲地使用许多不同的数字集来重复使用它。
在编程中,有一个称为 DRY(Don‘t Repeat Yourself,不要重复自己)的原则,其核心就是减少代码中的重复。

我最初编写的将两个数字相加并返回其和的代码就是一个不该做什么的好例子,因为我必须编写两次代码以适应第二组数字。

需要牢记的一个准则是:创建可以在整个应用程序中重复使用的函数。
过程编程示例

让我们检查另一个例子。这次是关于计算账单总额并为其添加税费。
代码将分为四个部分呈现,以帮助你关注每个过程的作用。
首先,bill_total 函数接受一个账单作为参数,并循环遍历它以计算总账单金额并返回总额。
def bill_total(bill):
total = 0.00
for item in bill:
total += item
return total

calculate_tax 函数接受两个参数:百分比和账单总额,然后返回要添加到账单中的税费总额,并四舍五入到两位小数。
def calculate_tax(percent, bill_total):
return round((percent * bill_total) / 100.0, 2)
food_bill 包含其项目,代表一个客户的账单,它是静态的,但也可以更改为输入以接受用户数据来动态创建账单。
food_bill = [10.50, 7.25, 15.75, 8.00]
最后几个部分将调用这两个函数来计算账单和税费,然后分别打印出来以及总金额。
food_total = bill_total(food_bill)
tax_total = calculate_tax(15, food_total)
print("Food Total:", food_total)
print("Tax Total:", tax_total)
print("Overall Total:", food_total + tax_total)
你能识别出代码中的子程序或功能部分吗?你是否注意到这些部分是如何相互重用的?
现在,让我们把四个子程序放在一起,检查过程编程从四个方面减少了代码的“足迹”。

最好从末尾开始检查代码。tax_total 重用了 food_total。


food_total 重用了 bill_total 和 food_bill。calculate_tax 重用了 bill_total。

而 bill_total 重用了 food_bill。
过程编程的优缺点

总而言之,过程范式的优点是:对于初学者来说,它易于学习和入门。


过程可以被代码的其他部分重复使用。
代码易于理解,因为每个过程都被分解为特定的任务。

然而,过程编程也有一些缺点,包括:可能更难维护和扩展。

在某些情况下,它与现实世界的对象关联性不强。

数据在整个程序中都是暴露的。


总结
过程编程既有优点也有缺点。作为一名新开发者,随着你学习的深入,你将能更好地判断它是否是解决特定编码问题的最佳方法。
本节课中,我们一起学习了过程编程的基本概念。我们了解到它是一种通过编写顺序执行的步骤来组织代码的范式,核心在于将任务分解为可重用的函数或过程。我们通过加法函数和账单计算示例,具体看到了如何应用DRY原则来避免代码重复,并分析了过程编程在易学性、可重用性方面的优势,以及在维护性、数据封装方面的局限性。理解这些是选择合适编程范式的重要基础。
Python 34:算法
在本节课中,我们将要学习算法的基本概念。算法是完成特定任务或解决问题的一系列步骤。在日常生活中,我们无时无刻不在使用算法来完成任务。
什么是算法?🤔
算法是一系列用于完成给定任务或解决问题的步骤。在编程中,算法被用来解决从简单到非常复杂的各种问题。
理解并创建算法的关键在于将问题分解成更小的部分,就像制作煎蛋卷的食谱一样。通过这种方式,你可以逐步构建出解决整体问题的算法步骤。
一个日常例子:制作煎蛋卷🍳

一个常见的例子是遵循食谱制作煎蛋卷。
以下是制作煎蛋卷的步骤:
- 输入:首先,你拥有制作煎蛋卷所需的食材清单。
- 步骤:接下来,是遵循食谱一步步制作菜肴的方法或指令。
- 输出:最后,你完成了煎蛋卷,这就是输出。
每次制作煎蛋卷的步骤都是相同的。编程中的算法以类似的方式工作。
算法的实际应用:回文检查🔍
现在,让我们探索一个算法的实际应用:编码。我将演示一个特定的算法,用于检查一个单词是否是回文。
回文是指正着拼写和反着拼写都相同的单词。例如,单词 “race car” 就是一个回文,因为正着拼是 R-A-C-E-C-A-R,反着拼仍然是 R-A-C-E-C-A-R。
为了检查一个单词是否是回文,我需要使用一个算法。如前所述,算法是解决问题的一系列步骤。
分解问题
我知道示例中的字符串 “race car” 有索引。我需要检查字符串开头的索引值是否等于字符串末尾的索引值。通过这种方式,我可以比较这两个索引的值。
我可以打印 str[0],因为那是第一个索引,同时打印 str[6],因为那是最后一个索引。运行后,输出是我需要比较的两个值,即 “race car” 开头和结尾的字母 R。
现在,我将把我们的问题分解成更小的步骤。
以下是检查回文需要进行的比较:
- 首先,我需要检查索引 0 的值是否等于最后一个索引 6 的值(本例中是 R)。
- 然后,我需要检查下一个或第二个字符(索引 1)是否等于倒数第二个字符(索引 5)。
- 最后,我需要检查字符 2 是否等于字符 4。
我需要做的是检查这些条件是真还是假。
编写代码实现
那么,让我们看看如何用代码写出来。
我首先创建一个函数 is_palindrome,我知道它将接受一个名为 string 的单一参数。
接下来,我想获取起始索引和结束索引。我将起始索引放入一个等于 0 的变量中。每个字符串总是从索引 0 开始。然后,结束索引将是字符串的长度。因此,我输入 end_index = len(str) - 1。这是因为字符串总是从 0 开始,我必须考虑最后一个索引。
接下来,我想做的是遍历字符串本身,并比较起始索引和结束索引的字符,以验证它们是否相同。为此,我创建一个 for 循环:for x in str:,并在 for 循环中进行比较。
我可以检查第一个索引是否等于最后一个索引。由于两个字符 R 和 R 相同,它将保持为真。但对我来说,检查它是否为假会更快,因为那样我就能立刻知道它不是回文。
因此,我使用一个 if 语句,并使用作为参数传递进来的字符串。然后,我使用起始索引获取字符,并检查它是否不等于结束索引内的字符串。如果满足这个条件,它将返回 false,从而确认它不是回文。但是,如果在 for 循环外从未满足该条件,则返回 true,从而确认它是回文。我已经完成了对起始索引和结束索引的所有检查,它返回到 true 的条件,以确认它是回文。
测试算法
现在,我将测试该算法以验证其是否有效。我使用一个 print 语句,调用 is_palindrome 函数,并传入 “race car”,因为我知道它是一个回文。我点击运行,它返回 true 值。如果我将 “race car” 改为 “race cars” 并再次运行,则返回 false 条件。
这是一个在代码中创建算法以解决问题的例子。它有一系列必须遵循的步骤,以在代码中解决问题,并返回字符串是否是回文的条件。

总结📝
本节课中,我们一起学习了算法作为一种通过编码逐步解决问题的方法是多么有用。算法可以用来解决无论大小、复杂的问题。一旦创建了算法的步骤,每次使用该算法时,它们都将以相同的方式执行。
Python 35:算法复杂度 📊
在本节课中,我们将要学习算法复杂度的核心概念。作为开发者,编写符合业务需求的代码是主要任务。这些代码通常需要经历重构过程,即重写或重新加工代码,使其更易于管理或运行更高效。重构是软件开发周期的标准环节。使代码易于管理或许很直接,但如何使其运行更快或性能更好呢?
为了确定如何让代码更快或性能更好,你必须能够度量它。代码通过时间和空间来度量。时间度量的是代码运行所需时长,空间度量的是代码占用的内存量。
大O表示法 📈
大O表示法用于衡量算法在时间和空间上的效率。它有不同的复杂度类别,范围从极差到极优。

上一节我们介绍了度量的必要性,本节中我们来看看具体的时间复杂度类型。
时间复杂度类型

以下是主要的时间复杂度类型,我们将逐一探讨。

常数时间 O(1)

常数时间算法无论输入规模大小,其运行时间和空间占用都保持不变。

例如,在字典中通过键获取值。要获取一个项的值,你需要拥有其键。键是指向值的直接指针,不需要任何迭代来查找它。这被认为是常数时间操作。
代码示例:
my_dict = {'a': 1, 'b': 2}
value = my_dict['a'] # 这是一个 O(1) 操作

线性时间 O(n)
线性时间算法的运行时间取决于输入数据的大小。

例如,如果我有一个包含100个数字的数组,代码会运行得很快。但如果数组大小增加到一百万个,完成操作所需时间将大大延长。在这种情况下,数据规模直接影响代码的运行时间。

公式描述:
运行时间 ∝ 输入规模 n

对数时间 O(log n)
对数时间算法指的是运行时间与操作次数成对数关系。

我可以采用线性方法来从100个数字中寻找一个目标值(例如97)。在线性方法中,需要96次迭代才能找到它,因为它需要逐个遍历每个项,直到找到目标值。

而使用二分查找法,我可以大幅减少迭代次数,在不到7次迭代内找到目标值。这通过对数时间来度量。二分查找的工作原理是每次都将列表分成两部分,检查目标是小于还是大于中间值。

核心思想:
每次迭代将问题规模减半。

平方时间 O(n²)

平方时间指的是对输入数据的每个值进行线性操作,且该操作本身也是线性的,结果与数据规模的平方成正比。
这通常出现在嵌套循环中。如下面的for循环被认为是平方时间,因为外层循环需要以线性方式迭代10次,并且对于外层循环的每一次迭代,内层循环也需要迭代相同的10次。这意味着它的总迭代次数是10乘以10,即100次。
代码示例:
for i in range(n): # O(n)
for j in range(n): # O(n)
# 执行某些操作 # 总复杂度 O(n * n) = O(n²)

指数时间 O(2^n)

指数时间算法是指运行时间随着每次迭代而翻倍的算法。

斐波那契数列递归计算是这方面的一个典型例子。

公式描述:
运行时间 ∝ 2^n,其中 n 通常是输入规模或递归深度。

总结与过渡 🎯
重构代码可能是一项艰巨的任务,但理解算法复杂度及其计算方式,能使优化代码变得更加容易。
在本节课中,我们一起学习了常数时间、线性时间、对数时间、平方时间和指数时间的概念。了解这些是朝着成为开发者的目标迈出的重要一步。现在你已经掌握了度量代码效率的基本工具,在后续的编码和优化工作中,可以更有意识地选择和改进算法。
Python 36:什么是函数式编程 🧮
在本节课中,我们将要学习函数式编程的基本概念。这是一种与面向对象编程等模型不同的编程范式,特别擅长高速处理大量数据。我们将探讨纯函数、递归、字符串反转以及Python中实用的map和filter函数。
函数的角色
首先,我们来探讨函数的作用。函数接收一些输入,进行处理,然后产生一些输出。函数主要分为两种类型:传统函数和纯函数。


纯函数无论被调用多少次,总是执行相同的操作并返回相同的结果。传统函数和纯函数之间存在几个关键区别。
以下是它们的主要区别:



- 传统函数可以访问和修改全局状态中的变量,但纯函数不能。
- 传统函数和纯函数都可以访问局部状态中的变量。
- 传统函数可以改变状态,而纯函数不能。
- 传统函数的输出不依赖于输入,而纯函数的输出则依赖于输入。
函数式编程的本质

上一节我们介绍了函数的类型,本节中我们来看看函数式编程的核心思想。

函数式编程本质上是一种利用函数来编写清晰、一致且可维护代码的编程范式。



与我们之后将学习的面向对象编程相比,函数式编程在设计上有所不同。



函数式编程不会改变函数作用域之外的数据。


这意味着函数应避免修改输入数据或传递的参数,而应只返回被调用函数的预期结果。



函数被认为是独立或自包含的,这有助于代码的简洁和优雅。



事实上,许多强类型的面向对象语言已将函数式编程融入其结构中。为了支持函数式编程,语言本身需要允许将函数作为参数传递,并允许函数将另一个函数返回给其调用者。
Python中的函数

了解了函数式编程的原则后,我们来看看它在Python中的体现。


在Python中,函数是所谓的“一等公民”。这本质上意味着它们与字符串和数字具有同等的地位。




它们可以被赋值给变量、作为参数传递或返回给调用者。



Python内置函数示例
现在,让我们探索几个Python中可用的函数示例。以sorted函数为例。

sorted函数接受一个项目列表,然后返回一个排序后的列表。


你可以使用sorted函数按字母顺序列出项目。通过将一个咖啡列表传递给sorted函数,返回的结果是按字母顺序排序的列表。
coffees = [‘Latte‘, ‘Espresso‘, ‘Cappuccino‘]
sorted_coffees = sorted(coffees)
print(sorted_coffees) # 输出: [‘Cappuccino‘, ‘Espresso‘, ‘Latte‘]


函数式编程的一大优点是,某些任务背后的逻辑已经为你内置好了。函数是可重用的,因此节省了大量开发时间。
创建自定义函数
但你是否知道,你也可以根据自身需求创建特定的函数?让我们看一个简单的例子。假设你想将咖啡的名字倒序拼写。


这可能不完全实用,但它很好地展示了函数式编程。


你可以创建自己的简单反转函数来实现这一点。定义函数,我们称之为reverse_string,并为其分配变量str。现在使用切片函数返回str的值。你将在课程后面了解更多关于切片函数的知识。
def reverse_string(s):
return s[::-1]
然后,将一个变量赋值为map函数的结果。map函数接受反转函数作为其第一个参数,然后是可迭代的咖啡列表。它会自动处理迭代,遍历每种咖啡并对其应用反转函数。
coffees = [‘Latte‘, ‘Espresso‘, ‘Cappuccino‘]
reversed_coffees = list(map(reverse_string, coffees))
print(reversed_coffees) # 输出: [‘ettaL‘, ‘osserpsE‘, ‘oniccuppaC‘]


总结
本节课中,我们一起学习了函数式编程是什么,并介绍了Python中内置函数的例子。我们了解了纯函数与传统函数的区别,函数式编程的核心原则,以及如何在Python中利用函数作为一等公民的特性来编写清晰、可复用的代码。
Python 37:纯函数 🧠
在本节课中,我们将要学习纯函数的概念。纯函数是函数式编程中的一个核心思想,它能让代码更清晰、更易于调试和维护。我们将通过对比传统函数与纯函数,理解其定义、优势,并通过一个具体的代码示例,学习如何将一个非纯函数改造为纯函数。
什么是纯函数?🤔
上一节我们介绍了纯函数的重要性,本节中我们来看看它的精确定义。
一个纯函数是指不会改变或影响其自身作用域之外的任何变量、数据、列表或集合的函数。例如,如果存在一个全局作用域内的列表,纯函数不能向该列表添加任何内容,也不能以任何方式修改它。
纯函数 vs. 非纯函数 ⚖️
为了更清晰地理解,让我们分析一个例子,并判断它是否为纯函数。
以下代码包含一个全局列表和一个函数:
my_list = [1, 2, 3]
def add_to_list(item):
my_list.append(item)
return my_list
print(add_to_list(4)) # 输出:[1, 2, 3, 4]
print(my_list) # 输出:[1, 2, 3, 4]
你认为这是一个纯函数吗?不是。因为它通过附加传入的参数 item 修改了全局列表 my_list。
如何创建纯函数?🔧

要将上述函数改为纯函数,我们需要思考如何:
- 扩展函数以接受一个列表作为参数。
- 在不修改原始列表的情况下向列表添加项。
- 返回一个包含新添加项的新列表。
解决方案是:创建一个新列表,并复制或克隆原始列表的数据。
让我们修改代码:
my_list = [1, 2, 3]
def add_to_list(lst, item):
new_list = lst.copy() # 创建原始列表的副本
new_list.append(item) # 修改副本
return new_list # 返回新列表
new_list = add_to_list(my_list, 4)
print(my_list) # 输出:[1, 2, 3]
print(new_list) #输出:[1, 2, 3, 4]
现在,这个函数就是一个纯函数了。它返回了一个包含新元素的新列表,而原始列表 my_list 保持不变。
纯函数的优势 ✨
理解了纯函数的定义和创建方法后,我们来看看使用它的好处。以下是纯函数的主要优势:
- 结果可预测:纯函数是行为一致的代码片段,总是返回相同的输出。
- 易于测试和调试:由于没有副作用,测试时只需关注输入和输出。
- 可缓存性:因为给定相同的输入总是返回相同的输出,结果可以被缓存以提高性能。
- 适合并发编程:在多线程程序中,多个进程可能并发运行。纯函数有助于防止对全局作用域的修改,确保数据可靠性。
实战演示:一步步改造纯函数 💻
现在,我们通过一个更详细的步骤演示,在VS Code中如何将一个普通函数改造为纯函数。
首先,我创建一个非纯函数:
my_list = [1, 2, 3]
def add_to_list(item):
my_list.append(item)
return my_list
new_list = add_to_list(4)
print(my_list) # 输出:[1, 2, 3, 4]
print(new_list) # 输出:[1, 2, 3, 4]
这个函数不是纯函数,因为它从函数内部操纵了全局作用域的数据。
第一次尝试改造:我们尝试传入列表作为参数并返回它。
def add_to_list(lst, item):
lst.append(item)
return lst
new_list = add_to_list(my_list, 4)
print(my_list) # 输出:[1, 2, 3, 4]
print(new_list) # 输出:[1, 2, 3, 4]
这仍然不是纯函数。虽然传入了参数,但函数内部更新的 lst 和外部传入的 my_list 指向同一个对象。
最终方案:要创建纯函数,关键是如何创建一个新列表,并将传入列表的所有值复制到新列表中。
def add_to_list(lst, item):
nl = lst.copy() # 创建传入列表的副本
nl.append(item) # 修改副本
return nl # 返回新列表
new_list = add_to_list(my_list, 4)
print(my_list) # 输出:[1, 2, 3]
print(new_list) # 输出:[1, 2, 3, 4]
现在,我们得到了两个不同的结果。my_list 保持不变,而 new_list 包含了新添加的值。这个函数现在是一个纯函数。

总结 📝
本节课中我们一起学习了纯函数。我们首先明确了纯函数的定义:一个不产生副作用、不修改外部状态的函数。然后,我们对比了非纯函数与纯函数的区别,并通过一个具体的列表操作示例,逐步演示了如何将非纯函数改造为纯函数。最后,我们总结了纯函数在可预测性、可测试性、可缓存性和并发安全方面的优势。在你的编程生涯中,很可能会经常使用纯函数,因为它们能让你的代码更干净、更易于调试和扩展。
Python 38:递归
在本节课中,我们将要学习编程中的一个核心概念——递归。我们将了解递归的定义、工作原理,并通过一个具体的例子(计算阶乘)来对比循环与递归两种解决方案。最后,我们将总结递归的优缺点。
什么是递归?🤔
在编程中,递归用于解决那些可以被分解为更小的、重复性子问题的问题。
它特别适用于处理具有许多可能分支且过于复杂、难以用迭代方法解决的问题。

一个很好的例子是遍历文件系统。
那么,递归究竟是什么?


递归本质上是一个调用自身的函数。递归创建了一种模式,即函数自身一遍又一遍地重复执行。
从编码的角度来看,这意味着什么?


在这个例子中,一个函数接受一个参数,并且在函数内部,它包含一些逻辑来处理它试图解决的问题。
关键部分是返回语句。在代码中,返回语句返回的是同一个函数。
递归与 for 循环非常相似。



它会迭代,或者在递归函数的情况下,多次调用自身。
但请注意:当你创建一个递归函数时,必须始终考虑终止条件。如果不这样做,它将陷入无限循环,耗尽所有内存,直到程序最终崩溃或被终止。


循环与递归:计算阶乘 🧮
上一节我们介绍了递归的基本概念,本节中我们来看看如何用循环和递归两种方法来解决同一个问题——计算一个数的阶乘。
让我们从循环解决方案开始。
循环函数接受一个名为 n 的整数作为参数,首先检查该数是否小于零。如果是,则返回零,因为负数没有阶乘。

else 条件将 factorial 变量初始化为 1,然后循环遍历参数的范围(在本例中为 5)。循环将计算 1 * 2 * 3 * 4 * 5,得到答案 120,即 5 的阶乘。

现在,让我们探索同一问题的递归解决方案。
递归函数更简单、更紧凑。主要原因是您不再需要完整的循环来迭代参数 n。
函数的第一行验证数字是否为 1,如果是则返回 1。else 条件将参数 n 乘以调用 find_factorial_recursive 函数并传入 n - 1 的结果。


递归的执行过程 🔄
仅通过解释可能难以理解递归,让我们来演示函数调用自身时到底发生了什么。
函数被一遍又一遍地调用,每次变化的部分是传入函数的值。


参数 n(本例中为 5)每次减少 1,直到最终变为 1。这阻止了函数再次被调用,并退出了递归过程。



那么,这段代码究竟是如何得到结果 120 的呢?

这是由返回语句提供的。它保留了对递增值的引用,这是完成计算后的最终返回值。


递归的优缺点 ⚖️
了解了递归的工作原理后,现在我们来回顾一下递归的优缺点。
以下是递归的主要优点:
- 递归代码可以使您的代码更整洁、更简洁。
- 复杂的任务可以分解为更易于阅读的子问题。
- 序列的生成可能比嵌套循环更容易理解。
但递归也存在缺点:
- 递归代码的逻辑可能更难跟踪。
- 在内存方面,递归开销大,有时效率低下。
- 递归代码也可能难以调试和逐步执行。


总结 📝
本节课中我们一起学习了递归。你现在应该能够解释什么是递归,以及如何用它来解决问题。
相信你将来会在代码中受益于递归的使用。
Python 39:字符串反转教程 🔄
在本节课中,我们将学习如何在Python中反转一个字符串。这是测试Python开发者解决问题能力的基本方法之一。掌握此技能在生产环境中非常有用。一些编程语言内置了反转字符串的函数,但Python没有。幸运的是,得益于Python语言的灵活性,我们有多种方法可以实现这个功能。本视频将向你展示两种在Python中反转字符串的方法。

方法一:使用切片函数
上一节我们介绍了课程目标,本节中我们来看看第一种方法——使用切片函数。
切片函数的格式或语法是:以字符串名称开头,后跟一个左方括号,然后是起始参数、冒号、结束参数、另一个冒号,接着是步长参数,最后是一个右方括号。这被称为扩展切片语法。起始和结束参数是函数操作字符串的索引范围。步长参数是函数遍历给定字符串时的跳跃或步进值。
以下是使用切片函数反转字符串的步骤:
- 首先,我创建一个名为
string_reversal.py的文件。 - 定义一个字符串变量。我将这个字符串命名为
trial,并为其赋值单词 “reversal”。 - 为了操作这个字符串,我创建一个新的字符串变量
new_trial。 - 使用切片函数为
new_trial赋值。语法是trial[::]。为了指示Python使用整个字符串,我将起始和结束参数留空,只输入两个冒号。然后将步长参数的值设为-1。 - 步长参数的负值表示字符串需要从右向左遍历,每次移动一个索引位置,而不是传统的从左开始的方法。
- 最后,我打印操作后的字符串以测试它是否有效。
核心代码示例:
trial = "reversal"
new_trial = trial[::-1]
print(new_trial)
运行代码后,终端成功显示了反转后的字符串。
总结: 整个字符串从右向左遍历,每次一个索引位置。这个新的切片对象随后被复制到另一个字符串,该字符串经过重新排列后被打印出来。需要注意的是,你可以使用切片函数来操作同一个变量。本例中为了清晰起见,我使用了第二个变量。切片函数是反转字符串最简单的方法。
方法二:使用递归和切片
在学习了简单的切片方法后,本节中我们将探讨另一种结合递归来反转字符串的方法。
这次,我创建一个新文件并保存为 string_reversal_2.py。接下来,我定义一个函数并向其传递一个字符串变量 str。这个函数将充当一个条件 if 语句。else 语句将递归调用切片函数,但每次调用时都会传入一个修改过的字符串。
以下是使用递归反转字符串的步骤:
- 定义一个函数
string_reverse(str)。 - 在函数内部,使用
if语句检查字符串长度是否为0。如果是,则返回该字符串。 - 在
else语句中,递归调用string_reverse函数,但传入的字符串是str[1:](即从第二个字符开始到结尾的子串),然后将第一个字符str[0]附加在后面。 - 在函数外部,给
str变量赋值为 “reversal”。 - 创建第二个变量
reversed_str来存储函数返回的字符串值。 - 最后,添加一个打印语句来输出
reversed_str变量。
核心代码示例:
def string_reverse(str):
if len(str) == 0:
return str
else:
return string_reverse(str[1:]) + str[0]
str = "reversal"
reversed_str = string_reverse(str)
print(reversed_str)
运行代码,字符串在终端中以相反的顺序成功显示。
原理: 该函数通过每次递归传递一个不同的字符串并附加它保留的元素(第一个字符)来调用自身。

课程总结 🎯

本节课中,我们一起学习了两种在Python中反转字符串的不同方法:第一种是仅使用切片函数,第二种是结合使用切片函数和递归。这两种方法都充分利用了Python的灵活性,是解决此常见编程问题的有效途径。
Python 40:map与filter函数详解 🧮
在本节课中,我们将学习如何使用Python中的map和filter函数来处理列表数据。这两个函数是函数式编程中的重要工具,能够帮助我们以简洁、高效的方式对列表元素进行转换和筛选。
假设我们想基于一个现有列表生成一个新列表。通常的做法是对现有列表中的每个元素应用某种操作,然后使用这些操作的输出结果来生成新列表。在Python中,有多种方法可以实现此目的。本节视频将重点介绍如何使用map和filter函数来处理列表。
准备工作与目标设定 ☕
我的文件中有一个名为menu的列表,其中包含了各种咖啡的名称。我的目标是筛选这个列表,找出特定的咖啡。例如,我想打印出所有以字母“C”开头的咖啡。

我将通过创建一个函数来实现这个目标,该函数将接收列表中的元素并与字母“C”进行比较。然后,我将演示如何先使用map函数,再使用filter函数来获取输出结果。
在开始之前,让我先介绍一下map函数的基本格式。请注意,filter函数的格式与之相同。
要创建一个map,需要键入map并定义其参数。map函数接受两个参数:
- 第一个参数是一个实际的函数。在本例中,它将是我用来根据条件匹配值的函数。
- 第二个参数是将要传递给该函数的可迭代对象。在本例中,就是我
menu列表中的咖啡。
创建条件函数 🔧
现在,让我们创建带有条件的函数。
我键入def和函数名find_coffee。然后在括号内添加一个参数coffee,并在右括号后加上冒号。我添加的coffee参数将代表列表中的每一项。
接下来,我需要检查列表中每一项的首字母是否与字母“C”匹配。为此,我将创建一个if语句:键入if coffee[0] == "C":。这表示如果coffee变量的第一个字母等于“C”,则执行后续操作。
我按下回车,在下一行键入return coffee。如果if语句为真,则返回该咖啡名称。
使用map函数处理列表 📝
为了使用map函数,我将把它赋值给一个名为map_coffee的变量。
我键入map_coffee = map(。现在可以传入map函数的参数了。记住,第一个参数是函数本身。我输入函数名find_coffee。需要注意的是,我并不是在调用这个函数,而是像传递参数一样传递它。 在find_coffee后添加一个逗号,然后传入第二个参数,即可迭代对象menu。
最后,我想打印出map_coffee的值,以便在终端中查看结果。我点击运行,在终端中,我收到了一个map对象作为输出。
下一步是遍历这个map对象。我键入for x in map_coffee: print(x)。
我再次点击运行,现在得到了map的输出。在终端中,除了“cappuccino”和“Cortado”之外,还出现了许多值为None的输出。这是因为只有“cappuccino”和“Cortado”是函数中匹配字母“C”的两项。
map函数的一大优点是,我不需要专门创建一个for循环来遍历列表。map函数将函数作为参数,并将menu列表的值逐一传递给该函数。这为我处理了迭代过程,使其非常有用。
使用filter函数处理列表 🎯
接下来,我将演示如何使用filter函数获取输出。首先,我将注释掉与map函数相关的代码部分,并清空终端。
filter函数的工作方式与map函数非常相似。
我声明一个名为filter_coffee的变量,并将filter函数赋值给它。同样,我添加两个参数:find_coffee函数和menu列表。
然后我打印变量filter_coffee。点击运行后,我收到了一个filter对象作为输出。
现在,我将像遍历map对象一样遍历这个filter对象。我键入for x in filter_coffee: print(x)。清空终端后点击运行。
这次,只返回了“cappuccino”和“Cortado”。这是为什么呢?
map与filter的核心区别 🤔
让我解释一下map函数和filter函数之间的区别。
map函数会获取列表中的所有对象,并允许你对每个对象应用一个函数。它返回一个包含所有函数返回值的新可迭代对象。如果函数对某些元素返回None,这些None也会被包含在结果中。

filter函数同样会接收列表中的所有对象,并通过一个函数运行它们。但它创建一个新的列表,并且只返回那些使评估函数返回True的值。这就是为什么在filter函数的输出中没有显示任何None值。
总结 📚
本节课中,我们一起学习了map和filter在Python中如何工作。你现在应该能够使用这两个函数来处理列表数据,并且能够解释它们之间的核心区别。

简单来说:
map(function, iterable):将函数应用于可迭代对象的每一个元素,并返回所有结果。filter(function, iterable):根据函数的真假条件(返回True或False)筛选可迭代对象中的元素,只保留使函数返回True的元素。


掌握这两个函数能让你的代码更加简洁和高效。
Python 41:面向对象编程简介 🐍
在本节课中,我们将要学习面向对象编程的基本概念。这是一种广泛使用的编程范式,它通过将数据和操作数据的方法组织成“对象”,来帮助程序员更高效、更清晰地构建复杂程序。
编程语言基于特定的模型构建,以确保代码行为可预测。Python主要遵循一种被称为面向对象范式或模型的编程方式。
正如你将很快发现的,面向对象编程(OOP)严重依赖于简单性和可重用性来提升工作流程。在本视频结束时,你将熟悉面向对象编程范式,并且能够识别定义面向对象编程的四个主要概念。
什么是编程范式?🤔
编程范式是一种用于降低代码复杂性和确定执行流程的策略。
存在多种不同的范式,例如声明式、过程式、面向对象、函数式、逻辑式、事件驱动式、流驱动式等等。这些范式并非互斥的,因此程序员和编程语言可以选择采用多种范式。
例如,Python主要是面向对象的,但它也支持过程式和函数式编程。
简单来说,范式可以被定义为一种编写程序的风格。OOP是当今使用最广泛的范式之一,这得益于采用它的语言(如Java、Python、C++等)日益流行。但OOP能够将现实世界问题转化为代码的能力,可以说是其成功的最大因素。

OOP具有高度的模块化,这使得代码更易于理解、可重用、增加了抽象层次,并允许代码块在项目之间移动。

OOP的核心组件:类、对象与方法 🧱
为了帮助你更好地理解OOP,我首先澄清一些其关键组件:类、对象和方法。
类


类是一个包含属性和行为的逻辑代码块。在Python中,类使用 class 关键字定义。属性可以是变量,行为可以是其内部的函数。
你可以从这些类中创建实例,这些实例被称为对象。换句话说,类为创建对象提供了一个蓝图。
更实际地说,假设你想记录Little Le公司员工的属性,例如他们的职位和雇佣状态。你可以创建一个名为 Employee 的类,并方便地将这些属性捆绑在一个地方。
class Employee:
pass # 类的定义
对象
如前所述,对象是类的一个实例,你可以创建任意数量的对象。对象的状态由其属性和行为构成,每个对象都有一个唯一的ID以区别于其他实例。类的属性和行为定义了对象的状态。
例如,你可以通过调用 Employee 类来创建对象 emp1。调用后,你可以将职位和雇佣状态属性分别定义为“轮班主管”和“全职”。在代码中,这将写为:
emp1 = Employee("Shift Lead", "FT") # 实例化,即创建类的实例
方法
方法是定义在类内部的函数,它决定了对象实例的行为。假设你希望员工对象输出一个说明其职位的字符串。你首先需要在 Employee 类中声明一个名为 intro 的函数,然后在对象上调用它以获得输出。
class Employee:
def __init__(self, position, status):
self.position = position
self.status = status
def intro(self):
return f"My position is {self.position}."
OOP的四大支柱 🏛️
现在你了解了类、对象和方法,让我们来探讨OOP所依赖的核心概念。
以下是支撑OOP的四个关键概念:
-
继承
继承是通过从现有类派生来创建新类。原始类称为父类或超类,而任何派生类被称为子类。这允许代码重用和层次结构的建立。 -
多态
多态是一个意为“具有多种形式”的词汇。在Python的上下文中,多态意味着单个函数可以根据调用它的对象不同而表现出不同的行为。例如,内置的
+运算符对于不同的数据类型工作方式不同。对于整数数据类型,+执行加法运算,如3 + 5 = 8。另一方面,对于字符串数据类型,内置的+运算符执行连接操作,即将两个字符串组合在一起。这种修改功能的能力被称为多态。 -
封装
广义上讲,这意味着Python可以通过将方法和变量包装在单个作用域单元(例如类)内,来限制对它们的直接访问。封装有助于防止不必要的修改,从而有效减少错误和意外输出的发生。 -
抽象
抽象指的是隐藏实现细节以使数据更安全、更可靠的能力。需要注意的是,Python不直接支持抽象,而是使用继承来实现它。这将在以后更详细地探讨。
OOP中还有其他一些重要概念,如方法重载、方法重写、构造函数等,这些将在以后更详细地学习。

本节课中我们一起学习了面向对象编程范式及其四大核心概念:继承、多态、封装和抽象。理解这些概念是掌握Python等面向对象语言的关键第一步。下次见!
Python 42:Python 类和实例 🐍
在本节课中,我们将要学习 Python 中一个核心概念:类。类能够将数据和功能组合在一起,这在编程中是一个非常实用的特性。通过本节课的学习,你将能够解释 Python 中的类、实例和对象是什么,并能够创建类、实例化它以及访问其变量和方法。
什么是类、实例和对象? 🤔
你可能也听说过类可以从属性和行为的角度来讨论。一般来说,属性指的是类中声明的变量,而行为则与类中的方法相关联。
一个类会创建一个新的对象类型,你可以从这个类型创建出实例。需要记住的一个重要概念是:Python 中的一切都是对象,或者派生自 object 类。
为了演示这一切是如何运作的,我们将在 VS Code 中创建一个新文件,并编写一个类,然后从中派生出对象。
创建你的第一个类 🏗️
首先,我输入关键字 class,后跟类名 MyClass 和一个冒号。为了让 Python 不报错,我还需要多做一步。

class MyClass:
那就是在下一行输入 pass 关键字。pass 关键字扮演着占位符的角色,表示此处不需要执行任何操作。实际上,这告诉 Python 我暂时还不会对这个类做任何事情。
接下来,让我们为这个类创建一个对象。我创建一个名为 my_class 的变量,然后通过输入 = MyClass() 将类赋值给它。
my_class = MyClass()
如果我运行这段代码,输出显示它已执行且没有错误。然而,为了确认它按预期工作,让我们在类中添加一个 print 语句。
class MyClass:
print("Hello")
当我再次运行代码时,单词 “Hello” 出现在输出中。在继续之前,让我先清空终端。
理解实例化过程 🔄
你可能注意到我使用了相同的名字来命名类和它的对象,但实际上对象名可以是任何名称。例如,如果我将对象名改为 my_instance 并再次运行代码,它的执行效果将与之前相同。
my_instance = MyClass()
我输入的所有内容都是 Python 中实例化过程的一部分,这个过程包含三个关键步骤:
- 类定义:使用
class关键字定义类。 - 创建新实例:通过
ClassName()创建类的一个新实例。 - 初始化新实例:通常通过
__init__方法完成(本节课未涉及)。
由于 Python 中的一切都是对象,遵循命名约定可以让后续工作不那么混乱。在这个例子中,我有 MyClass 作为类对象,my_instance 作为实例对象。还有第三种对象叫做方法对象,你可以在需要时用它来调用方法。
类的两种主要操作 📝
类主要执行两种操作:属性引用和实例化。我已经写了一个后者的例子,所以这次让我们尝试构建一个属性引用。
首先,我为类对象创建一个变量 a,并为其赋值 5。
class MyClass:
a = 5
要打印这个变量,我首先需要引用类。因此,在实例对象下方,我输入 print(MyClass.a)。
print(MyClass.a) # 输出: 5
当我运行代码时,它在输出中返回 5。为了确认类引用是必要的,我从 print 语句中删除 MyClass 并再次运行代码,Python 会抛出一个错误。所以我会修正代码,把 MyClass 加回去。
在继续之前,让我快速清空终端。现在你知道引用类对象会发生什么,但如果引用实例对象呢?让我们通过为 my_instance.a 输入一个 print 语句来找出答案,然后运行它。
print(my_instance.a) # 输出: 5
在输出中我得到了 5,这表明属性引用对实例对象仍然有效。
在类中创建方法 ⚙️
最后,让我们通过在这个类中创建一个方法来结束本节课。我将使用 def 关键字,后跟 hello、一对括号和一个冒号。
class MyClass:
a = 5
def hello(self):
print("Hello world")
在下一行,我为字符串 "Hello world" 输入一个 print 语句。为了避免混淆,我也会删除第一个 print 语句。为了调用这个方法,我在文档末尾为 my_instance.hello() 添加一个新的 print 语句,它使用了实例对象。
my_instance.hello()
这应该能正常工作,就像我通过实例对象成功调用变量一样,对吧?运行代码会导致一个错误。所以方法并不那么简单。幸运的是,我可以通过在类中定义的方法括号内添加关键字 self 来解决这个问题。
def hello(self):
print("Hello world")
再次运行代码会在输出中产生单词 “Hello world”。你还会发现下面打印了单词 None,因为给定的函数没有返回值。
总结 📚


本节课中我们一起学习了 Python 中的类、实例和对象。我们创建了一个类,然后能够实例化它并访问其变量和方法。这是一个关于如何将数据(属性)和功能(方法)捆绑在一起的强大概念的简要演示。理解这些基础是进行更高级的面向对象编程和数据库建模的关键。
Python 43:实例化自定义对象
在本节课中,我们将要学习Python中代码复用的核心概念,即如何通过创建类和实例化对象来重用代码。你将学会定义一个类,为其添加属性和方法,并创建多个独立的实例。我们将看到,即使不同的实例调用相同的方法和属性,它们也可以产生不同的结果,这正是代码复用的体现。
代码复用与面向对象
代码复用是指利用现有代码构建新软件的过程。它是编程的核心概念之一。通过创建类,我们可以定义一种数据结构和与之相关的行为(方法)。之后,我们可以基于这个类创建多个实例(对象),每个实例都拥有独立的属性状态,但共享相同的方法定义。

上一节我们介绍了代码复用的概念,本节中我们来看看如何在Python中通过创建类和实例化对象来实现它。
创建Recipe类
首先,创建一个名为 recipe.py 的新文件,并在其中定义一个名为 Recipe 的类。
class Recipe:
pass
在深入之前,我们先了解Python中的两个特殊方法。
特殊方法:__new__ 和 __init__
以下是关于这两个方法的说明:
__new__方法:负责创建并返回一个新的空对象。其基本结构如下:def __new__(cls): # cls 是一个约定,代表类本身,用于创建新对象 return super().__new__(cls)__init__方法:在其他一些编程语言中被称为“构造函数”。它接收由__new__方法创建的对象以及其他参数,用于初始化这个新创建的对象。其基本结构如下:def __init__(self, arg1, arg2): # self 是一个约定,代表实例对象本身,用于引用实例的属性和方法 self.attribute1 = arg1 self.attribute2 = arg2
注意:
cls和self不是Python关键字,而是广泛遵循的命名约定。cls作为类的占位符,self作为实例对象的占位符。
现在,让我们删除示例方法,编写一个实用的 __init__ 方法来初始化对象的状态。
定义类的属性和方法
设想一个现实场景:一位餐厅厨师需要管理他使用的食谱信息。我们将创建一个 Recipe 类来帮助他。
我们将为食谱定义三个属性:菜名 (dish)、配料 (items) 和准备时间 (time)。以下是初始化这些属性的代码:
class Recipe:
def __init__(self, dish, items, time):
self.dish = dish
self.items = items
self.time = time
接下来,我们添加一个名为 contents 的方法,用于将食谱信息格式化为字符串并打印出来。
def contents(self):
print("The " + self.dish + " has " + str(self.items) +
" and takes " + str(self.time) + " minutes to prepare.")
代码说明:在拼接字符串时,我们使用
str()函数将self.items(一个列表)和self.time(一个整数)转换为字符串。使用反斜杠\可以将一行长代码换行书写,以提高可读性。
现在,我们的类已经设置好了,接下来用它来创建具体的食谱实例。
实例化对象并访问其成员
我们可以基于 Recipe 类创建不同的食谱对象。每个对象在创建时传入不同的参数,从而拥有独立的状态。
以下是创建两个实例的代码:
# 创建披萨食谱实例
pizza = Recipe("Pizza", ["cheese", "bread", "tomato"], 45)
# 创建意大利面食谱实例
pasta = Recipe("Pasta", ["penne", "sauce"], 55)
创建实例后,我们可以访问每个实例的属性和方法。尽管它们调用的是类中定义的同一个属性名 items 和同一个方法 contents,但结果却因实例状态的不同而不同。
让我们通过打印来验证这一点:
# 访问实例属性
print(pizza.items) # 输出: ['cheese', 'bread', 'tomato']
print(pasta.items) # 输出: ['penne', 'sauce']
# 调用实例方法
pizza.contents() # 输出: The Pizza has ['cheese', 'bread', 'tomato'] and takes 45 minutes to prepare.
pasta.contents() # 输出: The Pasta has ['penne', 'sauce'] and takes 55 minutes to prepare.

运行上述代码,你将看到两个实例输出了各自不同的信息。这清晰地展示了代码复用:我们只编写了一次 Recipe 类和 contents 方法,但却能用于生成无数个具有不同数据的食谱对象。
总结

本节课中我们一起学习了Python面向对象编程的基础。我们首先了解了代码复用的概念,然后逐步创建了一个 Recipe 类,定义了其初始化方法 __init__ 和一个自定义方法 contents。接着,我们实例化了两个对象 pizza 和 pasta,并演示了如何访问它们的属性以及调用它们的方法。最关键的是,我们看到了相同的代码(类定义)如何根据不同的实例数据产生不同的输出,这正是面向对象编程中封装和复用的强大之处。
Python 44:实例方法 🧑💻
在本节课中,我们将学习如何通过实例变量和实例方法,来管理对象的状态。我们将通过一个餐厅经理支付员工工资的实际问题,来演示这些概念的应用。
概述
在面向对象编程中,类定义了对象的蓝图。每个根据类创建的对象称为实例。实例拥有自己的数据(称为实例变量)和可以执行的操作(称为实例方法)。本节课我们将创建一个 Paylips 类,用于管理员工的支付状态,并学习如何使用实例方法来独立地更新每个员工对象的状态。
创建 Paylips 类

首先,我们创建一个名为 paymentinfo.py 的新文件。在这个文件中,我们将定义一个 Paylips 类。
class Paylips:
def __init__(self, name, payment, amount):
self.name = name
self.payment = payment
self.amount = amount
在 __init__ 方法中,我们初始化了三个实例变量:name(员工姓名)、payment(支付状态)和 amount(支付金额)。self 关键字代表实例本身,用于将参数值绑定到该实例的属性上。
定义实例方法
接下来,我们为 Paylips 类添加两个实例方法:一个用于支付,另一个用于检查状态。
def pay(self):
self.payment = “yes”
def status(self):
if self.payment == “yes”:
return self.name + “ is paid “ + str(self.amount)
else:
return self.name + “ is not paid yet”
pay方法将实例的payment状态更新为“yes”。status方法根据payment的状态,返回一个描述该员工支付状态的字符串。
创建实例并调用方法
现在,让我们创建两个员工实例,并检查他们的初始状态。
nathan = Paylips(“Nathan”, “no”, 1000)
roger = Paylips(“Roger”, “no”, 3000)
print(nathan.status())
print(roger.status())
运行这段代码,输出会显示 Nathan 和 Roger 都尚未支付。为了让输出更清晰,我们可以在 print 语句中添加换行符 \n。
更新实例状态
假设经理决定支付 Nathan 的工资。我们可以调用 Nathan 实例的 pay 方法来更新他的状态。
print(“After payment:”)
nathan.pay()
print(nathan.status())
print(roger.status())
再次运行代码,输出将显示 Nathan 的支付状态已更新为“已支付”,而 Roger 的状态保持不变。这证明了实例方法只影响调用它的那个特定实例。

核心概念详解
上一节我们通过代码演示了实例方法的作用,本节中我们来详细看看其背后的原理。
在编码示例中,Nathan 和 Roger 是两个独立的实例对象,各自拥有自己的状态(即实例变量的值)。当你调用 Nathan 的 pay 方法来改变他的状态时,Roger 完全不受影响。这是因为类中定义的方法并非直接影响所有实例,而是为每个实例提供了一套可以独立操作的蓝图。
在代码中,我们没有在调用 pay 函数后直接打印变量值,但如果这样做,你会看到 Nathan 的 payment 实例变量从 “no” 变成了 “yes”,而 Roger 的 payment 变量仍然是 “no”。
实际应用场景
现在,让我们想象这段代码是一个在线支付系统的基础。它将允许任何经理点击某个员工的“支付”按钮,然后仅更新该员工的支付状态。这样就消除了经理之间反复沟通确认的需要,实现了流程的自动化。

总结
本节课中,我们一起学习了实例变量和实例方法的核心概念。你学会了如何定义一个类,在其中初始化实例变量,并创建用于操作这些变量的实例方法。最重要的是,你理解了如何通过实例方法改变单个实例对象的状态,而不会影响其他任何实例。这为构建模块化、可独立管理对象的应用程序奠定了坚实基础。
Python 45:父类与子类 🧬
在本节课中,我们将要学习面向对象编程中的一个核心概念——继承。通过继承,我们可以创建一个新的类(子类),它能够复用现有类(父类)的属性和方法,并在此基础上进行扩展或修改,从而避免重复编写代码,使程序结构更加清晰和高效。
类的实例化与继承需求
当从一个类实例化对象时,你可能会发现这个类缺少一些你经常使用的属性。
在这种情况下,你可以决定创建一个新的类,它复制了第一个类的功能,但额外增加了一些属性。
如果从头开始重新编写所有内容会非常繁琐,但得益于继承机制,你无需这样做。
理解继承:父类与子类
上一节我们提到了创建新类的需求,本节中我们来看看继承是如何具体工作的。
继承是面向对象编程,特别是Python中的一个核心概念,它是代码可重用性的重要组成部分。你可能知道Python中的一切都是对象,现在让我们更深入地探讨这个观点。
这具体意味着Python中的每个类都继承自一个名为object的内置基类,它位于builtins模块中。换句话说,像class SomeClass():这样的类声明,实际上等同于class SomeClass(object):。
在讨论类派生时,起源的类被称为父类、超类或基类;继承自它的类被称为子类、派生类或扩展类。任何命名方式都是可以接受的,但重要的是要知道,子类扩展了其父类的属性和行为。这允许你做两件事:
- 可以向子类添加新的属性。
- 可以在子类中修改继承来的属性,而不会影响父类。
Python中的继承示例
现在,让我们通过一个例子来探索在Python中如何实现继承。
这里有一个父类P,它包含一个值为7的变量A。
class P:
A = 7
然后是一个空的子类C,其中将父类P作为参数传入。
class C(P):
pass
最后,小写c代表子类C的一个实例。
c = C()
如果你为c.A编写一个打印语句并运行代码,输出将是7。

print(c.A) # 输出:7
所以,即使C本身是空的,它仍然持有从P继承来的属性。
请记住,父类中的任何更改也会影响所有子类。
实践:员工管理系统示例
现在你已经了解了继承的基本工作原理,让我们通过一个更具体的例子来探索它提供的灵活性。
我将创建一个名为employment.py的新文件,第一步是创建一个名为Employees的父类,我将在其中为名和姓定义两个变量。
class Employees:
def __init__(self, name, last):
self.name = name
self.last = last
接下来,我将创建两个都扩展自Employees类的子类。
第一个子类是Supervisors。为了调用Employees类,我这样写:
class Supervisors(Employees):
然后,我需要修改Supervisors类的__init__方法,以便添加另一个名为password的变量。通过调用Employees类,super()方法已自动应用,以访问父类的变量并在Supervisors类中初始化它们。
class Supervisors(Employees):
def __init__(self, name, last, password):
super().__init__(name, last)
self.password = password
现在,我将编写另一个名为Chefs的子类。
class Chefs(Employees):
在这个类中,我想包含一个新的函数leave_request。
class Chefs(Employees):
def leave_request(self, days):
return "May I take a leave for " + str(days) + " days?"
leave_request函数的目的是返回一个字符串,指明请求休假的天数。
创建实例并测试功能
现在所有类都已就位,我将从这些类中创建几个实例:一个用于主管,两个用于厨师。
首先,为主管创建一个实例:
adrian = Supervisors("Adrian", "A", "apple")
然后,为厨师创建两个实例:
emily = Chefs("Emily", "E")
juno = Chefs("Juno", "J")
接下来,让我们调用emily实例上的方法并传递一个值。她想请求三天的假期。
print(emily.leave_request(3))
我还将添加另一个打印语句来检查主管adrian的实例变量password。
print(adrian.password)
第三个打印语句输出emily的name变量值。
print(emily.name)
现在运行代码,得到以下输出:
- 第一个打印语句输出:
May I take a leave for 3 days? - 第二个打印语句输出:
apple - 第三个打印语句输出:
Emily
请注意,各个继承类中的实例变量和方法,以及来自父类的变量,都同时存在并可用。

总结 🎯
本节课中我们一起学习了Python中的继承机制。你了解到继承如何通过创建子类来复用和扩展父类的功能,从而使代码更具可重用性、组织性,并减少冗余。我们通过定义父类Employees,以及继承它的子类Supervisors和Chefs,实践了属性的继承、方法的添加与重写,并最终实例化对象验证了继承的效果。掌握继承是构建复杂、模块化Python应用程序的关键一步。
Python 46:抽象类和方法 🧩
在本节课中,我们将要学习面向对象编程中的一个重要概念:抽象类和方法。抽象类提供了一种定义通用接口和强制子类实现特定方法的方式,有助于提高代码的一致性、互操作性和可维护性。
什么是抽象类? 🤔
上一节我们介绍了课程概述,本节中我们来看看抽象类的核心定义。
在面向对象编程中,抽象类是一种无法被实例化的类。你不能直接创建一个抽象类的对象。它的主要作用是作为其他类的“蓝图”或“模板”。
公式/概念:抽象类 = 一个不能被实例化、用于定义子类必须实现的方法的类。

抽象类的作用与优势 🚀

了解了抽象类的基本定义后,我们来看看为什么需要使用它。

抽象类的主要作用是确保所有从它派生出来的子类都具备某些特定的功能。例如,“交通工具”(Vehicle)可以是一个抽象类。你不能创建一个“交通工具”对象,但你可以从它派生出“汽车”(Car)、“拖拉机”(Tractor)或“小船”(Boat)。

将方法定义在抽象类中,可以保证这些方法一定会出现在派生类中,因为派生类必须实现它们。如果“交通工具”有一个 turn_on_engine(启动引擎)方法,那么我们就可以确信,任何对派生类调用 turn_on_engine 的代码都能找到这个方法。

使用抽象类主要出于以下原因:
- 互操作性:确保不同子类对象能以统一的方式被调用。
- 一致性:强制子类遵循相同的接口规范。
- 避免代码重复:将公共接口的定义集中在一处。
Python中的抽象类 ⚙️

Python本身并不直接支持抽象类,因此我们需要导入一个专门的模块来定义它。这个模块叫做 ABC(Abstract Base Class,抽象基类)。

此外,抽象类中的方法需要先被声明,然后才能在子类中实现。考虑到这些限制,你可能会疑惑为什么要使用抽象类。它的一个关键优势是:能够在保持功能的前提下,隐藏具体的实现细节。
抽象方法的实现方式 🛠️

在抽象类中,方法的实现主要有两种方式。


第一种是,作为基础的抽象类自身没有实现,其方法必须由派生类来具体实现。
另一种可能性是使用 super() 函数,但这属于更高级的话题,我们暂时不深入讨论。
现在,让我们聚焦于如何定义抽象类。

如何定义抽象类与抽象方法 📝

你可能现在对模块还不熟悉,这没关系,后续课程会详细讲解。目前,你只需要跟着步骤操作即可。

首先,需要导入 ABC 模块和 abstractmethod 装饰器。

from abc import ABC, abstractmethod

接下来,创建一个类,并让它继承自 ABC 类,这样就定义了一个抽象类。
class SomeAbstractClass(ABC):
pass
然后,在抽象类内部,使用 @abstractmethod 装饰器来定义抽象方法。装饰器是一个以另一个函数为参数并返回一个新函数的函数,用 @ 符号表示。你可以暂时将装饰器理解为给现有函数添加功能的辅助函数。
这里定义的抽象方法不能在这个抽象类的对象上直接调用。你只能在继承了这个抽象类的子类对象上调用这个方法。
class SomeAbstractClass(ABC):
@abstractmethod
def some_abstract_method(self):
pass

一个抽象类可以包含一个或多个抽象方法。然而,任何以抽象类为父类的子类,除非它重写(实现)了父类中的所有抽象方法,否则它自身也无法被实例化。

实战演练:员工捐款示例 💻
理解了理论之后,让我们通过一个实际场景来编写代码。假设一个雇主想为慈善事业向员工募集捐款。

以下是实现步骤:
首先,导入必要的模块。

from abc import ABC, abstractmethod

然后,创建员工抽象类 Employee,并使用抽象方法装饰器定义一个名为 donate 的方法。注意,这里只声明方法,不提供具体实现。

class Employee(ABC):
@abstractmethod
def donate(self):
pass

接着,创建一个继承自 Employee 抽象类的具体类 Donation。这个类必须重写 donate 抽象方法。

class Donation(Employee):
def donate(self):
a = input("How much would you like to donate: ")
return int(a)

现在,我们可以创建员工实例并调用方法了。同时,创建一个列表来存储捐款金额。
john = Donation()
peter = Donation()


amounts = []
amounts.append(john.donate())
amounts.append(peter.donate())
最后,打印出两位员工的捐款总额。


print(f"Total donations: {sum(amounts)}")

总结 📚
本节课中我们一起学习了抽象类和方法的核心概念。我们了解到抽象类是一种不能被直接实例化的类,它通过定义抽象方法来强制其子类实现特定的功能,从而保证了代码的接口一致性和可维护性。我们还掌握了在Python中如何使用 ABC 模块和 @abstractmethod 装饰器来定义抽象类和方法,并通过一个员工捐款的实例演示了其具体应用。掌握抽象类将帮助你设计出结构更清晰、更健壮的面向对象程序。
Python 47:方法解析顺序 🧬

在本节课中,我们将要学习Python中一个重要的概念——方法解析顺序。当类之间的继承关系变得复杂时,MRO提供了一套规则来确定方法或属性的查找路径。我们将了解MRO的基本规则、代码线性化的概念,并学习如何在Python中使用相关函数。
继承的复杂性
到目前为止,你探索的类关系相对简单直接。但当情况变得复杂时,你将如何知道哪个类继承了哪个类?

幸运的是,方法解析顺序提供了一些规则来帮助我们理清头绪。通过本视频的学习,你将能够解释方法解析顺序的基本规则及其如何应用于继承类,理解多重继承背景下的代码线性化概念,并在Python中运用方法解析顺序函数。
Python中的继承类型
你可能已经遇到过一些单继承的例子,即一个子类只从一个父类继承。但了解Python有多种继承类型非常重要。

继承的分类类型基于父类和子类的数量以及层次结构。除了简单继承,广义上有四种继承类型。


以下是主要的继承类型:

- 简单继承:这是你已经处理过的类型,一个子类继承自一个父类。
- 多重继承:涉及一个子类从多个父类继承。
- 多级继承:继承在多个层级上发生。
- 层次继承:涉及多个子类从一个共同的父类继承。

最后,可以说还有第五种类型,称为混合继承,它混合了其他类型的特性。

正如这些继承类型所示,随着项目中类的数量增长且相互依赖性增强,继承关系会变得越来越复杂。
什么是方法解析顺序
那么开发者如何解决这个问题呢?答案是使用方法解析顺序。

MRO决定了在类的层次结构中搜索给定方法或属性以进行解析(或者说,确定其归属)时所遵循的顺序。这个解析顺序被称为类的线性化,而MRO定义了它所遵循的规则。

在想象这些Python类的继承树状结构时,Python中的默认顺序是自底向上和从左到右。

MRO规则示例
让我们以最简单的单继承为例。对象首先在它自己的类中搜索,然后在它的超类中搜索。


那么在一个类Z继承自两个类的例子中呢?假设Z继承自类X和Y。在这种情况下,MRO将是Z、Y,然后是X。换句话说,MRO的查找路径是自底向上,然后从左到右。
但是当层次结构中添加更多层级时,情况会变得复杂得多,因此开发者依赖算法来构建MRO。

MRO算法

旧式类使用深度优先搜索算法。
从Python 3版本开始,Python转向了依赖C3线性化算法的新式类。
C3线性化算法的实现很复杂,超出了本课的范围,但现在可以概述它遵循的几个规则。

该算法遵循单调性,广义上意味着继承的属性不能跳过直接的父类。
它还遵循类的继承图,并且只有在访问了本地类的方法之后才会访问超类的方法。当你将来探索更复杂的类关系时,这个逻辑会更有意义。
在Python中查看MRO

接下来,让我们花点时间探索一些查找类MRO的方法。首先,我将演示mro属性或函数。
让我们看一个由三个类组成的多级继承示例:类A、类B和类C。类A是父类,B和C是各自的子类。换句话说,B继承自A,C继承自B。当我打印对类C调用mro函数的返回结果时,输出确实证实了遵循的顺序。

那么为什么这很重要呢?想象一下,类A有一个值为5的变量num。然后类B也有一个值为9的num变量。这里的mro函数可以快速告诉你,类C将从类B继承值9。
最后,让我们再检查一个函数,即help函数。如果我使用之前的代码,并将打印语句中的mro函数替换为help函数,它会提供一个更详细的输出,顶部包含MRO信息。

它还包含有关代码内部使用的数据描述符和类型的信息。

总结
本节课中,我们一起学习了方法解析顺序的简要介绍,以及它如何在不同场景下影响继承。这些都是非常广泛的主题,但希望它能帮助你理解Python中可能存在的代码复杂性。
Python 48:模块小结 编程范式
在本节课中,我们将对“编程范式”这一模块进行回顾与总结。我们将梳理已学习的核心概念,并明确你应掌握的关键技能。

模块回顾
上一节我们介绍了面向对象编程的核心概念,本节中我们来对整个模块进行总结。
本模块探讨了三种主要的编程范式:过程式编程、函数式编程和面向对象编程。
我们首先指出,过程式编程被认为是最简单、最基础的编程范式,是迈向面向对象编程的基石,也是新开发者的首选入门方式。


接下来,你探索了函数式编程。其本质是一种通过创建函数来编写清晰、一致且可维护代码的编程范式。


最后,你学习了面向对象编程。它围绕着创建对象展开,这些对象同时包含数据和方法。
现在,你应该对这些概念有了清晰的理解。是时候回顾你学到的关键课程和掌握的技能了。
关键知识点总结
基于以上内容,我们来总结你在本模块中学到的要点。
你现在应该能够:
- 描述过程式编程的概念。
- 描述算法是什么,以及如何用它来解决问题。
- 识别如何计算算法复杂度。
- 认识到算法复杂度如何帮助提升性能。


你还应该能够:
- 描述 大O表示法。
- 解释什么是函数式编程。
- 解释纯函数在函数式编程中的运用。
- 解释递归及其如何用于解决问题。
然而,你的学习并未止步于此。因此,你还应该能够:
- 在Python中使用不同的方法反转字符串。
- 解释
map和filter函数的区别。 - 解释面向对象编程及其构建的四个核心概念(封装、抽象、继承、多态)。
- 描述Python中类与实例之间的关系。


最后,在学习了本模块剩余的关键点后,你现在应该能够:
- 创建类。
- 实例化类。
- 访问类的变量和方法。
- 通过使用实例变量和方法来改变对象的状态。


课程总结
本节课中,我们一起学习了Python中不同编程范式的全面介绍。这些是至关重要的知识,为你未来编写更优秀的程序代码做好了准备。
Python 49:Python中的模块是什么
概述
在本节课中,我们将要学习Python中的模块。模块是Python语言的重要组成部分,它们为代码添加功能,避免重复劳动,并提升开发效率。我们将探讨模块的定义、价值、优势、类型以及如何导入和使用它们。
模块是什么?🚗
汽车是我们生活的重要组成部分,它让出行变得更加便捷。但是,如果你需要汽车具备更多功能,例如在雪地中行驶或运输大件物品,你可以通过添加冬季轮胎或挂接拖车来改装它。
类似地,Python是一种强大的语言,允许开发者构建出色的应用。通过使用模块,Python可以获得更多功能。模块就像是制作馅饼的说明书:与其自己摸索每一步,不如直接遵循说明。模块以相同的方式工作,它们是向代码添加功能的构建块,因此你无需不断重复编写所有内容。
一个Python模块包含语句和定义。例如,一个名为 sample.py 的文件可以是一个名为 sample 的模块,并且可以被导入。Python模块可以同时包含可执行语句和函数。
模块的价值与优势 🧱
在探索如何使用模块之前,理解它们的价值、目的和优势非常重要。
模块源于模块化编程。这意味着代码的功能被分解成部分或代码块。这些部分或代码块具有巨大的优势,即:作用域、可重用性和简洁性。
让我们深入探讨这些优势。
作用域
Python中的一切都是对象,因此你为函数、变量等使用的名称变得很重要。作用域意味着模块创建了一个独立的命名空间。因此,两个不同的模块可以拥有同名函数。导入一个模块会使其成为正在执行的代码全局空间的一部分。
可重用性
可重用性是模块化最重要的优势。当你编写一段代码时,模块帮助你避免编写所有可能需要的功能。代码重复会浪费你的精力,占用更多计算机内存,并且效率低下。
例如,假设你想导入一个数学包,你会自动获得大量功能,如阶乘、最大公约数(GCD)等,这些功能无需定义即可重用。
代码示例:导入数学模块
import math
# 使用模块中的功能,无需自己实现
result = math.factorial(5) # 计算5的阶乘
gcd_value = math.gcd(48, 18) # 计算48和18的最大公约数

简洁性
使用模块带来的一个特性是简洁性。当模块之间相互依赖较少时,有助于实现简洁性。因此,每个模块的构建都着眼于一个简单的目的。模块由其用途定义,例如,你也可以使用正则表达式或 re 模块来管理正则表达式。
简洁性也有助于避免这些模块之间的相互依赖。因此,如果你正在进行数据可视化,导入像 Matplotlib 这样的单个模块就足以可视化你的数据。

Python中的模块类型 📦
Python中存在不同类型的模块。这些模块之间的主要区别在于访问模块的方式。
以下是主要的模块类型:
内置模块
有些模块已经内置在标准的Python库中。当你在Python代码中使用类似 import math 的语句时,解释器首先会尝试查找内置模块。
第三方模块
这些是由Python社区开发并可通过包管理器(如 pip)安装的模块。它们极大地扩展了Python的功能。
自定义模块
这些是你自己创建的 .py 文件,可以在其他项目中导入和使用。
如何导入和执行模块 🔧
现在,我们来看看如何导入和执行模块。首先需要知道的重要一点是,模块在执行期间只导入一次。
例如,如果你导入一个包含 print() 语句的模块,你可以验证它只在你第一次导入模块时执行,即使该模块被多次导入。
由于模块是为了帮助你而构建的,独立模块包含所有函数,但很可能不包含无需调用即可执行的函数。只有当用户执行该模块内的不同函数时,他们才会发现这些函数在代码中的效用。
模块通常在代码开头定义,但你也可以在代码的任何点定义它。由于Python中的代码执行是顺序的,你必须先导入模块,然后才能执行其中的任何函数。
代码示例:模块导入位置
# 模块通常在开头导入
import math
def calculate_circle_area(radius):
# 也可以在函数内部导入(局部作用域)
import math
return math.pi * radius ** 2
area = calculate_circle_area(5)
模块也可以从函数内部执行。这意味着该模块内的代码只有在函数执行后才能使用。

总结
本节课中,我们一起学习了Python中的模块。我们了解了模块就像预制的功能包,能够通过提供独立的作用域、卓越的代码可重用性和结构上的简洁性,来提升开发效率。我们探讨了内置模块、第三方模块和自定义模块等不同类型,并掌握了如何正确地导入和使用它们。记住,合理使用模块是编写高效、可维护Python代码的关键。
Python 50:访问模块 🔧
在本节课中,我们将学习如何在Python中访问不同类型的模块,包括内置模块和用户自定义模块。理解模块的搜索路径对于高效地组织和使用代码至关重要。
模块的概念 🧱
在Python中,你可以访问不同类型的模块,例如内置模块和来自不同位置的用户自定义模块。
你可以将内置模块想象成一座你想建造的房子,这座房子使用了预先建造并打包好的地板、墙壁和屋顶,你只需要组装即可。这意味着你无需费力寻找锤子、砖块、灰泥和瓷砖来建造墙壁和地板,从而节省时间,使你的工作更高效。在Python中访问内置模块和用户自定义模块的工作原理相同,有助于你在编码时节省时间并提高效率。
请记住,任何Python文件都可以是一个模块。
模块的搜索路径 🔍
解释器按照以下顺序搜索模块:
首先,当前目录路径。
其次,内置模块目录。
第三,Python路径(一个包含目录列表的环境变量)。
最后,它会检查与安装相关的默认目录。
上一节我们介绍了模块的基本概念,本节中我们来看看解释器具体如何查找它们。
以下是解释器搜索模块的具体序列:

- 当前目录路径。
- 内置模块目录。
- Python路径(一个包含目录列表的环境变量)。
- 与安装相关的默认目录。
实践:访问内置模块 💻
让我们编写一些代码,学习如何访问一些内置模块。我将首先在Visual Studio Code中创建一个名为my_calendar.py的新文件。
我将使用sys.path函数,并将其返回的值存储在一个名为locations的变量中。最后,我使用print函数打印这些值。现在我尝试运行这段代码。
不幸的是,这无法工作,因为Python不知道sys是什么。为了解决这个问题,我将尝试导入内置的sys模块。我将再次运行代码。
print函数返回了解释器在搜索模块时将查找的所有可能位置,包括当前工作目录。但这看起来不太清晰。我知道我有一个值列表,因此我将运行一个for循环,依次遍历每个位置。
import sys
locations = sys.path
for location in locations:
print(location)
这通过在终端中每个位置单独打印一行,返回了更清晰的结果。
导入与使用模块 📦
现在,在代码开头导入所有必需的模块是良好的实践,但我也可以用不同的方式来做。我将在代码中间导入一个模块。
我将导入另一个名为calendar的内置模块。现在我将使用calendar模块中的几个函数。我将使用一个名为leapdays的函数,它有两个输入参数year1和year2,并会返回一个整数值。因此,我要做的是调用leapdays函数,传入两个年份,并将返回值存储在一个名为leap_days的变量中。然后我将打印这个变量的值。
import calendar
leap_days = calendar.leapdays(2000, 2050)
print(f"Leap days between 2000 and 2050: {leap_days}")
我得到的返回值是13,这意味着在2000年到2050年之间有13个闰日。
现在我将使用另一个函数,这个函数是isleap。它以一个年份作为输入,并返回一个布尔值。它会告诉你给定的年份是否是闰年。让我们尝试2036年,并将返回值存储在另一个名为is_it_leap的变量中。
is_it_leap = calendar.isleap(2036)
print(f"Is 2036 a leap year? {is_it_leap}")
这次我得到的值是True,因为2036年是闰年。
探索模块内部 🕵️
如果你决定多探索一点,可以将鼠标悬停在calendar上(如果你使用MacBook,请按住Command键;如果使用Windows,请按住Control键),然后点击它,这将带你进入calendar模块的文件。
请注意,calendar模块本身也导入了一些其他模块,除此之外,它包含了所有的功能。
我现在在Python 3.9包中找到了calendar模块的位置,这个位置在我之前运行的打印路径循环中列出的终端位置之中。

总结 📝
本节课中我们一起学习了如何从不同位置访问内置模块和用户自定义模块。我鼓励你在代码中开始使用模块,以使你的工作更高效。记住模块化编程的优势:节省时间、提高代码复用性并使项目结构更清晰。
Python 51:导入语句 📦
在本节课中,我们将学习如何使用Python的import语句来访问不同目录下的模块。你将了解模块、包的基本概念,以及如何从Python包索引(PyPI)安装和使用第三方包。
什么是模块?
每一个Python文件(即扩展名为.py的文件)都可以被视为一个模块。你正在编写的代码文件通常被称为主模块。例如,当前目录下的check_imports.py文件就是一个主模块。
你可以导入当前工作目录(即项目作用域)内的任何Python文件。导入时,使用import关键字,后跟文件名(不带.py扩展名)。
import sample
执行上述代码,如果导入成功,终端不会报错。但如果你尝试导入一个非Python文件(例如.txt文件),系统会返回错误。
import sample_text # 这将导致 ModuleNotFoundError

内置模块与标准库
Python自带了一系列标准模块,称为内置模块。这些模块已直接集成在Python解释器中,无需单独安装。例如,json模块就是一个内置模块。
import json

导入后,你就可以直接使用该模块提供的函数了。所有内置模块的列表可以在Python标准库文档中找到。
包与PyPI
包可以被看作是Python模块的集合。为了让Python将一个目录识别为包,该目录下必须包含一个名为__init__.py的特殊文件。

Python拥有一个由社区构建的庞大包生态系统,这些包托管在Python包索引(PyPI)上。

Pip(或pip3)是Python默认的包安装工具,用于从PyPI安装包。
pip install package_name
例如,如果你已经通过Pip安装了numpy,就可以直接在Python中导入它:
import numpy
如果尝试导入一个未安装的包(例如seaborn),则会收到ModuleNotFoundError错误。此时,你需要先在终端中运行pip install seaborn来安装它。
导入其他目录中的模块
有时,你可能需要导入位于当前工作目录子文件夹中的模块。这需要修改Python的模块搜索路径。
假设你有一个名为workplace的文件夹,里面包含一个trial.py文件,该文件定义了一个列表变量names。
以下是导入该文件的步骤:
- 导入
sys模块,它提供了对Python解释器系统功能的访问。 - 使用
sys.path.insert()方法,将目标目录的路径添加到模块搜索路径的开头。 - 然后,就可以像导入普通模块一样导入目标文件了。
import sys
# 将 'workplace' 文件夹的路径插入到模块搜索路径中
sys.path.insert(0, r'你的/workplace/文件夹/绝对路径')
import trial
# 访问 trial.py 中定义的变量
print(trial.names)
注意:在传递路径字符串时,前面的r表示“原始字符串”,可以避免反斜杠\被误解为转义字符。虽然IDE可能会在import trial处显示警告(因为它不知道你动态添加的路径),但解释器在执行时能够正确识别。
总结
本节课我们一起学习了Python中import语句的核心用法。
我们了解到,每个.py文件都是一个模块,而包是模块的集合。Python的内置模块无需安装即可使用,而丰富的第三方包可以通过Pip从PyPI安装。

对于导入其他目录的模块,我们学习了通过修改sys.path来实现的方法,虽然这有时会比较具体和复杂。对于初学者,更重要的实践是将所需文件放在当前工作目录下进行导入。但了解从其他目录导入模块作为一种可选方案,也是很有益的。


掌握模块和包的导入,是组织和管理更大型Python项目代码的基础。
Python 52:编写导入语句

概述
在本节课中,我们将学习如何在Python中使用import语句导入模块。我们将探讨多种导入方法,包括导入整个模块、导入特定函数、使用别名以及导入模块中的所有内容。掌握这些技巧能帮助你更高效地组织代码,并利用Python强大的模块化特性。
导入整个模块
首先,我们来看如何导入一个完整的模块。我已经创建了一个名为import_pi.py的文件。现在,我将通过输入import math来导入Python内置的math模块。
为了确保代码正常运行,我使用一个print语句。输入print("正在导入math模块")。运行代码后,print语句成功执行。
你遇到的大多数模块,尤其是内置模块,通常不会有任何print语句,它们只会被解释器静默加载。
现在我已经导入了math模块,接下来我想使用其中的一个函数。我们选择平方根函数sqrt。为此,我输入math.sqrt。
当我输入math.后,会出现一个下拉菜单,列出所有可用的函数,你可以从中选择sqrt。我将数字9作为参数传递给math.sqrt函数,将结果赋值给一个名为root的变量,然后打印它。
终端输出了数字3,即9的平方根,这是正确答案。
导入特定函数
与上面导入整个math模块不同,有一种更好的方法:直接将所需函数导入到项目的作用域中。这样可以避免因导入整个模块而使解释器过载。
为此,我输入from math import sqrt。运行后,它显示了一个错误。
现在,我从变量声明中移除math.前缀,再次运行代码。这次,它成功运行了。
使用别名
接下来,我们讨论一种称为“别名”的导入方式,这是导入不同模块的绝佳方法。这里,我为math模块分配一个别名m。我通过输入import math as m来实现。
然后,我输入cosine = m.cos。接着,我从函数列表中选择cos,并在括号内添加数字0。在下一行,我将打印cosine,然后运行代码。
结果是0的余弦值,即1。这之所以可行,是因为我使用了别名m。如果我尝试写math.cos,它将无法工作,因为现在math模块被识别为m。
让我从屏幕上移除这段代码,并在继续之前清空终端。
别名也可以用于导入的函数。例如,我可以输入from math import factorial as f来为factorial函数设置别名。
现在,我将f(10)赋值给一个名为factorial_10的变量。我将打印这个变量,看看它是否有效。运行代码后,我们看到它运行良好。
以这种方式使用别名可以减少每次输入factorial的工作量。
导入多个函数
移除别名后,我可以从一个给定的模块中导入任意多个函数。我将导入log和sqrt。
我使用log函数创建一个变量来求log10(50)的值。我通过输入x = log(10, 50)来实现。同样,我在下一行打印这个变量。点击运行后,我将查看它是否有效。
再次,它运行良好。
导入模块中的所有内容
那么,如果我想导入给定模块中的所有函数呢?我可以移除之前添加的函数,并用一个星号*替换它们。
这基本上等同于从math模块中导入所有内容。当我再次运行代码时,让我们看看它是否有效。它确实有效。
然而,在某些情况下,使用星号*并不是最佳做法。例如,这是一个小文件,我知道log10函数存在于math模块中。但是,当你处理大型代码库时,可能很难追踪log10函数来自哪里。此外,当你导入其他模块时,可能会造成混淆。
导入变量和类
导入包与在Python中导入模块非常相似。就像你可以导入函数一样,你也可以从给定模块中导入变量和类。
现在,我将星号*替换为一个名为some_variable的变量,它可能存在于给定的模块中。让我再次尝试运行代码。
由于math模块没有这样的变量,当我打印它时会抛出错误。解释器无法从math中导入some_variable。
总结

在本视频中,我们探索了在Python中使用import、from、*和as等关键字导入模块的不同方法。这使你能够在面向对象编程中充分利用Python的模块化结构。
Python 53:命名空间和作用域 🐍
在本节课中,我们将要学习Python中两个紧密相关的核心概念:命名空间和作用域。理解它们对于编写结构清晰、易于维护的代码至关重要。
命名空间与作用域概述
现在,你应该对模块的工作原理相当熟悉了。让我们来看看Python中另一个相关的概念:命名空间和作用域。
Python官方文档将命名空间定义为从名称到对象的映射。而作用域是Python程序中可以直接访问该命名空间的文本区域。此时,具有键值对的字典是映射名称和对象的理想数据结构。
你也已经学习了每个Python文件都可以是一个模块。你可以将同一个模块视为Python创建模块对象的地方。一个模块对象包含了在其中定义的不同属性的名称。通过这种方式,模块就是一种命名空间。
理解作用域类型
命名空间和作用域可能很快变得非常令人困惑,因此尽可能多地练习作用域以确保代码质量的标准非常重要。
Python中可以定义四种主要的作用域类型:
- 局部作用域
- 闭包作用域
- 全局作用域
- 内置作用域
尝试确定某个变量属于哪个作用域的做法被称为作用域解析。作用域解析遵循通常所说的LEGB规则。
让我们来逐一探索这些作用域:
- 局部作用域:这是首先搜索变量的地方,位于函数内部。
- 闭包作用域:定义在封闭或嵌套函数内部的作用域。
- 全局作用域:定义在最顶层,或者简单说就是在任何函数之外。
- 内置作用域:这是内置模块中存在的关键字。
简单来说,在函数内部声明的变量是局部的,而在任何函数作用域之外的变量通常是全局的。
作用域解析示例
上一节我们介绍了作用域的类型,本节中我们通过一个例子来看看它们的具体表现。
以下是一个示例,屏幕上的代码输出了相同变量名 Greek 在不同作用域中的情况。
alpha = "global_alpha"
def function_B():
beta = "local_beta"
print(f"Inside B, id(beta): {id(beta)}")
def function_C():
gamma = "nested_gamma"
print(f"Inside C, id(gamma): {id(gamma)}")
function_C()
print(f"After C, id(beta): {id(beta)}")
print(f"Global, id(alpha): {id(alpha)}")
function_B()
print(f"After all, id(alpha): {id(alpha)}")
变量有三种可能的声明位置:在全局级别、在函数B内部、或在从B内部调用的嵌套函数C内部。
id() 函数在打印语句中被使用,它返回对象的身份标识。你可以从输出中观察到以下几点:
- 全局变量
alpha的ID在代码完全执行后保持不变。 - 函数B内部的局部变量
beta的ID在嵌套函数C执行前后保持不变。 gamma的ID仅在嵌套函数的作用域内被分配。- 所有三个变量的ID都不同,即使它们拥有相同的变量名。
变量声明与作用域默认值
Python中的变量在你定义它们时被隐式声明。这意味着,与其他编程语言不同,Python中没有特殊的声明来指定变量的数据类型。
这也意味着,除非另有说明,否则给定的变量在声明时是局部的,而非全局的。😡
这与大多数其他编程语言形成对比,在那些语言中变量默认是全局的。因此,当变量在全局空间声明时,它对该空间来说也是局部的。
这可以通过一个简单的例子来理解:
country = "GlobalCountry"
def my_function():
country = "LocalCountry"
print("Locals:", locals())
print("Globals in function:", globals().get('country'))
print("Globals in main:", globals().get('country'))
my_function()
如果你查看这两个字典的内容,可以看到键 country 的值在两种情况下是不同的。你还使用了两个特殊的内置函数 locals() 和 globals() 来列出这两个作用域内字典的内容。
在这个例子中,你可以看到声明的全局变量保持不变。
全局变量的使用与注意事项
虽然全局变量是可以接受的,但由于多种原因,不鼓励使用它们。
当你处理生产代码时,项目结构可能变得复杂,使用全局变量可能难以诊断问题,从而导致所谓的“意大利面条式代码”。其他范式,如访问修饰符、并发和内存分配,使用局部变量能更好地处理。
当你刚开始使用Python时,将良好实践集成到你的代码中总是一个好主意。
有两个关键字可以用来改变变量的作用域:global 和 nonlocal。
global关键字帮助我们从函数内部访问全局变量。nonlocal是Python中定义的一种特殊作用域类型,仅用于嵌套函数中,条件是它已在封闭函数中提前定义。

实践:理解作用域解析
现在,你可以编写一段代码,以更好地帮助你理解属性的作用域概念。
你已经创建了一个名为 Animfarm.py 的文件。你将在其中定义一个名为 D 的函数,并在其中创建另一个嵌套函数 E。
以下是完整的代码:
animal = "camel" # 全局变量
def function_D():
animal = "elephant" # 闭包作用域变量 (对E而言是非局部的)
def function_E():
nonlocal animal # 声明使用外层(非全局)的animal变量
animal = "giraffe"
print("Inside nested function E, animal is:", animal)
print("Before calling E, animal is:", animal)
function_E()
print("After calling E, animal is:", animal)
print("Global animal is:", animal)
function_D()
print("Global animal after D is:", animal)
让我们来编写其余部分的代码。你可以从定义几个都叫 animal 的变量开始,第一个在函数D内部,第二个在函数E内部。请注意,你必须首先在E函数内部将变量声明为 nonlocal。
你现在将添加更多的打印语句以在查看输出时进行澄清。最后,你在这里调用了E函数,并且你可以在D函数之外再添加一个变量 animal。这将是一个全局变量。你可以添加对D函数的调用和一个针对全局变量的打印语句。
保存此文件并运行代码。
执行流程如下:
- 首先,全局
animal变量被赋值为"camel"。 - 然后调用
function_D,一旦进入其中,将"elephant"赋给局部(对E而言是非局部)的animal。 - 接着声明内部函数E,并通过打印“调用E函数前”的
animal值来继续,此时animal的值是局部值"elephant"。 - 一旦进入内部函数E,你使用
nonlocal关键字声明你将使用animal变量,并将其值改为"giraffe"。在这里,你可以看到打印语句将输出“在嵌套函数E内部,animal是:giraffe”。 - 这个值在你退出内部函数后仍然保持一致。所以当你打印“调用E函数后”时,值仍然是
"giraffe"。 - 函数完全执行后,退出到全局空间,可以看到全局
animal的值将是开始时赋值的"camel"。
因此,你可以看到在内部所做的更改不会影响全局变量的值。
最后一点:nonlocal 的必要条件
让我们看最后一点:如果你将函数D中的局部 animal 变量声明注释掉,这将抛出一个错误。
def function_D():
# animal = "elephant" # 将此行注释掉
def function_E():
nonlocal animal # 错误!
animal = "giraffe"
你可以看到错误信息指出,在D函数内部没有所需的非局部 animal 绑定存在。这说明了 nonlocal 关键字要求变量必须在直接外层作用域(即闭包作用域)中已定义。
总结

本节课中,我们一起学习了Python中命名空间(名称到对象的映射)和作用域(可访问命名空间的代码区域)的核心概念。我们深入探讨了四种作用域(LEGB:局部、闭包、全局、内置)及其解析规则,并通过实例观察了变量在不同作用域中的行为。我们了解了Python变量隐式声明、默认为局部作用域的特点,以及使用 global 和 nonlocal 关键字来修改作用域的方法。最后,我们强调了谨慎使用全局变量,并实践了如何通过代码来理解和验证作用域的工作原理,为编写结构清晰的代码打下了基础。
Python 54:reload函数 🔄
概述
在本节课中,我们将要学习Python中的reload函数。这个函数与import语句配合使用,允许我们在程序运行时重新加载已导入的模块,从而实现动态更新代码的效果,而无需重启整个程序。
reload函数基础
上一节我们介绍了import语句的基本用法,本节中我们来看看如何动态地重新加载模块。
reload函数用于重新加载一个已经被成功导入到Python程序中的模块。它的唯一前提条件是传递给它的参数必须是一个已经成功导入的模块对象。

之前你了解到,import语句默认只会被Python解释器加载一次。但reload函数允许你多次导入并重新加载同一个模块。下面我将演示这一点。
首先,我创建一个新文件 sample.py。

我在其中添加一个简单的打印语句:print("Hello World")。
请记住,Python中的任何文件都可以作为一个模块使用。
我将在另一个新文件 using_reloads.py 中使用这个文件。
现在,我导入 sample.py 模块。我可以多次添加import语句,但解释器只会加载它一次。如果它被重新加载了,我们应该会看到多次“Hello World”输出。然而,我可以通过reload函数来改变这一点。
让我移除这段代码,并导入包含reload函数的importlib模块。
然后,我将模块名作为参数传递给这个函数。请注意,sample模块已经被导入了不止一次,并且我可以想重复多少次就重复多少次。
动态监控目录变化
为了更好地演示reload函数如何被使用,我创建另一个名为 filechanges.py 的文件。这个文件将列出特定目录的内容。
在接下来的代码中,我将更新目录的内容,并能够通过一个我将导入的文件来监控这些变化。由于解释器只加载文件一次,reload函数将允许我们重新加载那个导入,从而有效地在每次运行时更新变化,而无需停止正在执行的代码。
我首先导入内置的os模块,并使用其中的一个函数os.listdir()。
接下来,我通过右键点击顶部的文件标签并选择“复制路径”来获取当前路径,并将其作为参数传递。
我将这个路径作为参数粘贴给listdir函数,并在路径前添加一个r,因为我寻找的是一个目录而不是文件。我从这里移除filechanges.py。
我将listdir函数的输出保存到一个名为contents的变量中。在下一行,我为contents变量添加一个print函数。
在运行程序之前,我将清除终端以使内容清晰。返回值应该列出给定目录中存在的文件。
你会注意到,打印出来后,它确实列出了此目录中存在的所有文件。
实现动态重载
我现在回到 using_reloads.py 文件并清空它。然后,我再次导入importlib模块。之后,我导入filechanges并创建一个名为check_changes的函数。
作为良好实践,我添加一个try块,并使用reload函数将filechanges作为参数传递。
让我回到 filechanges.py 文件,创建一个函数来打印contents变量。
现在这部分完成了,但为了清晰起见,我将添加另一个打印语句。
我保存这个文件,然后回到 using_reloads.py。
我调用刚刚在filechanges模块中创建的这个函数。为了让try块工作,我添加except并暂时使用pass。
之后,我使用一个for循环来执行代码。因为我想执行不止一次,所以我使用range函数并调用我刚写的函数。
为了对程序有一些控制,我在这里添加一个input语句。
现在程序将执行五次,每次它都会加载filechanges模块并列出目录的内容。
演示动态更新
为了让演示更有趣,我在目录内创建几个文本文件。
现在我返回到 using_reloads.py 文件来运行这段代码。请注意,当前目录的内容被列在这里。
但现在我将删除名为text3.txt的文本文件。当我再次按回车键执行代码时,你会注意到那个特定的文本文件已经被移除了。
现在,在不做任何其他更改的情况下,我执行剩下的代码。如果我同时更改filechanges.py的内容,例如更改文件名前的打印语句,我可以在再次按下回车键后看到代码的更改被反映出来。

总结

本节课中我们一起学习了reload函数。正如我所演示的,reload函数可以借助import语句在你的代码中实现动态更改。它允许你在程序运行时重新加载模块,这对于开发需要热更新或动态监控外部资源(如文件系统)的应用程序非常有用。
核心操作可以总结为以下代码:
import importlib
import some_module
# ... 之后当需要重新加载时 ...
importlib.reload(some_module)


Python 55:Python流行包介绍 🐍
在本节课中,我们将学习Python中“包”的概念,并了解一些在数据科学、人工智能和Web开发等领域最流行和实用的包。理解这些工具是成为一名高效Python开发者的关键一步。
什么是Python包? 📦
包是Python中服务于特定目的的模块集合。你可以将其想象成一个传统的图书馆,每个包就是一本特定的书或杂志,而这个“图书馆”每天都在变得更大。
在编程中,一个包就是一个目录或文件夹,而模块则是其中的文件或文档。你使用import语句导入包,方式与导入模块相同。但需要注意的是,除非正确定义,否则导入语句本身没有意义。
如何导入和使用包?
导入包的方式与模块类似,但有时需要更具体的格式。例如,假设你想导入一个名为F的包,仅使用import F可能无法达到目的。通常需要指定从包中导入哪个具体的模块,格式如下:
from F import A
其中,F是包名,A是包含你所需函数的模块名。探索包的目录结构或参考在线代码示例可以节省大量时间。
Python包管理器与仓库
要使用Python包,了解包管理工具至关重要。Pip是Python默认的包管理器。而Python Package Index (PyPI) 是官方的软件仓库,你可以在这里查找和发布开源包。
Python的主要应用领域与包分类
Python拥有庞大的包生态系统。对于初学者开发者来说,这可能令人望而生畏。因此,了解Python当今最主要的应用领域很有帮助。这些领域包括:
- 数据科学
- 人工智能与机器学习
- Web框架
- 应用程序开发
- 自动化与硬件接口
基于这些领域,我们可以将包大致分为几类:内置包、数据科学包、机器学习与AI包,以及Web和GUI开发包。接下来,让我们逐一简要探索。
内置包 🧰
内置包是那些无需单独安装,在安装Python后即可立即使用的包。几乎每个项目都会用到它们中的一个或多个,因此值得深入了解。
以下是最受欢迎的一些内置包:
- OS:用于与操作系统交互。
- CSV:用于读写CSV格式文件。
- JSON:用于处理JSON数据。
- Importlib:用于动态导入模块。
- Re:用于正则表达式操作。
- Math:提供数学函数。
- Itertools:用于创建高效迭代器的函数。
数据科学包 📊
在数据科学领域,Python拥有极其强大的工具集。
以下是该领域最核心和流行的包:
- NumPy:提供高性能的多维数组对象及计算工具。
- SciPy:建立在NumPy之上,用于科学计算和技术计算。
- NLTK:自然语言工具包,用于文本处理和分析。
- Pandas:提供高性能、易用的数据结构和数据分析工具。

这些包主要用于数据探索和操作。此外,还有其他一些重要的包:
- OpenCV:用于图像处理和计算机视觉。
- Matplotlib:一个广泛使用的数据可视化库,用于创建静态、交互式和动画图表。

机器学习与人工智能包 🤖
在机器学习(ML)和人工智能(AI)领域,Python同样占据主导地位。
以下是当前最流行的包:
- TensorFlow:由Google开发的开源机器学习框架。
- PyTorch:由Facebook开发,以其动态计算图和易用性在研究中非常流行。
- Keras:一个高级神经网络API,能够运行在TensorFlow、Theano等后端之上。PyTorch和Keras是目前实现深度学习和神经网络最流行的选择。
此外,还有其他一些优秀的包,例如SciPy、Scikit-learn(一个简单高效的数据挖掘和数据分析工具)和Theano。选择使用哪个包取决于项目的规模和范围,以及你对特定包的熟悉程度。
Web开发包 🌐
如今,Python主要用于机器学习、人工智能和Web开发。
在Web开发领域,最流行的包是:
- Flask:一个轻量级的微框架,灵活且易于上手。
- Django:一个功能全面的全栈框架,内置了许多开箱即用的功能。
其他流行的Web开发包还包括CherryPy、Pyramid、Beautiful Soup(用于网页抓取)和Selenium(用于Web自动化测试)。
其他领域的包
除了上述领域,Python在机器人、游戏开发等专业领域也有相应的包。无论你想从事哪个领域,几乎都能找到相关的Python包。虽然可能没有一个包能完美契合你当前的项目,但Python的开源开发者社区正在不懈努力填补这些空白。
对于Python初学者来说,你所需的大部分功能通常都能通过某一个包得到满足。
总结与下一步
本节课中,我们一起学习了Python包的核心概念。我们介绍了什么是包、如何导入包,并分类探讨了内置包以及当今在数据科学、机器学习、人工智能和Web开发中最流行的一些包。

为了继续扩展你对Python包的了解,建议你想一个希望创建的项目,并尝试使用本视频中提到的这些包进行实践。动手实践是掌握它们的最佳途径。
Python 56:数据分析包 📊
在本节课中,我们将要学习数据分析领域中一些最常用的Python库。这些库是数据科学项目的基石,能够高效地处理、分析和可视化数据。
过去十年,数据科学领域经历了指数级增长。随着开发者需要在代码中融入科学计算和数据分析,对数据分析师和数据科学家的需求持续增加。Python已成为数据科学家中最受欢迎的语言之一。其流行的一个主要原因是拥有大量不同的开源软件包。
这些软件包由成千上万的贡献者协作开发,提供了免费可用的资源。许多软件包因其高效性和出色的功能而获得高度评价。


以下是几个核心的数据分析包,排名不分先后:NumPy、SciPy、Matplotlib 和 scikit-learn。

核心数据分析库介绍
上一节我们概述了Python在数据科学中的重要性,本节中我们来看看这些核心库的具体功能和用途。
scikit-learn:机器学习库

作为一个例子,scikit-learn 用于预测性学习,它构建在其他流行包之上。该库主要由各种监督和非监督的机器学习算法组成,用于分类、回归和支持向量机(SVM)。
该库的主要焦点是数据建模,它提供了流行的模型,例如:
- 聚类
- 特征提取与选择
- 验证
- 降维
Pandas:数据分析与处理工具

Pandas 是 “Python Data Analysis” 的缩写,它是一个数据分析和操作工具。它主要用于处理数据集,并提供数据清洗、分析和操作的功能。
使用Pandas,我可以比较不同的列,并找到算术平均值、最大值和最小值。

Pandas中使用的主要数据结构是 Series 和 DataFrame。Series是单维的,可以比作表格中的一列;而DataFrame是多维的,可以高效地存储表格。它们对存储的数据类型是无关的。

Pandas最常见的应用是读取CSV文件和JSON对象,并在Python代码中使用它们以实现更快的数据检索。Pandas以为数据分析带来速度和灵活性而闻名。

Pandas库通常通过以下代码导入:
import pandas as pd

NumPy:数值计算基础库


NumPy 代表 “Numerical Python”,它是一个强大的库,构成了诸如scikit-learn、SciPy和Matplotlib等库的基础。
数据科学家,尤其是在信号处理、图像处理、统计计算和量子计算等科学领域工作时,会使用NumPy的能力。NumPy执行代数领域所需的计算,例如傅里叶变换和矩阵运算。


NumPy中的核心数据结构称为 ndarray 或N维数组,它替代了Python中传统的列表(list)使用,是比列表快得多的解决方案。NumPy中的维度称为轴(axes),轴的数量称为秩(rank)。
通常,NumPy通过以下方式导入:
import numpy as np

Matplotlib:数据可视化库

Matplotlib 是Python中使用的可视化库。它可以用来创建静态、交互式和动画式的可视化。

许多第三方工具,如ggplot和Seaborn,扩展了Matplotlib的功能。这些功能位于 pyplot 子包中。

Matplotlib通过以下方式导入:
import matplotlib.pyplot as plt

一个例子是,使用Matplotlib和NumPy库可以显示一个班级学生的图形化表示或他们分数的分布情况。

总结
本节课中我们一起学习了Python数据分析中最常用的几个核心库。我们了解了scikit-learn用于机器学习建模,Pandas用于高效的数据处理与分析,NumPy作为高性能数值计算的基础,以及Matplotlib用于创建各种数据可视化图表。掌握这些工具是进行数据科学和数据分析项目的重要第一步。
Python 57:机器学习、深度学习与AI核心概念及Python库 🧠


在本节课中,我们将学习人工智能、数据科学和机器学习的基本概念,并了解Python在这些领域中的核心地位及其流行的开源库。


人工智能(AI)的广义目标是让机器像人类一样思考。数据科学主要关注数据的管理与探索,其数据可能包含文本、音频、图像和视频等多种媒体形式。机器学习(ML)是人工智能的一个分支,专注于通过算法从数据中训练模型并获取洞见。



上一节我们介绍了AI、数据科学和ML的基本定义,本节中我们来看看机器学习在哪些具体领域得到了广泛应用。


以下是机器学习被广泛应用的几个主要领域:
- 自然语言处理
- 深度学习
- 情感分析
- 推荐引擎
- 计算机视觉
- 语音识别


如今,随着文本、图像和视频数据量的激增,数据科学,尤其是人工智能,正面临着前所未有的巨大需求。

为了应对这些需求,开发者需要高效的工具。Python是这些领域中最受欢迎的语言之一。

以下是Python在这些领域如此流行的几个关键原因:
- 语法高效且可读性强:代码简洁易懂。
- 跨语言、框架和操作系统的灵活性:易于与其他技术栈集成。
- 庞大且友好的开发者社区:有丰富的学习资源和问题解答支持。
- 无需深入理解底层原理即可构建ML模型:得益于高级库的封装。
- 用户友好的调试与测试工具,以及模块化结构:便于开发和维护。


这些优势共同促进了大量(主要是开源的)库和框架的蓬勃发展。理解“包”、“库”和“框架”这几个术语的区别很重要。一个包是模块的集合。库和框架这两个词常与“包”互换使用。库也可以是为特定目的而设计的包的集合,而框架一词通常用于涉及特定流程或架构的场景。


所有这些都是通过Python的import语句来使用的代码片段。


目前,一些最流行的机器学习库集中在以下几个领域:深度学习与神经网络、计算机视觉与图像识别、自然语言处理、数据可视化以及网络爬虫。需要理解的是,这些是宽泛的分类,大多数相关库的功能并不局限于某个特定领域。

每个项目都是独特的,应具体问题具体分析。在编码时,选择合适的库可以节省宝贵的时间。
本节课中我们一起学习了机器学习库的相关知识。许多领域都使用机器学习,而像深度学习和神经网络这样的领域,依赖于使开发者工作更轻松的开源机器学习库。这些库是包的集合,选择合适的库可以在编码时为你节省时间。因此,在未来项目中,请仔细思考应选择哪个库,以确保它符合你的需求。
数58:Python Web框架 🕸️
在本节课中,我们将要学习什么是Web框架,了解它们的作用和优势,并重点介绍Python中几种主要的Web框架类型及其代表。


Web框架是设计用来为我们提供构建、部署和支持Web应用程序的标准方式的软件应用。它们通过自动化重复性任务来帮助开发者专注于应用逻辑和常规工作,这有助于缩短开发时间。它们还提供了可靠、稳定且易于维护的简易结构和默认模型,从而节省时间和精力。

Web框架主要用高级代码编写,这消除了理解套接字、线程和协议等概念所需的开销。因此,开发者可以更好地将时间花在应用逻辑上,而不是常规任务上。
Python因其良好的文档、丰富的库和包、易于实现、代码可重用性、安全的框架以及易于集成等特性,成为Web开发中一个流行的框架选择。Python中的不同框架高效且易于处理表单处理、路由请求、数据库连接和用户认证等任务。它们还提供调试和测试工具来处理性能分析、测试覆盖率和测试自动化等。




上一节我们介绍了Web框架的基本概念和Python的优势,本节中我们来看看Python Web框架的主要分类。

Python中的Web框架主要有三种类型:全栈框架、微框架和异步框架。现在让我们简要探讨每一种。



以下是三种主要类型的简要说明:

- 全栈框架:被视为一站式解决方案,通常包含所有必需的功能。这可能包括表单生成和验证器、模板布局、HTTP请求处理、用于连接Web服务器的WSGI接口以及数据库连接处理。一些最流行的Python全栈框架是Django、Web2py和Pyramid。
- 微框架:是全栈框架的轻量级版本,不提供那么多模式和功能。它们通常用于较小的Web项目和构建API。Flask、Bottle、Dash和CherryPy是一些流行的微框架。
- 异步框架:顾名思义,异步框架类型用于处理大量并发连接。它们主要使用异步网络库构建,Sanic、AIOHTTP和Tornado是您会遇到的一些名字。


了解了框架的分类后,我们来看看如何选择以及两个最广泛使用的框架。


选择框架可能取决于许多因素。这可以包括可用文档、可扩展性、灵活性和集成性等。虽然这种分类相当宽泛,但重要的是要记住,Python中的每个框架都有其独特的功能集。这可能使某些框架比其他框架更适合特定的项目。
两个最广泛使用的是Flask和Django。现在让我们简要探讨每一个。
以下是两个流行框架的对比:


- Django:是一个鼓励简洁设计和快速开发的高级框架。它是一个功能丰富、库齐全的全栈框架。它安全,并拥有模板系统和第三方支持。它主要因其快速的部署速度而广受欢迎。您无需具备广泛的底层编程知识即可快速构建可扩展的应用程序。
- Flask:是一个微框架,更适合较小的项目。它易于学习,使用简单,并且拥有庞大的扩展库。

本节课中我们一起学习了Web框架的概念及其优势,探讨了Python中全栈、微框架和异步框架三种主要类型,并简要介绍了两个最流行的框架Django和Flask的特点与适用场景。
Python 59:什么是测试 🔍
在本节课中,我们将要学习软件测试的基本概念、重要性及其在软件开发周期中的角色。我们将探讨测试的定义、目的、发展历程以及一些核心的最佳实践。
概述
测试是质量保证的重要组成部分,它能确保我们的软件、应用程序和网站按预期工作。例如,假设你建立了一个网站,每天有几百名访客。某天,你发布的一篇文章突然爆火,导致上百万人同时访问你的网站,网站因此崩溃。另一个场景是在线表单。我们都遇到过填写表单时,系统提示我们输入有误的情况。例如,在信用卡号码栏位中误输入了字母,或者在密码中缺少特殊字符。这类数据验证在银行和金融等领域尤为关键。


什么是软件测试?

上一节我们介绍了测试的重要性,本节中我们来看看测试的具体定义。
软件测试是一个评估和验证各种软件应用程序及产品的过程,主要关注其性能、正确性和完整性。



它有助于识别产品中的缺陷、漏洞、错误以及与预期要求不符之处。

测试的发展历程
在计算机发展的早期,软件开发者严重依赖调试来发现和消除潜在错误。20世纪80年代后,随着软件规模的增长,根据不同的需求,也并行发展出了多种不同的测试类型和产品。

测试最初主要在软件生命周期的后期阶段进行,现在已发展为在早期阶段也进行集成。

测试的效率与理想场景

任何测试类型的效率都取决于其设计的好坏。
理想的测试场景是:编写最少的测试用例,发现最多的缺陷。
测试的重要性与作用
虽然软件测试在任何场景下都很重要,但产品的真正考验在于其投放市场后,由利益相关者和用户进行评判。我们身处互联网时代,存在缺陷的产品,尤其是在早期阶段,会使用户迅速失去兴趣,因为市场上存在许多替代品。
以下是测试发挥重要作用的几个原因:


- 检测问题:帮助发现不良设计、低效流程或功能、可扩展性问题以及安全漏洞。
- 优化与保障:提供A/B测试以找到最佳方案,解决与平台和设备的兼容性问题,为利益相关者提供保证,并为最终用户带来更好的体验。



测试的最佳实践


为了达到最佳效果,测试中必须遵循一些良好的实践:

以下是必须遵循的几项核心实践:
- 测试代码化:允许测试用例的复用。
- 可追溯性:测试必须能够追溯到设定的需求。
- 目的明确:编写的测试必须目的明确、高效且可重复执行。
这些测试技术随后可以根据所使用的测试类型,遵循程序化的方法进行。
测试生命周期与测试用例
测试生命周期通常可以概括为:规划、准备、执行和报告。



实现这一过程的步骤包括:编写脚本和测试用例、编译测试结果、根据结果修正缺陷以及从测试结果中生成报告。




你已经了解了测试用例,它们是为特定目的编写的一套通用操作集合,包含步骤、数据、前置和后置条件。这个目的可以是改进功能、优化流程和发现缺陷。一个编写良好的测试用例最终能提供良好的覆盖率、可复用性、更好的用户体验、降低成本并提高整体满意度。


测试的分类与多样性


随着科技行业的不断发展,已经演化出多种测试类别、类型、工具和产品,它们都是为了最好地满足特定软件的需求而量身定制的。

例如,一个网页的测试需求与一个基于Android的游戏不同。
即使在网页中,社交媒体页面与财务管理页面也会有所不同。

测试可以根据多种不同因素进行分类。例如,根据我们对内部实现的了解程度,可以称之为黑盒测试或白盒测试。实践中还使用许多测试类型,包括兼容性测试、随机测试、可用性测试和回归测试。
目前不必过于担心这些术语,你将在后续课程中了解更多。现在,你只需要知道,在测试产品时,没有一种放之四海而皆准的解决方案。
何时停止测试?
理解何时停止测试也很重要,因为没有应用程序会是100%完美的。否则,开发者可能觉得产品已经测试得很好,但一旦发布给最终用户,就会发现它充满了漏洞和缺陷。



为此可以建立一些度量标准,前提是已有编写良好的测试用例。这些标准包括:通过一定数量的测试周期、测试用例的通过百分比、时间截止日期以及后续测试失败之间的时间间隔。


总结
本节课中我们一起学习了软件测试。在软件开发中,测试可以被视为船只的锚或车辆的保险。你可以希望一切运行顺利,但情况往往并非如此。虽然你可以追求完美,但人为错误总是存在潜在可能。通过系统化的测试,我们能够最大限度地降低风险,确保软件产品的质量和可靠性。
Python 60:测试类型 🧪
在本节课中,我们将要学习软件测试的不同类型。测试是软件开发生命周期中至关重要的组成部分,其发展得益于测试工具和技术的进步。我们将重点介绍测试的四种主要级别或类别:单元测试、集成测试、系统测试和验收测试。
测试的分类方式

有多种方式可以对测试类型进行分类,例如白盒测试与黑盒测试。

白盒测试是指测试人员了解代码、设计和功能。黑盒测试则是在没有这些信息的情况下进行的,测试人员对内部实现一无所知。

除了上述分类,测试还可以分为功能测试、非功能测试和维护测试。接下来我们逐一探讨。
以下是功能测试、非功能测试和维护测试的简要说明:
- 功能测试:基于既定的业务需求,用于确定软件的特性和功能是否符合预期。
- 非功能测试:定义更为复杂,涉及产品的性能、质量等度量指标。
- 维护测试:发生在系统运行环境中,当系统被修正、更改或扩展时进行的测试。
此外,根据软件规模,还有手动测试和自动化测试等方法。
测试的四个主要级别
最被广泛接受的分类是基于软件生命周期进程的测试级别。让我们深入探讨这些测试级别。
四个主要的测试级别是:单元(或组件)测试、集成测试、系统测试和验收测试。这四种测试级别相互关联,并遵循一个顺序流程。现在我们来详细了解一下。
单元测试
在单元或组件测试中,程序通过隔离特定的独立组件来进行测试。这些组件是低级别的,意味着它们更接近实际编写的代码。

由于单元测试规模小,通常使用自动化工具以支持持续集成。因此,你通常在编写代码的同时编写这些测试。例如,如果代码是Python,可以使用pytest等包来编写单元测试。

# 示例:一个简单的Python单元测试(使用pytest风格)
def add(a, b):
return a + b
def test_add():
assert add(2, 3) == 5
assert add(-1, 1) == 0
集成测试
上一节我们介绍了如何测试独立的代码单元,本节中我们来看看如何测试这些单元之间的协作。集成测试将单元测试组合起来,测试数据从一个组件流向另一个组件。
这里的关键词是接口。这意味着你需要测试数据是否在Python代码中从数据库正确获取,以及是否已将其发送到网页。集成测试有不同的方法,如自顶向下、自底向上和混合(三明治)方法。你采用的方法取决于你首先尝试测试哪个代码级别的接口。集成测试建立在单元测试之上,通常由测试人员处理。
系统测试
接下来是系统测试,它测试整个软件系统。你根据设定的需求和期望对其进行测试,以确保其完整性。
这包括对已部署组件各项指标的测量,例如可靠性、性能、安全性和负载均衡。它还会测量在工作环境(如平台和操作系统)中的可操作性。这是由测试团队处理的最重要的阶段,也是最关键的阶段,因为软件在此阶段之后才会交付给利益相关者和最终用户。
验收测试
最后一种测试类型是验收测试。当产品到达这个阶段时,通常被认为已准备好部署。它应该是无缺陷的,并符合既定标准。利益相关者和部分选定的最终用户会参与验收测试。
验收测试通常包括阿尔法测试、贝塔测试和回归测试。一种常见的方法是向用户提供预先编写的使用场景,然后利用测试结果进行改进,并试图发现之前遗漏的缺陷。
总结与关键原则
本节课中,我们一起学习了软件测试的主要类型,包括单元测试、集成测试、系统测试和验收测试。
所有不同的测试级别都是为了在软件的不同阶段进行优化而设计的。测试的关键在于尽早测试、频繁测试。虽然每个测试阶段都很重要,但早期发现问题可以节省时间、精力和金钱。随着代码变得越来越复杂,修复错误也会变得更加困难。

这并不意味着单元测试只发生在开始阶段,而验收测试发生在后期阶段。在许多测试周期中,这些级别是迭代进行的。一个典型的例子是敏捷模型,在该模型中,你迭代地发布产品的不同版本,并每隔几周进行一次验收测试。
重要的是要记住,这些测试方法的目的是建立一个系统化的测试方法,并尽可能早地发现缺陷和改进点。这将最终提升软件的整体性能和用户体验。
Python 61:测试自动化包 🧪
在本节课中,我们将学习测试自动化包的概念及其重要性。随着技术发展,代码自动化已成为重要趋势。我们将了解哪些测试适合自动化,并介绍几个主流的Python测试框架。
概述:自动化测试的重要性
随着技术进步,代码自动化成为主要驱动力。过去,机器替代人力生产商品,节省了时间和精力。在编程领域,自动化测试同样旨在提升效率。

适合自动化的测试通常具有高重复性、高执行量、可预测的环境与数据以及确定性的结果。可以自动化的测试类型包括单元测试、回归测试和集成测试。

理想的测试代码与Python的角色
理想的测试代码应在编程逻辑与测试用例之间架起桥梁。Python以其简洁的编码方式,很好地实现了这一点。此外,Python社区还提供了一些编写精良的测试框架。
自动化测试通常包含三个步骤:
- 准备测试环境。
- 运行测试脚本。
- 分析测试结果。

重要的Python测试框架
接下来,我们来看看一些多年来广受欢迎的Python测试框架。



首先,探索Python内置的测试包 unittest。unittest框架支持测试自动化、独立的测试模块以及将测试聚合到测试集合中。
以下是使用unittest的一个简单示例:

import unittest
def add(a, b):
return a + b
class TestMathFunctions(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
self.assertEqual(add(-1, 1), 0)
if __name__ == '__main__':
unittest.main()


PyTest:简单易用的原生库
第一个要介绍的是 PyTest,这是一个原生Python库,以简单、易用和良好的可扩展性著称。PyTest将在本课程后续部分进行演示。

PyTest能处理多种功能测试类型,如单元测试、集成测试和端到端测试。它支持参数化测试,允许我们使用不同的参数多次执行单元测试。PyTest可以并行运行测试,并生成HTML、XML或纯文本报告。它还能与其他框架(如unittest和Nose2)以及Web框架(如Flask和Django)集成。虽然主要用于测试API,但也广泛应用于UI、数据库连接和其他Web应用程序测试。

易于创建测试和快速修复错误是PyTest成为最受欢迎的自动化测试框架的原因。

Robot Framework:关键字驱动的测试


接下来是 Robot Framework,它主要因其关键字驱动的开发能力而流行。

Robot Framework使用关键字来构建测试用例。这些关键字可以是预定义的,也可以是用户自定义的。
Robot Framework非常通用,可用于验收测试、机器人流程自动化(RPA)和测试驱动开发(TDD)。它适用于许多领域,包括Android、API和大型机系统。


Selenium:专注于Web应用的测试
Selenium 是另一个随着时间推移而广受欢迎的开源测试框架,主要面向Web应用程序。它支持大多数Web浏览器和操作系统。
Selenium通过特定浏览器的Web驱动程序来实现测试功能,如登录、按钮点击和表单填写。它允许测试人员选择测试执行的速度,并可以选择运行特定的测试或测试套件。

框架与工具的协同
除了流行的PyTest、Robot和Selenium框架,还有许多其他选择。重要的是要知道,许多测试框架经常与其他工具一起使用,例如插件、小部件、扩展、测试运行器和驱动程序。
这些工具有助于集成被测试的软件组件,并增加功能。有时,在被测试的代码上会使用多个框架。

总结


本节课中,我们一起学习了测试自动化包。
让我们快速回顾一下:自动化测试是软件行业能够快速、平稳发展的重要原因。手动测试能提供专注的注意力,并能以更复杂的方式处理细微差别和复杂问题。

这种测试目前尚无法被自动化测试完全取代,测试场景的完全自动化仍需时日。但所有这些框架的发展,都正朝着这个目标努力。
Python 62:使用pytest编写测试 🧪
在本节课中,我们将学习如何使用 pytest 模块为Python代码编写简单的单元测试。pytest 是Python中最流行的单元测试模块之一,它允许你以最少的努力进行测试,并且代码简洁、文档完善。
创建待测试的函数
首先,我们创建一个名为 add.py 的文件,并在其中定义两个简单的函数。

def add(a, b):
return a + b
def sub(a, b):
return a - b
以上代码定义了两个函数:add 用于计算两个数的和,sub 用于计算两个数的差。
编写测试文件
接下来,我们创建另一个名为 test_addition.py 的文件来编写测试用例。
首先,我们需要导入待测试的模块和 pytest。
import add
import pytest
然后,我们定义测试函数。良好的实践是使用 test_ 作为函数名的前缀。
以下是测试用例的编写步骤:
- 每个测试函数应专注于测试一个特定的功能。
- 在函数内部,我们使用
assert关键字来断言某个条件为真。 assert语句会检查代码中的条件,并期望一个布尔值(True或False)。当返回值为True时,测试通过;为False时,测试失败。
现在,让我们为加法和减法函数编写具体的测试。
def test_add():
assert add.add(4, 5) == 9
def test_sub():
assert add.sub(4, 5) == -1
在 test_add 函数中,我们断言 4 + 5 的结果等于 9。在 test_sub 函数中,我们断言 4 - 5 的结果等于 -1。
运行测试
要运行测试,请在终端中切换到文件所在目录,并执行以下命令:
python -m pytest test_addition.py
如果两个断言都为真,你将看到类似以下的输出,其中的两个点(..)表示两个测试都通过了。
test_addition.py ..
理解测试失败
为了理解测试失败的情况,我们可以故意修改一个断言。例如,将减法测试的预期结果从 -1 改为 -2。
def test_sub():
assert add.sub(4, 5) == -2 # 这会导致测试失败
再次运行 pytest,输出将发生变化:
test_addition.py .F
这里,一个点(.)表示 test_add 通过,一个 F 表示 test_sub 失败。pytest 还会在下方详细显示失败的原因,指出期望值与实际值不匹配。
关于assert语句的更多细节
assert 语句不仅限于使用相等运算符(==)。你可以使用任何返回布尔值的比较,例如小于(<)、大于(>),或者关键字如 in、not in。
一个测试函数中可以包含多个 assert 语句。只有当函数内所有 assert 语句都通过时,该测试才算通过。
例如:
def test_multiple_asserts():
assert add.add(1, 1) == 2
assert add.add(0, 0) == 0
assert add.add(-1, 1) == 0
你也可以编写一个不执行任何断言的测试,直接使用 pass 语句。这样的测试会自动通过,但这通常不是好的实践,因为它没有实际验证任何功能。
def test_pass_example():
pass # 此测试总是通过
运行特定的测试
如果你只想运行测试文件中的某个特定测试函数,可以在命令行中指定函数名。
python -m pytest test_addition.py::test_add

这条命令将只运行 test_addition.py 文件中的 test_add 函数。
总结

本节课中,我们一起学习了使用 pytest 进行单元测试的基础知识。我们了解了如何创建待测试的函数,如何编写以 test_ 开头的测试函数,以及如何使用 assert 语句来验证代码行为。我们还实践了如何运行所有测试、如何解读测试通过或失败的结果,以及如何运行特定的测试函数。掌握这些是确保代码质量的重要一步。
Python 63:测试驱动开发TDD 🧪
在本节课中,我们将要学习测试驱动开发(TDD)的基本概念、标准流程、优势以及它与传统测试的区别。TDD是一种先编写测试用例,再编写功能代码的开发实践,旨在提高代码质量和开发效率。
概述
测试在软件开发生命周期中是一个相对较晚出现的环节,但其重要性正与日俱增。软件开发通常时间紧迫,开发者常常在代码编写完成后才将测试挤入剩余时间。这导致没有足够的时间进行充分测试,可能使软件包含需要长期处理的缺陷。测试驱动开发(TDD)是一种替代性的编程实践,它要求先编写测试,再编写能使测试通过的代码。这与先编写代码再逐步测试应用程序的传统做法不同。

TDD的标准流程 🔄
上一节我们介绍了TDD的基本理念,本节中我们来看看它的具体实施流程。TDD遵循一种迭代方法,从编写测试用例开始。初始工作需要团队进行功能和测试规划,具体步骤略有变化。以下是TDD的标准步骤:
- 编写一个会失败的测试:为一个新功能编写测试,此时由于功能尚未实现,测试预期会失败。
- 编写最少量的代码:编写恰好能使上一步测试通过的代码,不追求完美或完整。
- 运行测试并观察失败:运行测试,确认它如预期般失败(这验证了测试的有效性)。
- 评估错误并重构代码:分析测试失败的原因,并根据需要重构或完善代码。
- 重新运行整个过程:运行测试,确保其通过,然后为下一个功能或改进重复此循环。

这个过程也被称为 “红-绿-重构”循环。“红”代表失败的测试,“绿”代表重构后通过的测试。遵循此循环的核心目的是让测试失败,然后重写代码直到测试通过。当一个功能的所有测试都显示为“绿色”且无需再次运行时,该功能即告完成。
自动化测试工具 🛠️
当自动化成为优先事项时,你可以使用如 pytest 这样的包或库。pytest 只需要编写函数,而 unittest 则需要编写类。这意味着 pytest 具有更简单的优势,因为它需要的工作量更少。

# 使用 pytest 编写一个简单测试示例
def test_addition():
assert 1 + 1 == 2

TDD的优势 ✨
了解了流程和工具后,我们来看看采用TDD能带来哪些好处。
- 全面的测试覆盖:先编写测试并根据测试重构代码,能确保测试充分覆盖代码。
- 明确的设计导向:你可以带着特定的功能和预期结果来编写测试。这种前瞻性需求从一开始就提供了清晰度。
- 更好的组件集成:这种前瞻性在集成不同组件时也发挥作用,你可以根据已有组件来添加新功能和接口。
- 增强的重构信心:在代码上进行循环工作使开发者有信心轻松地进行额外的更改和重构。

总的来说,代码更精简、早期修复缺陷、代码可扩展性以及最终调试的便利性,是TDD越来越被接受的主要原因。
TDD与传统测试的区别 ⚖️

最后,让我们简要探讨一下TDD与传统测试的一些区别。主要区别在于,TDD从一开始就突出了需求和标准,使其目的性更强。
现代开发通常根据软件开发生命周期的不同部分和阶段,结合使用这两种测试形式。测试驱动开发有几种子类型和变体,包括行为驱动开发(BDD)、验收测试驱动开发(ATDD)、规模化测试驱动开发以及开发者测试驱动开发。这些都是软件开发过程中可以使用的选项。
总结

本节课中,我们一起学习了测试驱动开发(TDD)的过程。我们了解了TDD“红-绿-重构”的迭代循环、其相对于传统测试先写测试后写代码的核心差异、以及它所带来的代码质量更高、设计更清晰等优势。掌握TDD有助于构建更健壮、可维护的软件系统。
Python 64:应用测试驱动开发(TDD)🧪
在本节课中,我们将要学习如何应用测试驱动开发(TDD)的方法论。我们将通过一个具体的例子,了解TDD与传统测试的区别,并掌握其核心步骤。
概述
测试驱动开发是一种软件开发方法,其核心思想是在编写实际功能代码之前,先编写测试用例。这与传统的先写代码后写测试的方式相反。TDD遵循“红-绿-重构”的循环,旨在通过测试来驱动设计,并确保代码质量。
传统测试与TDD的区别
上一节我们概述了TDD,本节我们来具体看看它与传统测试的区别。
在传统测试中,流程是先编写代码,然后编写测试用例来确保该代码的完整性。
在测试驱动开发中,方法正好相反。测试用例是你必须开始思考的地方。
TDD的核心步骤🧩
以下是TDD方法所涉及的步骤:
- 编写测试用例:心中带着某个功能目标来编写测试。
- 编写代码:根据测试用例编写代码,确保测试通过。
- 重构代码:如果测试失败,则重构代码。

实践示例:学生注册验证
现在,我们通过一个示例来演示如何设计一个检查学生注册的测试用例,数据存储在数据库中。测试需要检查输入姓名的完整性。
首先,我将演示如何设计测试用例,然后编写一些代码。
为了保持简单明了,我将使用一个包含姓名的Python列表来代替数据库。我需要确保我输入的姓名在列表中。同时,我还想确保数据完整性,这意味着我必须确保姓名以正确的格式输入。
项目文件结构
我创建了两个文件:
- 第一个是
test_find_string.py,这是我的测试文件。 - 第二个是
fine_string.py,这是我的主程序文件。
我已经安装了 pytest 包。因为这是测试驱动开发,所以我将首先编写我的测试函数。
步骤一:编写第一个测试
以下是 test_find_string.py 文件的内容:
import string
import pytest
import fine_string
def test_is_present():
assert fine_string.is_present('Al') == True
我首先导入 string 模块,它将帮助我检查ASCII字符。然后导入 pytest 模块以及 fine_string 模块(我的主文件)。我定义了一个名为 test_is_present 的函数,并添加了一个 assert 语句来检查 is_present 函数是否正常工作,因为我将用它来验证我的数据输入。
与传统编写代码的方法不同,我先编写了 test_find_string.py,然后添加了名为 test_is_present 的测试函数。
步骤二:根据测试编写功能代码
根据测试,我创建了另一个名为 fine_string.py 的文件,我将在其中编写 is_present 函数。
以下是 fine_string.py 文件的内容:
def is_present(person):
list_of_names = ['Al', 'Alice', 'Bob', 'Charlie']
if person in list_of_names:
return True
else:
return False
我定义了一个名为 is_present 的函数,并传递一个名为 person 的参数。然后,我创建了一个写有姓名的列表作为值。之后,我创建了一个简单的 if-else 条件来检查传入的参数是否存在于列表中。
因此,名为 is_present 的函数将检查传入的姓名是否在列表中。
让我测试我的代码。注意,测试通过了,因为姓名“Al”在列表中。
步骤三:扩展测试以增强完整性
但这并不能确保我可能添加的条目的完整性。例如,我可能不希望姓名中包含数字字符。
为了解决这个问题,我编写了另一个名为 test_no_digit 的函数。我将根据新添加的测试来更新主程序 fine_string.py 中的部分代码。
以下是更新后的 test_find_string.py 文件:
import string
import pytest
import fine_string
def test_is_present():
assert fine_string.is_present('Al') == True
def test_no_digit():
assert fine_string.no_digit('N7') == False
步骤四:根据新测试更新功能代码
为此,我创建了一个名为 no_digit 的函数来匹配我的测试。
以下是更新后的 fine_string.py 文件:
def is_present(person):
list_of_names = ['Al', 'Alice', 'Bob', 'Charlie']
if person in list_of_names:
return True
else:
return False
def no_digit(person):
for char in person:
if char in string.digits:
return False
return True
我再次创建了一个简单的 if-else 条件。我运行代码,你会注意到其中一个测试通过了,另一个测试失败了。
所以,姓名“Al”通过了,因为它在姓名列表中。但值“N7”没有通过,因为它包含一个数字字符。
总结

本节课中,我们一起探索了测试驱动开发的方法论。我们了解到,TDD要求我们先从测试用例开始思考,然后编写代码使测试通过,并在测试失败时重构代码。通过学生注册验证的示例,我们实践了TDD的完整循环:编写测试(检查姓名存在性)、编写代码、扩展测试(检查数据格式)、再次更新代码。你可以继续添加更多测试用例并修改代码,使其适合这些测试用例,并重复这个循环,直到没有更多失败的测试。恭喜你掌握了TDD的基本应用!🚀
Python 65:模块小结 🎯
在本节课中,我们将回顾并总结关于Python模块、包、库和工具的核心知识。你将清晰地理解这些概念如何扩展Python的功能,并掌握在实际项目中应用它们的关键技能。
模块回顾 📦
上一节我们介绍了模块的基础,本节中我们来总结模块的核心要点。
模块是Python中用于扩展代码功能的基础构建块。使用模块可以避免重复编写代码。

以下是关于模块你应掌握的关键能力:
- 能够解释Python中模块是什么以及为何使用它们。
- 识别不同类型的模块并说明它们的位置。
- 举例说明如何从不同位置访问内置模块和用户自定义模块。
- 使用
import语句从不同目录访问模块。 - 能够使用
pip从Python包索引(PyPI)创建包。 - 使用
import语句编写模块。 - 解释并使用Python中的
reload()函数。
包与库 📚
现在,我们来看看Python中丰富的包与库集合。
Python拥有一个庞大的包和库生态系统,用于支持各种应用场景。


以下是关于包与库你应掌握的关键能力:
- 能够描述典型的模块使用场景。
- 区分内置Python包和用户自定义Python包。
- 列举一些流行的Python包。
- 列举一些在数据分析和数据科学中常用的Python库。
框架、库与测试 🧪
在模块中,你还学习了关于库、框架和测试的知识。
因此,你还应掌握以下能力:
- 识别在机器学习和人工智能中流行的Python库。
- 解释如何使用Python进行大数据分析。
- 定义Python Web框架。
- 列举不同类型的Web框架。
- 描述测试并解释不同类型的测试。
- 列举测试的四个主要级别或类别。
- 描述Python中的测试包,例如
pytest、Selenium、Robot。 - 探索自动化测试的重要性。
- 能够解释测试驱动开发(TDD)方法。
- 列举测试驱动开发的特点。


总结 ✨
本节课中我们一起学习了Python模块、包、库和工具的入门知识。这些知识使你能够极大地扩展编程代码的能力。通过掌握模块化编程、利用丰富的第三方库以及实施有效的测试策略,你可以更高效、更可靠地构建复杂的软件应用。
Python 66:课程总结与回顾
在本节课中,我们将对Python编程基础课程的核心内容进行简要回顾。我们将梳理从入门到进阶的关键知识点,为接下来的毕业评估做好准备。
概述
本课程介绍了Python开发的基础知识。我们将简要回顾所涵盖的内容。
模块一:Python入门 😡
在第一个模块中,你学习了开发者在现实世界中使用Python的不同方式,并了解了Python存在的理由。你通过运行Visual Studio Code和执行操作系统环境检查来确认你的硬件和软件,识别了任何必需的依赖项。你探索了变量和数据类型,并处理了字符串、类型转换和数据文件。这引导你进入了控制流和条件语句部分,在那里你使用了Python运算符,并在代码中构建了循环和流程控制。
模块二:核心编程技能
上一节我们介绍了Python的基础语法,本节中我们来看看一些核心的编程技能。
你学习了函数和数据结构、作用域,并深入研究了以下几种核心数据结构:

- 列表:有序、可变的元素集合。例如:
my_list = [1, 2, 3] - 元组:有序、不可变的元素集合。例如:
my_tuple = (1, 2, 3) - 集合:无序、不重复的元素集合。例如:
my_set = {1, 2, 3} - 字典:键值对的集合。例如:
my_dict = {"key": "value"}

在编写了所有这些代码之后,是时候检查错误了。你通过研究错误、异常和文件处理,并思考错误处理的方法,完成了模块二的学习。
模块三:编程范式与算法
课程进行到将近一半的模块三时,你全面了解了函数式编程和面向对象编程的范式及其相关的逻辑概念。你还初步认识了算法,以及Python中的类和实例。
以下是本模块涉及的核心概念:
- 函数式编程:强调使用纯函数和不可变数据。
- 面向对象编程:使用类(Class)作为蓝图来创建对象(Object/Instance)。例如:
class Dog:和my_dog = Dog()。 - 算法:解决问题的明确步骤序列。
模块四:提升开发环境
在接近课程尾声的模块四中 😡,你学习了如何通过使用Python中的模块、库和工具来提升你的编码环境。你还了解了不同类型的测试以及如何编写一个好的测试。
恭喜你完成了本课程的回顾!
总结

本节课中我们一起回顾了Python编程课程的四个核心模块:从环境搭建与基础语法入门,到掌握核心数据结构和错误处理,进而学习高级的编程范式与算法概念,最后了解如何利用丰富的模块和库来提升开发效率并进行测试。
现在,是时候在毕业评估中检验你的知识了。你准备好展示你所有的Python技能了吗?
Python 67:恭喜完成Python编程 🎉
在本节课中,我们将对您完成的Python编程课程进行总结,回顾您已掌握的核心技能,并展望后续的学习路径与职业发展机会。
恭喜您完成了编程与Python课程。您付出了辛勤努力,并在课程期间掌握了大量重要技能。现在,您应该已经拥有了扎实的后端Web开发技能基础。这是您未来持续构建和发展的基石。






同时,您也在分级评估中展示了自己的技能组合。
课程核心成果回顾
完成这第一门课程后,您现在应该能够实现以下目标:
以下是您已掌握的核心能力列表:
- 使用Python完成基础编程。
- 区分过程式、函数式和面向对象这三种编程范式。
- 演示如何使用模块、包和库。
- 在测试驱动开发环境中进行工作。
后续学习步骤

那么,接下来的步骤是什么?本课程是后端开发专业证书中的一门。虽然您目前已打下良好基础,但仍有更多知识等待您去学习。

因此,如果您喜欢这门课程并希望探索更多,何不注册学习其他课程呢?在后续的每一门课程中,您都将持续发展自己的技能组合。
无论您是刚刚起步的技术专业人士还是学生,这个项目都将使您掌握后端开发实践的知识,这些知识广泛应用于许多商业领域,例如:
以下是后端开发技能的应用领域:
- Web开发
- 人工智能
- 机器学习
- 数据分析
- 以及许多其他应用






构建您的作品集与认证
您将编写一个Python代码作品集,向潜在雇主展示您的技能。


这向雇主表明您是自我驱动且具有创新精神的。它也能充分说明您作为个人的特质以及持续成长的动力。

完成本证书的所有课程后,您将获得后端开发的Coursera认证。这些认证提供了全球认可且受行业背书的技能掌握证明。

总结
本节课中我们一起学习了课程完成的总结与展望。我们回顾了您通过本课程掌握的Python编程、多种编程范式、模块化开发及测试驱动开发等核心后端技能。我们也探讨了将这些技能应用于Web开发、人工智能、数据分析等广阔领域的可能性,并了解了通过构建作品集和获取专业认证来提升职业竞争力的路径。
再次祝贺您完成本课程。很荣幸能与您一同踏上这段探索之旅。祝您好运,请继续您的学习旅程。
Python 68:课程介绍 📚
在本课程中,我们将学习如何使用Python作为客户端来连接和操作MySQL数据库。我们将从建立基础连接开始,逐步深入到执行CRUD操作、使用高级查询、调用数据库函数与存储过程,最后学习连接池技术以优化数据库访问性能。
模块一:建立Python与MySQL的连接 🔌
欢迎来到数据库工程学的下一门课程。本课程的重点是数据库客户端。
让我们花点时间回顾一下你将在这些模块中掌握的一些新技能。
第一课:Python连接MySQL与包管理
你将开始学习关于MySQL Python连接的知识。
你将学习使用Pip来安装包或软件。
pip install mysql-connector-python
接着,你将学习如何安装一个前端的Python客户端,并将其连接到后端的MySQL数据库。

然后,你将探索如何建立Python和MySQL之间的通信以执行CRUD操作。

第二课:游标对象与数据库操作
一旦建立了连接,你将访问一个游标对象。
cursor = connection.cursor()
访问游标对象后,你将使用Python创建一个MySQL数据库和表。


然后,你将学习如何使用Python提交对MySQL数据库的更改。
connection.commit()
第三课:深入理解游标
在模块一的第三课也是最后一课中,你将探索MySQL数据库中游标的概念。


你将学习游标在Python和MySQL中如何工作。
你还会回顾游标的关键特性,并发现它们是只读的、不可滚动的、不敏感的。
接着,你将学习游标类用于在Python和MySQL数据库之间转换通信。
你还会学习如何识别不同的游标类。
并且回顾交错请求的基础知识。
模块二:使用Python执行CRUD操作与高级查询 🛠️
上一节我们介绍了如何建立连接和使用游标,本节中我们来看看如何执行具体的数据库操作。
第二个模块的重点是使用Python在MySQL数据库中执行创建、读取、更新和删除操作,即CRUD操作。
第一课:创建与读取记录
你将开始学习如何在数据库中创建和读取记录。
你将回顾此过程的步骤,并发现Python如何与数据库通信以执行这些操作。
然后,你将探索如何使用Python执行MySQL更新和删除操作。
并学习如何将更改提交到数据库。
最后,你将通过完成一系列实验练习来结束第一课,在练习中展示你使用Python在MySQL数据库中执行CRUD操作的能力。


第二课:高级查询

在模块二的第二课中,你将回顾使用Python在MySQL数据库中进行高级查询。

以下是这些查询的概述:
首先,涉及使用Python在MySQL数据库中对数据进行过滤和排序。
你将回顾早期课程中MySQL过滤和排序技术的基础知识,并学习如何将这些相同的技术应用于Python。
接下来,你将学习如何执行一系列不同的连接操作,以使用Python从MySQL数据库的不同表中查找数据。

你将有机会通过一系列实验来测试自己使用Python在MySQL数据库中进行高级查询的能力。

模块三:高级数据库客户端技术 ⚙️
模块三侧重于高级数据库客户端。本模块的第一课首先概述如何将MySQL函数与Python结合使用。
第一课:使用MySQL函数
你将首先学习识别MySQL函数的重要性,并回顾MySQL中可用的不同类型函数。

一旦你回顾完MySQL函数的基础知识。
接着,你将学习如何使用Python实现或访问MySQL函数。
你还会探索Python中的datetime函数,并学习如何利用这些函数通过Python更新MySQL数据库。
然后,你将在实验练习中展示使用这些函数的能力。
第二课:使用存储过程
在第三模块的第二课中,你将探索将MySQL存储过程与Python结合使用。
你将回顾存储过程的基础知识,了解它们与函数的区别,以及如何使用Python在MySQL数据库中创建它们。
接着,你将学习如何通过Python使用 callproc方法来访问存储过程。
并且回顾分隔符的使用。
模块四:数据库连接池 🌊
第三个也是最后一个模块侧重于连接池。
理解与实现连接池
你将首先理解数据库连接池的概念。

你将学习数据库连接池如何工作。


并了解如何识别数据库连接池的优势。


然后,你将回顾为数据库创建连接池的步骤,包括实现MySQL连接池模块的过程。



课程总结
在本节课中,我们一起学习了使用Python作为MySQL数据库客户端的完整路径。从建立基础连接、执行CRUD操作、进行高级查询,到使用数据库函数、存储过程,最后掌握了连接池技术以提升应用性能。
你已经到达本课程介绍的结尾。现在,是时候开始你数据库工程之旅的下一章了。祝你好运。
Python 69:1_Meta的数据库工程 🗄️
在本节课中,我们将跟随Meta软件工程师Maxxie Herrera,学习数据库设计中的核心考量、常见挑战以及工程师的职责。课程将重点阐述如何构建可靠、安全且可扩展的数据库系统。

在我的职业生涯中,曾遇到过这样的情况:两个系统相互依赖,我必须同时发布它们。唯一的解决方案是在夜间流量最低时发布代码,并希望在我们一个系统更新而另一个系统宕机的五分钟内,只有少数用户会遇到问题。有时,这是唯一能做的事情。

大家好,我是Maxxie Herrera,我使用They/Them代词,是Meta门洛帕克办公室的一名软件工程师。我从事捐赠产品相关的工作,确保我们能够追踪谁向哪个筹款活动、哪个慈善机构进行了捐赠。这一点至关重要,我们不能出错。

我们希望确保存储正确的数据,并将正确的数据显示给正确的用户。这意味着我们需要保证数据有效性,确保只获取特定用户应该看到的数据,并保存正确的数据。这些是设计可靠数据库时非常重要的概念。你需要确保数据关系合理,并且不会访问任何特定用户不应看到的数据。
数据库及其设计的完整性与质量,是确保数据受到保护、数据以安全方式存储、用户能够信任其数据未被滥用的首要和关键步骤。这要求我们拥有一个精心设计的数据库,需要周全地考虑数据之间可能存在的各种关系,并为未来的变化制定计划。
我设计数据库时通常遵循的流程是:首先构思产品运行所需的核心数据模型。我以此为起点,因为从产品角度出发,最容易概念化我们将如何访问所需的数据。在初步数据模型建立之后,我开始深入研究所需的特定隐私和验证细节。例如,某些数据是否需要加密?某些数据是否应仅允许特定服务器访问?这些都是我们必须提出的不同问题。然后,根据存储的数据类型(可能是信用卡信息或用户信息),你还需要在数据库和数据库设计中集成更多的检查机制来适应这些需求。


在Meta,设计良好数据库的核心考量首先是尊重用户隐私和用户安全。用户应该知道他们的数据在哪里、有权访问它们,并且应该知道这些数据不会被用于他们不认可的产品中。
我们需要确保的另一件事是可扩展性。如果你的数据模型构思得再好,却无法与Meta产品每天面对的数十亿用户规模一同扩展,那也是无济于事的。
我认为,处理数据库时最常见的挑战之一,并非最初构建数据库的时候,因为那时你已经在模型中构思好了关系。真正的挑战在于,当有新需求出现并改变原有关系时。首先要做的是认真思考未来如何更改你的数据库,它如何不仅在用户数量上扩展,还要适应不同类型的产品。
另一个非常重要的考量是如何修改现有数据库。这将是一项极具挑战性的任务,并且数据库相关的大部分工作都围绕于此。我们有一个旧的数据模型,它已不满足当前需求。我们需要克服这个问题,这需要你进行大量的思考和规划,例如如何迁移数据。这些都是需要时间来解决的重大任务。但正是通过这些实践,你才能更好地管理数据库,并从一开始就构建出更好的数据模型。
作为一名数据库工程师,你将接触到大量数据,必须时刻牢记这对于用户信任或任何将数据托付给你的人的信任是多么重要。即使你认为数据微不足道,人们也对你寄予了厚望,确保你负责任地处理数据。我希望你能认识到,数据库设计和数据库工程对于整体产品体验至关重要,并且是构建用户对你产品信任的基石。


本节课中,我们一起学习了数据库设计的核心原则:确保数据有效性和完整性是基础。设计流程应从核心数据模型出发,再深入考虑隐私与安全细节。成功的数据库必须优先保障用户隐私与安全,并具备强大的可扩展性以应对增长。此外,我们探讨了修改现有数据库和进行数据迁移的挑战,这是数据库工程师工作的关键部分。最终,我们认识到,负责任的数据库工程是赢得用户信任、构建可靠产品的核心。
Python 70:MySQL Python连接 🔗
在本节课中,我们将要学习如何建立Python应用程序与MySQL数据库之间的连接。你将了解连接的基本原理、核心组件以及一个典型的数据查询流程是如何工作的。
连接的工作原理
许多日常使用的网络应用程序都依赖MySQL数据库来发送和存储数据,而这些应用程序中有许多是用Python开发的。数据库工程师可以使用MySQL Python连接,将基于Python的应用程序中的数据发送并存储到MySQL数据库中。
上一节我们介绍了连接的重要性,本节中我们来看看连接是如何具体工作的。
连接是通过一个称为应用程序编程接口(API)的软件组件建立的。API也常被称为驱动程序或客户端。API是一组编写的程序或软件,它充当了前端Python应用程序和后端MySQL数据库之间的桥梁。
可以使用不同的API来创建这种连接,例如:
- SQLAlchemy
- MySQLclient
- MySQL Connector/Python


在本课程中,我们将重点介绍最常用的API:MySQL Connector/Python。





连接流程详解

理解MySQL数据库与Python之间连接的一个有效方式是可视化。想象一个示意图:一边是Python应用程序,另一边是MySQL数据库,而连接这两者的中间元素就是MySQL Connector/Python API。
在一个典型的交互中,流程如下:
- 前端Python应用程序向连接器API发送一个连接请求。这个请求是Python应用程序在请求访问数据库并使用Python检索信息的权限。
- API将这个请求转发给后端的MySQL数据库。
- 数据库接受连接,并通过API向Python应用程序发回一条消息,确认连接已建立。换句话说,MySQL通过API授予Python应用程序访问数据库的权限。
连接建立后,你可以从连接器类实例化一个游标(cursor)实例。当创建了游标对象后,你就可以使用Python在MySQL数据库中执行SQL查询了。

实战示例:Little Lemon餐厅




让我们以Little Lemon餐厅的数据库为例。Little Lemon需要通过他们的Python应用程序查询客人晚餐的到达时间。



客人的预订日期和时间数据存储在后端数据库中。因此,Python应用程序使用游标对象的execute模块来执行客户的查询需求。
以下是执行查询的核心代码步骤:
# Python 1. 建立数据库连接
connection = mysql.connector.connect(host='localhost', database='little_lemon', user='user', password='password')




# Python 2. 创建游标对象
cursor = connection.cursor()
# Python 3. 使用游标执行SQL查询
cursor.execute("SELECT booking_time FROM bookings WHERE guest_name = 'John Doe'")

# Python 4. 获取查询结果
records = cursor.fetchall()

查询结果会通过游标对象以元组的形式返回,显示每位客人的预订时间槽。


请求完成后,可以关闭游标对象和数据库连接。
总结


本节课中我们一起学习了Python应用程序与MySQL数据库之间连接的工作原理。我们了解到连接是通过MySQL Connector/Python这样的API建立的,它充当了应用程序和数据库之间的桥梁。连接建立后,通过创建游标对象,我们可以使用Python执行SQL查询并获取结果。掌握这一连接机制是进行后续数据库操作的基础。
Python 71:安装与设置
在本节课中,我们将学习如何为数据库工程任务安装和配置Python环境,并建立Python与MySQL数据库之间的连接。我们将从下载Python开始,逐步设置开发环境,并安装必要的库来实现数据库交互。

下载与安装Python
首先,你需要从Python官方网站下载最新版本的Python。请遵循网站上的安装说明进行操作。
安装完成后,你需要验证Python是否正确安装。打开命令提示符,输入以下命令来检查你机器上运行的Python版本:
python --version
如果Python安装正确,控制台将显示类似 Python 3.x.x 的信息,这表明你正在运行Python 3。请确保版本号与Python官网上的最新版本匹配。如果看到“Python not found”的提示,请检查你的安装步骤或参考Python官网的相关文档。
选择与设置集成开发环境
上一节我们介绍了如何安装Python,本节中我们来看看如何设置一个编写和运行代码的环境。你需要选择一个IDE(集成开发环境)。本课程使用Jupyter IDE来演示Python代码,因此建议你也使用Jupyter环境。

以下是安装Jupyter的步骤:
- 打开命令提示符。
- 输入以下命令来安装Jupyter:
python -m pip install jupyter - 安装完成后,输入以下命令来启动Jupyter Notebook:
python -m notebook
此命令将在你的默认浏览器中打开一个新的Jupyter Notebook实例。


配置工作环境
现在,你可以在Jupyter中设置你的工作环境。
- 在Jupyter主界面,点击“New”按钮。
- 选择“Folder”来创建一个新文件夹。这将生成一个名为“Untitled Folder”的文件夹。
- 将这个新文件夹重命名为
mysql_python_course_content,然后点击进入。 - 在这个文件夹内,再次点击“New”按钮。
- 选择“Python 3 (ipykernel)”选项。这将打开一个新的浏览器标签页,你可以在其中输入和运行Python代码。

安装MySQL连接器

为了在Python和MySQL数据库之间建立连接,我们需要使用一个专门的Python库,名为 mysql-connector-python。这个库是一个API,提供了许多用于操作MySQL的实用功能。
mysql-connector-python 需要使用Python自带的包管理工具 pip 进行单独安装。
以下是安装步骤:
- 在你刚刚创建的Jupyter Notebook代码单元格中,输入以下命令:
!pip install mysql-connector-python - 按下
Shift + Enter或点击“Run”按钮来执行代码。
代码执行后,控制台将输出安装过程的信息。如果安装成功,你将看到一系列库被成功安装的提示。这意味着Python现在可以访问这些库的所有功能。
导入MySQL连接器库
安装完成后,你需要在Python代码中导入这个库才能使用它。在Python中,使用 import 语句来导入库。
在你的Jupyter Notebook的新单元格中,输入以下代码:
import mysql.connector as connector
这段代码的含义如下:
import:告诉Python你想要导入并使用一个库。mysql.connector:mysql是pip安装的主包,.connector是使用点运算符访问的该包下的子模块。as connector:这是一种使用别名的重命名方法。它将mysql.connector简化为connector,方便后续代码调用。在Python开发中使用别名是常见做法,最好使用其他开发者熟悉的通用别名。
运行这段代码。如果控制台没有输出任何错误信息,则表明 mysql-connector-python 已成功导入,你现在可以与你的MySQL数据库进行通信了。
总结


本节课中我们一起学习了为数据库工程配置Python环境的完整流程。我们首先下载并安装了Python,然后设置了Jupyter开发环境。接着,我们使用 pip 安装了关键的 mysql-connector-python 库,并最终在代码中成功导入该库,为后续连接和操作MySQL数据库做好了准备。现在,你的Python环境已经准备就绪,可以开始进行数据库操作了。
Python 72:使用Python客户端连接MySQL数据库 🐍🔌
在本节课中,我们将学习如何使用Python客户端连接MySQL数据库。我们将了解如何导入必要的库、建立连接,并理解连接过程中的关键参数。
概述
基于Python的应用程序需要能够与MySQL数据库通信以执行数据库操作。这意味着需要在Python和MySQL之间建立连接。例如,Little Lemon餐厅需要在其依赖Python的网站和MySQL数据库之间建立连接,以便客户可以查看菜单和预订时段等数据。
导入MySQL连接器
首先,您需要熟悉MySQL Python Connector API软件包。这个API促进了Python和MySQL之间的连接。但在使用之前,您需要将其导入到Python程序中。
要导入连接器API,请键入import命令,后跟其名称mysql.connector,然后选择运行。
然而,每次需要使用API时都输入mysql.connector可能很繁琐。因此,我们可以创建一个别名。您可以为mysql.connector创建一个名为connector的别名。然后,您可以使用这个简写来提高编码效率。
要创建别名,您可以再次键入import mysql.connector或使用现有代码,但这次在语句中包含as connector。as关键字指示Python在未来的所有代码中使用connector这个别名来识别import mysql.connector。
现在,每次需要使用MySQL Python连接器API时,您只需键入其别名connector。但请确保您已首先安装了连接器API,否则会遇到“模块未找到”的错误。
您已成功导入了连接器API(也称为包或软件)。现在,您可以使用访问运算符(点号.)开始使用其模块和功能。
建立数据库连接
例如,您可以帮Little Lemon使用连接器在其基于Python的网站和MySQL数据库之间建立连接。
首先,创建一个变量来访问连接器模块中的连接功能。将其命名为connection,并为其分配值connector.connect。
接下来,在一对括号内向connect模块传递关键参数。这些参数是数据库用户名和密码,因为只有授权用户才能访问数据库。在这个例子中,用户是Mario,密码是cuisine。
默认情况下,连接是在Python和安装在您机器本地的数据库之间建立的。这个数据库被称为“本地主机”(Localhost)。它也可以通过其IP地址127.0.0.1访问。
在本课程的后续阶段,您将了解更多关于本地主机和其他参数的信息。现在,您应该能够在Python和MySQL之间创建连接了。
以下是建立连接的核心代码:
import mysql.connector as connector
connection = connector.connect(
user="Mario",
password="cuisine"
)
总结
本节课中,我们一起学习了如何为Python程序导入MySQL连接器API,以及如何使用用户名和密码参数在Python和MySQL数据库之间建立基本连接。这是进行后续所有数据库操作的第一步。




Python 73:使用Python在MySQL数据库中创建数据库和表 🗄️
在本节课中,我们将学习如何通过Python程序连接到MySQL数据库,并执行创建新数据库和数据表的操作。这是构建数据驱动应用程序的基础步骤。

上一节我们介绍了如何建立Python与MySQL的连接。本节中,我们来看看在连接建立后,如何具体执行创建数据库和表的操作。
创建游标对象
与MySQL数据库建立连接后,需要通过一个“游标”对象来执行SQL命令。游标可以理解为指向数据库中特定位置的指针,它允许应用程序执行查询并获取结果。
创建游标对象的代码如下:
cursor = connection.cursor()
创建新数据库
以下是创建名为“LittleLemon”数据库的步骤。
首先,将SQL语句编写为Python字符串,并存储在一个变量中。使用三引号可以方便地将长SQL语句写成多行,提高可读性。
create_database_query = """
CREATE DATABASE LittleLemon;
"""
接着,使用游标对象的execute()方法来执行这个SQL语句。
cursor.execute(create_database_query)
选择使用的数据库
数据库创建成功后,需要明确指定后续操作在此数据库中进行。
以下是选择使用“LittleLemon”数据库的代码:
use_database_query = "USE LittleLemon;"
cursor.execute(use_database_query)
在数据库中创建表
现在数据库已准备就绪,下一步是在其中创建存储数据的表。
我们将创建一个名为MenuItems的表,用于存储菜单项信息。该表包含以下列:
ItemID: 主键,整数类型,自动递增。Name: 菜品名称,可变字符类型,最大长度200。Type: 菜品类型(如菜系),可变字符类型,最大长度100。Price: 价格,整数类型。
创建该表的SQL语句和Python代码如下:
create_menu_item_table = """
CREATE TABLE MenuItems (
ItemID INT AUTO_INCREMENT,
Name VARCHAR(200),
Type VARCHAR(100),
Price INT,
PRIMARY KEY (ItemID)
);
"""
cursor.execute(create_menu_item_table)
使用相同的方法,您可以创建数据库所需的任何其他表,只需修改相应的SQL查询语句即可。


本节课中我们一起学习了使用Python操作MySQL数据库的核心流程。我们首先通过连接对象创建了游标,然后依次执行了创建数据库、选择数据库以及创建数据表的SQL命令。掌握这些步骤是进行后续数据插入、查询和更新等操作的基础。
Python 74:游标和MySQL 🎯
在本节课中,我们将要学习在Python前端客户端访问MySQL后端数据库时,一个核心概念——游标。我们将了解游标是什么、它的关键特性以及它在数据库查询中是如何工作的。
什么是游标?📍
当使用Python前端客户端访问MySQL后端数据库时,你的Python应用程序需要知道完成查询所需的数据存储在何处。游标指示了这些数据在数据库中的位置。

让我们通过Little Lemon数据库的一个例子来理解游标。Little Lemon需要检索一位客人的预订详情。他们可以使用Python执行SQL SELECT查询来完成此任务。然而,Python前端客户端需要知道数据存储在MySQL后端数据库的哪个位置。MySQL数据库可以使用一个游标对象来指向Little Lemon所需的记录。这个游标帮助Python客户端定位所需的数据。
这个例子很好地解释了数据库工程师所说的“游标”一词。游标是一个指针,它将Python客户端指向MySQL数据库中你的SQL查询结果。游标通过识别特定的行或记录来指示查询数据的位置。你可以使用游标来读取、检索和遍历查询结果中的单个记录。
游标的关键特性 🔑
游标有几个对数据库工程师特别有用的关键特性或特征。
以下是游标的主要特性:

- 只读性:游标是只读的,因此你无法更新与其关联的数据。结果不能被修改,它们由游标保存。
- 不可滚动性:游标按顺序获取记录,这有助于在处理单个记录时跟踪你的位置。你不能在记录之间跳过或跳转,也不能以相反的顺序获取它们。
- 敏感性:游标是敏感的。这意味着它们指向MySQL数据库中的原始数据,而不是副本。这比使用不敏感游标更快,因为不敏感游标只能指向数据的副本,所以返回结果需要更长的时间。

上一节我们介绍了游标的基本概念和特性,本节中我们来看看如何在MySQL数据库查询中使用游标。
如何使用游标?⚙️
在MySQL数据库查询中使用游标需要遵循几个步骤。
以下是使用游标的标准流程:
- 声明游标:使用
DECLARE语句并为你的游标分配一个自定义名称,后跟CURSOR关键字。然后使用FOR关键字和一个相关的SQLSELECT语句来确定游标的用途。DECLARE cursor_name CURSOR FOR SELECT_statement; - 打开游标:输入
OPEN命令并调用你的游标名称以建立结果集。此时,游标正指向你的SELECT语句的结果集。OPEN cursor_name; - 获取结果:输入
FETCH命令和你的游标名称。然后输入INTO关键字,后跟结果需要传输到的位置名称。例如,结果可以传输到一个局部变量中,以便在你的Python应用程序中使用。FETCH cursor_name INTO variable_name; - 关闭游标:输入
CLOSE命令,后跟游标名称。CLOSE cursor_name;

关闭游标始终是一个好习惯,可以释放与其关联的内存。正如之前所学,游标是不可滚动的,它按顺序处理结果集。因此,一旦它到达最后一个结果,就不再需要保持打开状态。所以关闭游标以释放它使用的内存。

回到Little Lemon的示例 🍋

现在你已经熟悉了游标的工作原理,让我们回到Little Lemon的查询。
Little Lemon可以使用游标来检索客人的预订数据。首先,他们声明一个名为 guest_booking_details 的新游标。这后面跟着一个SQL SELECT 语句,该语句从Little Lemon的MySQL数据库中定位客人的数据。然后他们打开游标。接下来,他们获取数据并将其存储在其Python客户端中一个名为 booking_data 的变量里。
总结 📝

本节课中我们一起学习了MySQL数据库中的游标。你现在应该能够解释游标是什么、描述其关键特性并说明它们是如何工作的。随着课程的深入,你将更详细地探索游标,所以这是你MySQL Python之旅的一个良好开端。
Python 75:游标子类 🎯
在本节课中,我们将要学习 Python 中游标类的概念及其子类。你将了解游标如何作为 Python 与 MySQL 数据库之间的翻译器,以及如何通过不同的游标子类来优化数据查询和处理。
游标类概述
在课程的这个阶段,你已经探索了如何使用游标来指向 MySQL 数据库中所需数据的位置。然而,理解 Python 如何利用游标类也同样重要。游标类将 MySQL 记录转换为更符合 Python 习惯的代码。通过 Python,你还可以使用游标子类来改变或调整游标的行为。在本视频中,你将探索游标类及其子类,并深入了解它们的工作原理。
Little Lemon 餐厅需要查明一位客人在餐食上花费了多少钱。他们可以通过使用游标子类来创建 Python 字符串,从而以更高效的方式从其 MySQL 数据库中查询此数据。
让我们花点时间来了解更多,首先理解数据库工程师所说的“游标类”是什么意思。
什么是游标类?
游标类是 Python 与后端 MySQL 数据库之间通信的一种翻译方法。Python 以字符串对象的形式向 MySQL 数据库发送 SQL 语句。游标类接收这些 Python 字符串对象,并将它们解析为数据库可以理解的、符合 MySQL 习惯的命令和数据类型。然后,Python 在检索这些结果时使用游标类,将它们解析为符合 Python 习惯的代码。
游标类包含多个子类,可以根据你的需求以不同方式解析字符串对象。在课程的这个阶段,你可能已经看到了一些以属性和方法形式出现的子类示例。
以下是游标类中一些常见的属性和方法:
column_names游标属性:返回 SQL 语句结果集的列名。rowcount属性:返回一个整数,表示受SELECT、INSERT或UPDATE语句影响的行数。execute方法:这是最常用的游标函数。它将 Python 字符串参数的参数绑定到 MySQL 查询语句,以便可以在 MySQL 数据库上执行。
游标子类继承了父游标类的属性。反过来,子类通过改变父类的行为来提高代码效率。

游标子类示例
上一节我们介绍了游标类的基本概念,本节中我们来看看几个具体的游标子类及其应用场景。
原始游标子类

一个例子是原始游标子类。这个子类返回变量的结果,而不将它们预处理为更符合 Python 习惯的解释。因此,它消耗更少的处理能力,让你可以自由地创建对结果的自定义转换。然而,缺点是处理目标变量需要编写更多的代码。
Little Lemon 可以使用原始游标子类来创建他们自己的自定义数据类型转换。如果初始的转换类型不是所需的类型,这可以节省时间。
字典游标子类
另一个子类的例子是 MySQL 字典游标类。这个类将每一行作为一个字典返回,这有助于访问变量。你可以通过直接使用变量名来访问它们。
Little Lemon 可以利用这个子类以字典的形式返回结果集。这让他们可以使用数据库列的实际列名,而不是处理一个未命名的元组列表。
缓冲游标子类
最后,还有缓冲游标类,它获取数据的一个子集并将其存储在缓冲内存中。这个子类的优点是,你的代码不需要重复地向服务器请求每一行。缺点是数据需要存储在本地内存中,因此你只能使用这个子类来返回小的数据集。
Little Lemon 可以使用缓冲游标类来检索数据。这让他们可以进行交错的 SQL 请求。SQL 请求的交错是指你获取 SQL 查询结果的一部分,并用它向数据库发出后续请求。
让我们举一个例子,Little Lemon 需要查明一位客人在餐食上花费了多少钱。他们可以交错一个 SQL 请求来执行此任务。对于第一个查询,他们创建一个作为 Python 字符串的 MySQL 查询,以检索客人的预订 ID。一旦他们获得了第一个查询的结果,他们就可以创建第二个或后续的查询,该查询使用第一个结果的一部分(即预订 ID)来查找餐食的费用。换句话说,Little Lemon 可以在第二个查询中使用其第一个查询的一部分,向数据库发出后续请求。
数据库可以从第一个查询返回多个结果。如果你在所有其他结果返回之前,在后续查询中使用第一个结果,那么 MySQL 会遇到一个名为“发现未读结果”的错误。因此,最佳实践是在进行任何后续查询之前完成你的循环并让第一个查询的所有结果都打印出来。然而,如果你首先使用缓冲游标来缓冲结果,就可以避免这种情况。
缓冲游标返回所有行,而标准游标要求你向每个受影响的行发送单独的查询。

实例化游标子类的语法
现在你已经熟悉了不同的游标子类,让我们看看实例化它们的语法。所有子类的语法都非常相似。你只需向游标传递一个关键字参数,以特定方式改变其行为。
要创建标准游标,你需要将游标创建为一个对象。因此,要实例化一个游标子类的实例,你需要添加该子类作为关键字参数来改变游标的行为。
以下是实例化不同游标子类的示例代码:

# 创建标准游标
standard_cursor = connection.cursor()
# 创建缓冲游标
buffered_cursor = connection.cursor(buffered=True)
# 创建原始游标
raw_cursor = connection.cursor(raw=True)
# 创建字典游标
dict_cursor = connection.cursor(dictionary=True)
例如,你可以传递 buffered 作为关键字来创建缓冲游标,或者传递 raw 作为关键字来创建原始游标,或者传递 dictionary 来使用字典游标。
Little Lemon 可以使用游标子类从 MySQL 数据库的订单表中请求所有数据。他们可以创建两个游标实例:一个是缓冲的,另一个是标准实现。他们将 SQL SELECT 语句作为参数传递给两个游标。一旦执行,游标将返回订单表中的所有项目。
总结

本节课中我们一起学习了游标子类的概念以及它们如何用于改变游标的行为。你现在应该理解,游标子类如原始游标、字典游标和缓冲游标,各自提供了不同的数据返回和处理方式,以适应特定的性能需求或编程便利性。通过选择合适的子类,你可以优化 Python 与 MySQL 数据库之间的交互。
Python 76:模块小结 - 使用Python与MySQL交互 🎉
在本节课中,我们将回顾并总结本模块的核心内容。您已经学习了如何使用Python与MySQL数据库进行交互的基础知识,包括建立连接、使用API以及操作游标。接下来,我们将系统地梳理这些关键技能。
模块概述
恭喜您完成了本课程第一个模块的学习。现在,您应该已经熟悉了使用Python与MySQL数据库交互的基础知识。
让我们花点时间回顾一下您在本模块课程中获得的关键技能。
第一课:Python与MySQL的连接基础
在第一课中,您学习了课程介绍,并理解了如何使用应用程序编程接口(API,也称为驱动程序)在Python和MySQL数据库之间建立连接。
您现在知道,前端Python应用程序会向连接器API发送连接请求。API将此连接转发给后端的MySQL数据库,随后可以建立游标连接。一旦连接建立,数据就可以在Python和MySQL之间传输。


您还了解了可用于创建此连接的不同API,并且作为数据库工程师,您将主要依赖 mysql.connector Python API。


在第一课中,您还学习了如何在系统上安装和配置Python软件,以便在Python和MySQL之间建立连接。
以下是您学到的具体步骤:
- 您学习了如何下载Python。
- 您学习了如何使用Pip。
- 您学习了如何导入所需的不同包。
- 您还学习了如何使用别名创建自定义名称,以便更轻松地与数据库通信。
接着,您探索了一个使用Python客户端连接到MySQL数据库的实际示例。
您看到了如何将API导入Python程序并使用别名,并且您现在知道如何使用访问(点)运算符来利用其模块和功能。
您还知道了如何向连接器模块传递参数,例如用户名和密码。
最后,您以使用Python在数据库中创建表的流程概述结束了本课。您了解到需要创建一个游标对象,用于与MySQL数据库通信。
游标对象访问一个执行模块,该模块将查询作为Python字符串传递给MySQL数据库。
一旦您的连接设置完成,您就可以使用Python在MySQL数据库中创建数据,例如数据库和表。
第二课:深入理解游标
在上一节我们介绍了连接的基础,本节中我们来看看数据库交互的核心工具——游标。
在模块的最后一课中,您学习了游标。您了解到游标用于指示数据在MySQL数据库中的位置,以便Python客户端可以访问它。
游标允许您读取、检索并在查询结果中的各个记录之间移动。
接着,您探索了对数据库工程师特别有用的游标关键特性或功能。
以下是游标的三个主要特性:
- 只读性:游标是只读的,无法被修改,并且会保留结果。
- 不可滚动性:游标按顺序获取记录,这有助于在处理单个记录时跟踪当前位置。
- 敏感性:这意味着它们指向MySQL数据库中的原始数据,而不是副本。
然后,您探索了在MySQL数据库中使用游标所需的代码。
您现在可以使用以下命令:
DECLARE命令来声明一个游标。OPEN命令来调用游标的名称。FETCH命令来获取结果。CLOSE命令来关闭游标。
您随后通过Little Lemon数据库的示例探索了这个过程。
在本课的下一个部分,您探索了不同的游标子类,并学习了如何使用它们来改变或调整游标的行为。
您发现游标类是一种在Python和MySQL数据库之间转换通信的方法。类接收Python字符串对象,并将其解析为MySQL友好的命令和数据类型,以便数据库理解。
您还探索了一些常见的游标子类示例。子类继承其父游标类的属性,例如:
cursor.Raw子类cursor.Dict子类buffered cursor类

您还了解了交错SQL请求,这涉及使用部分SQL查询来发起后续请求。



接着,您探索了创建和使用子类的语法,并且也通过Little Lemon数据库的示例探索了子类的应用。


课程总结
本节课中我们一起学习了使用Python与MySQL数据库交互的基础知识,包括建立MySQL-Python连接和使用游标。做得很好。
我期待在下一个模块中继续指导您,您将学习如何使用Python在MySQL中执行查询。
Python 77:使用Python在MySQL数据库中创建和读取数据 📊
在本节课中,我们将学习如何使用Python编程语言,在MySQL数据库后端执行创建(Create)和读取(Read)操作。我们将通过一个餐厅预订系统的实例,一步步了解如何将SQL语句转换为Python字符串,并通过连接器与数据库进行交互。
概述:Python与数据库的CRUD操作
正如你所知,在MySQL中操作数据库涉及CRUD(创建、读取、更新、删除)操作。通过Python操作数据库同样涉及这些CRUD操作。
关键区别在于,用于执行操作的SQL语句必须在Python中作为字符串进行处理。在本视频中,你将发现如何使用Python在MySQL数据库中执行创建和读取操作。
创建数据:从SQL到Python字符串
上一节我们介绍了CRUD操作的基本概念,本节中我们来看看如何使用Python执行创建(插入)操作。
到目前为止,你已经学会了如何使用类似INSERT INTO的语句在数据库中创建数据。例如,Little Lemon餐厅必须使用INSERT INTO语句,将顾客姓名和他们预订的时间段添加到数据库bookings表的customer_name和time列中。
然而,在使用Python时,这种方法需要更多的步骤。
以下是使用Python执行插入操作的基本流程:
- 编写SQL语句:像平常一样创建你的SQL语句。
- 转换为字符串:然后使用引号将其转换为Python字符串参数。
- 存储为变量:创建一个变量来存储这个查询字符串。
- 通过游标发送:Python通过游标(cursor)将这个字符串发送到数据库。
- 执行语句:该语句随后在数据库上执行。
Little Lemon可以使用Python,通过mysql_insert_query变量将客人的预订数据添加到他们的MySQL数据库中。SQL数据只需要以字符串格式传递。
核心代码示例:
# 步骤1-3:创建SQL插入语句并存储为字符串变量
mysql_insert_query = “INSERT INTO bookings (customer_name, time) VALUES (‘John Doe’, ‘19:00’);”
读取数据:执行SELECT查询
现在我们已经了解了如何创建数据,接下来让我们看看如何从数据库中读取数据。
正如你现在应该知道的,你也可以使用SELECT语句从数据库中检索或查询数据。在使用Python读取数据时,编写SQL SELECT查询同样是第一步。
Python可以使用SELECT语句从MySQL数据库读取数据。就像处理插入查询一样,你需要创建一个变量来将查询存储为Python字符串,并编写你的SELECT查询。确保它写在引号内以转换为Python字符串。
Little Lemon可以使用一个read_data_query字符串对象来检索他们bookings表中的所有数据。他们只需要将SELECT查询写成Python字符串,然后使用游标对象的execute模块。
核心代码示例:
# 创建SELECT查询字符串
read_data_query = “SELECT * FROM bookings;”
实践演练:帮助Little Lemon餐厅
既然你知道了如何使用Python创建和读取数据,让我们看看你是否能帮助Little Lemon。
为了演示,Python、API和MySQL数据库之间已经通过MySQL Connector Python API建立了连接。
任务一:插入数据
你的第一个任务是使用cursor()方法从连接实例化游标对象。
下一步是通过将MySQL插入查询作为参数传递给execute()方法来执行它。
一旦查询执行完毕,使用连接对象的commit()方法将更改提交到数据库。
现在,每个新的客户数据实例都通过mysql_insert_query添加到了数据库的bookings表中。
操作步骤代码:
# 假设 `connection` 是已建立的数据库连接对象
cursor = connection.cursor()
mysql_insert_query = “INSERT INTO bookings (customer_name, time) VALUES (‘Alice’, ‘20:00’);”
cursor.execute(mysql_insert_query)
connection.commit()
任务二:读取数据
在开发的下一阶段,Little Lemon需要读取或检索其数据库中的数据。一些示例客户数据已被添加到数据库中以测试读取功能。你需要开发功能来检索这些数据。
正如前面所学,第一步是创建一个作为Python字符串的SQL语句,你可以将其传递给一个变量。
在这种情况下,你需要创建一个SQL SELECT语句,从数据库的bookings表中检索所有数据,并将此语句作为字符串传递给名为read_data_query的Python变量。
现在你需要将查询传递给游标上的execute模块,就像创建数据时一样。查询执行后,你需要使用游标上的fetchall()方法来检索结果。
创建一个名为results的新变量,然后通过游标对象将查询结果传递给这个变量。
results变量是列表数据类型,它以元组的形式显示每条记录。因此,results变量本质上是一个元组列表,每个元组都是从bookings表中提取的单行。
在这种情况下,results变量中每个元组中的项目顺序与bookings表中的列顺序相同。它们这样排序是因为你正在读取表中的所有记录。
你可以通过创建一个名为columns的新变量并从游标对象调用列名来检索列名。这些值随后存储在columns变量中以供后续使用。
操作步骤代码:
read_data_query = “SELECT * FROM bookings;”
cursor.execute(read_data_query)
results = cursor.fetchall()
columns = cursor.column_names
重要注意事项与收尾工作
别忘了,当你不再需要它们时,关闭游标对象和连接也是一个好习惯。
收尾代码:
if cursor:
cursor.close()
if connection and connection.is_connected():
connection.close()

总结
本节课中我们一起学习了如何使用前端Python应用程序在后端MySQL数据库中执行创建和读取操作。
你现在知道了如何:
- 将SQL语句(如
INSERT INTO和SELECT)转换为Python字符串。 - 使用游标对象的
execute()方法在数据库上运行这些查询。 - 使用
commit()提交插入操作的变化。 - 使用
fetchall()检索查询结果,并以列表形式获取列名。 - 在操作完成后正确关闭游标和数据库连接。

这是一个很好的开始。我期待引导你学习更多Python中的CRUD操作。
Python 78:使用Python更新和删除MySQL数据库中的记录
在本节课中,我们将学习如何使用Python对MySQL数据库执行更新和删除操作。这些是数据库日常维护和应用程序交互中的核心CRUD操作。
概述
我们将通过一个餐厅预订管理的实际案例,演示如何编写Python代码来更新和删除MySQL数据库bookings表中的记录。课程将涵盖SQL UPDATE和DELETE语句的构建与执行,以及如何在Python中提交更改和验证结果。
了解数据表结构
在开始操作之前,我们先了解一下目标数据表。bookings表存储了餐厅客人的预订信息,包含以下字段:
BookingID:预订IDTableNumber:桌号FirstName:客人名LastName:客人姓BookingSlot:预订时间段WaiterID:服务员ID
我们的任务就是帮助Little Lemon餐厅使用Python更新和删除这张表中的记录。
更新数据库记录
上一节我们了解了数据表的结构,本节中我们来看看如何更新已有的记录。在数据库中,更新数据需要使用UPDATE语句。
以下是更新记录的基本步骤:
-
构建SQL更新语句:首先,需要编写一个包含
WHERE子句的SQLUPDATE查询,以精确指定要更新哪条记录。例如,更新某位客人的桌号。UPDATE bookings SET TableNumber = %s WHERE BookingID = %s在Python中,我们将此查询语句保存为一个字符串对象,例如
update_bookings。 -
执行更新操作:使用数据库游标的
execute()方法来运行这个查询,并传入需要更新的具体值(如新的桌号和目标预订ID)。 -
提交更改:为了将更改永久保存到数据库,必须调用连接对象的
commit()方法。
实践示例:假设我们需要将预订ID为6的客人Diana Pinto的桌号更新为10。
# 假设 cursor 是数据库游标, connection 是数据库连接
update_query = "UPDATE bookings SET TableNumber = 10 WHERE BookingID = 6"
cursor.execute(update_query)
connection.commit()
执行后,可以查询验证数据是否已正确更新。
删除数据库记录
学会了更新记录后,接下来我们学习如何删除记录。当客人取消预订时,就需要从数据库中删除对应的记录。
以下是删除记录的核心步骤:
-
构建SQL删除语句:编写一个使用
WHERE子句的DELETE语句,以确保只删除特定的记录。通常使用BookingID作为条件。DELETE FROM bookings WHERE BookingID = %s同样,在Python中将其创建为字符串对象,例如
delete_booking。 -
执行与提交:使用
execute()方法运行删除查询,然后使用commit()方法提交更改。
实践示例:删除预订ID为4的客人Marcos Romero的记录。
delete_query = "DELETE FROM bookings WHERE BookingID = 4"
cursor.execute(delete_query)
connection.commit()
执行后,重新查询bookings表,可以确认Marcos Romero的记录已不存在,这表明删除操作成功。
高级技巧:你还可以修改DELETE语句中的WHERE子句,使用更复杂的条件。例如,删除那些TableNumber或WaiterID为NULL的无效预订记录。
DELETE FROM bookings WHERE TableNumber IS NULL OR WaiterID IS NULL

总结

本节课中,我们一起学习了使用Python进行MySQL数据库更新和删除操作的关键技能。我们掌握了如何构建并执行UPDATE和DELETE SQL语句,如何通过commit()方法确认更改,以及如何验证操作结果。这些是构建能够与数据库交互的Python应用程序的基础操作。
Python 79:使用Python对MySQL数据库中的数据进行过滤和排序 🔍
在本节课中,我们将学习如何使用Python对MySQL数据库中的数据进行过滤和排序。当查询数据库记录时,查询结果可能包含数百、数千甚至数百万条数据。然而,我们通常只需要其中的一小部分。通过应用过滤和排序技术,我们可以精确地定位所需的数据。
上一节我们介绍了数据库查询的基本概念,本节中我们来看看如何在Python中实现这些技术。我们将以Little Lemon餐厅为例,他们需要查询所有账单金额大于或等于40美元的预订记录,并按账单金额升序排列。
过滤技术:WHERE子句 📊
过滤技术中,WHERE子句是一个基础且重要的工具。它用于筛选满足特定条件的记录。

以下是WHERE子句的基本用法:
SELECT booking_id, bill_amount FROM orders WHERE bill_amount = 40;
此语句从orders表中选取bill_amount等于40的所有记录的booking_id和bill_amount列。
然而,Little Lemon需要的是账单金额大于或等于40美元的记录。这需要引入比较运算符。

使用比较运算符 🔧
比较运算符允许我们指定更精确的过滤条件。

例如,我们可以将等于运算符(=)替换为大于或等于运算符(>=):
SELECT booking_id, bill_amount FROM orders WHERE bill_amount >= 40;
此修改将结果集缩小,仅返回账单金额大于或等于40的记录。
排序技术:ORDER BY子句 📈

为了进一步组织数据,我们可以使用ORDER BY子句对结果进行排序。这是一个可选的子句,可以附加在SELECT语句末尾。
Little Lemon需要按账单金额升序排列结果。实现方式如下:
SELECT booking_id, bill_amount FROM orders WHERE bill_amount >= 40 ORDER BY bill_amount ASC;
这里,ASC关键字表示升序排列。执行后,查询将返回所有符合条件的记录,并按bill_amount从小到大排序。
在Python中实现查询 🐍
现在,我们已经回顾了SQL中的过滤和排序技术。接下来,我们将探讨如何在Python程序中执行这些查询。
首先,我们需要将SQL查询语句编写为Python字符串:
mysql_query = """
SELECT booking_id, bill_amount
FROM orders
WHERE bill_amount >= 40
ORDER BY bill_amount ASC;
"""


以下是使用Python连接MySQL并执行查询的完整步骤:
- 建立与MySQL数据库的连接。
- 创建游标对象。
- 执行SQL查询。
- 获取并处理结果。
import mysql.connector
# Python 1. 建立连接
connection = mysql.connector.connect(
host='localhost',
user='your_username',
password='your_password',
database='little_lemon_db'
)
# Python 2. 获取游标
cursor = connection.cursor()
# Python 3. 执行查询
cursor.execute(mysql_query)
# Python 4. 获取所有结果
results = cursor.fetchall()
# 打印结果
for row in results:
print(row)
# 关闭游标和连接
cursor.close()
connection.close()
执行上述代码后,results变量将包含一个Python元组列表,每个元组代表一条符合条件的记录,并且已按账单金额升序排列。Little Lemon餐厅便可以获得他们所需的数据。

总结 🎯
本节课中我们一起学习了如何使用Python对MySQL数据库进行数据过滤和排序。我们回顾了SQL中WHERE子句和比较运算符用于过滤数据,以及ORDER BY子句用于排序数据的方法。接着,我们通过一个完整的Python示例,演示了如何连接数据库、执行包含过滤和排序条件的SQL查询,并获取处理结果。掌握这些技术能帮助你更精确、高效地从数据库中提取所需信息。
Python 80:使用Python将不同MySQL数据库表中的数据联接
在本节课中,我们将要学习如何使用Python对MySQL数据库执行联接操作,以从多个表中提取和组合数据。这对于构建需要整合不同数据源的功能至关重要。
概述
在数据库工程的这个阶段,你应该已经具备使用联接操作从多个表中提取数据的经验。同时,也存在需要使用Python在MySQL数据库上执行联接操作的场景。本节将探索使用Python执行联接操作的具体流程。
联接操作回顾
上一节我们介绍了数据库联接的基本概念,本节中我们来看看如何在Python中实现它。联接是使用SQL的JOIN子句创建的。它针对两个目标表之间的一个公共列。这些公共列用于将表连接在一起并提取所需的记录。

MySQL中使用的联接类型包括:
- 左联接 (
LEFT JOIN) - 右联接 (
RIGHT JOIN) - 内联接 (
INNER JOIN) - 外联接 (
OUTER JOIN)
所有这些联接都可以与Python结合使用。
使用Python执行内联接
让我们通过一个内联接的例子来了解其语法和创建过程。


首先,需要创建一个SQL查询字符串,并将其传递给一个Python变量。
join_query = “SELECT * FROM table1 INNER JOIN table2 ON table1.common_column = table2.common_column;”
然后,使用游标对象的execute方法来运行此查询。

cursor.execute(join_query)

查询执行后,可以将结果检索到另一个变量中。对包含联接结果的游标对象使用fetchall方法。
results = cursor.fetchall()
数据将以元组列表的形式被检索。
实战案例:小柠檬餐厅菜单功能

现在你已经熟悉了使用Python联接不同表数据的过程,让我们看看如何帮助小柠檬餐厅创建这个查询。
小柠檬餐厅正在其网站上添加一个新的菜单功能。该功能让顾客可以查看菜单项、价格以及每道菜所属的菜系类型。该功能所需的数据位于其MySQL数据库的两个不同表中:menu表和menu_items表。
正如之前所学,小柠檬餐厅需要使用一个联接查询来提取其网站新菜单功能所需的数据。
他们首先在Python中将联接语句创建为一个字符串对象,并将其存储在一个名为join_query的变量中。该联接查询必须从menu_items表中选取name、type和price列,同时从menu表中选取cuisine列。通过两个表共有的itemID列创建一个内联接。
join_query = “””
SELECT MenuItems.Name, MenuItems.Type, MenuItems.Price, Menu.Cuisine
FROM MenuItems
INNER JOIN Menu ON MenuItems.ItemID = Menu.ItemID;
“””

假设MySQL Connector/Python API已经建立了前后端之间的连接,并且游标对象也已准备就绪。这意味着你现在可以执行你的联接查询了。
使用游标对象的execute方法运行查询。

cursor.execute(join_query)
当查询执行后,你可以使用fetchall方法将游标对象中的所有结果提取到一个名为results的新变量中。

results = cursor.fetchall()

结果将以元组列表的形式被检索,每个元组代表一行数据。

小柠檬餐厅可以查看每个单独条目的顺序。他们只需调用游标上的column_names属性,即可按顺序返回列名。

column_names = cursor.column_names
总结
在本节课中,我们一起学习了如何使用Python在MySQL数据库上执行联接操作。你现在应该已经具备使用联接从多个表中提取数据的经验,并且熟悉了结合使用联接和Python从MySQL数据库中提取数据的方法。
Python 81:使用Python对MySQL数据库执行高级查询小结 📚
在本节课中,我们将回顾并总结本模块的核心内容。本模块主要讲解了如何使用Python编程语言对MySQL数据库执行查询操作,包括基础的增删改查(CRUD)和更高级的查询技术,如数据过滤、排序与表连接。
模块内容回顾


恭喜你完成了本课程的第二个模块。现在,你应该已经熟悉如何使用Python在MySQL数据库中执行查询操作。

让我们花点时间回顾一下你在本模块课程中获得的一些关键技能。

第一课:使用Python执行CRUD操作


在第一课中,你学习了如何使用Python在MySQL数据库中执行创建、读取、更新和删除(CRUD)操作。

你首先回顾了如何使用INSERT语句在MySQL数据库中创建数据。接着,你学习了如何通过Python将数据插入MySQL数据库。


这个过程的核心步骤如下:
- 首先,SQL查询被创建为一个Python字符串参数。
- 然后,这个参数通过一个连接器(connector)传递给MySQL数据库。
- 连接器将其解析为MySQL能够理解的格式。

你随后探索了将MySQL数据库查询渲染为Python字符串参数的语法示例,并研究了在Little Lemon数据库中使用Python创建和读取数据的实例。

接下来,你重新学习了如何使用UPDATE和DELETE操作在MySQL数据库中删除和更新记录。你学习了如何将这些查询创建为Python字符串参数,并探索了来自Little Lemon数据库的一些示例。


之后,你进行了一系列实验练习,获得了在自己MySQL数据库中使用Python执行CRUD操作的机会。

你还通过完成几个测验来测试你对这些主题的掌握程度。
第二课:使用Python执行高级查询
在本模块的第二课中,你学习了如何使用Python在MySQL数据库中执行高级查询。



你首先学习了如何使用Python在MySQL中过滤和排序记录。你重温了在其他课程中学到的基本过滤和排序技术。

以下是这些技术的核心:
- 使用
WHERE子句来满足一个或多个特定条件。 - 利用
ORDER BY子句按升序或降序对数据进行排序。 - 包含比较运算符以指定所需的确切数据。
你随后通过探索Little Lemon数据库的几个示例,发现了这些技术如何在Python中使用。

本课的下一个部分重点介绍了如何使用Python连接MySQL数据库中不同表的数据。你回顾了JOIN子句的基础知识,以及如何使用它来定位两个目标表之间的公共列。

接着,你学习了如何将JOIN与Python结合使用,以从MySQL数据库中提取数据。这个过程可以概括为:
- 使用
JOIN创建一个SQL查询,并将其作为Python字符串。 - 使用游标对象上的
execute模块执行该字符串。 - 然后,使用另一个满足查询条件的变量和
fetchall方法从MySQL数据库中检索结果。

你还探索了来自Little Lemon数据库的此过程示例。与第一课一样,你也完成了一个实验练习。

在这个实验练习中,你使用Python执行了一个JOIN操作,以从MySQL数据库中提取数据。然后,你通过一个测验测试了对该过程的掌握程度。

总结

本节课中我们一起学习了如何使用Python对MySQL数据库执行查询。你现在应该已经掌握了使用Python在MySQL数据库中执行查询所需的技能和知识。
做得很好。我期待在下一个模块中继续指导你,在那里你将探索高级数据库客户端的主题。
Python 82:MySQL函数快速回顾 📚
在本节课中,我们将要学习MySQL函数的基础知识。函数是存储在数据库中的可重用代码块,用于执行特定操作并返回结果。它们能帮助数据库工程师高效地处理数据,而无需重复编写代码。我们将回顾几种常见的MySQL函数类型,并了解如何在Python中使用它们。
什么是MySQL函数?🤔
上一节我们介绍了课程概述,本节中我们来看看MySQL函数的定义。
MySQL函数是一段执行特定操作并返回结果的代码。换句话说,它是一个将一组指令组合起来,并以输出形式产生结果的任务。
公式:函数(输入) -> 输出

MySQL函数的优势 💪
了解了函数的基本概念后,我们来看看使用MySQL函数有哪些好处。

以下是MySQL函数的主要优势:
- 数据操作:非常适合对数据库中的数据进行操作。
- 参数化:部分函数可以接受参数或参数。
- 自定义功能:可以创建自定义函数,将多个任务组合在一个代码块中。
- 存储与调用:可以将函数存储在数据库中,并在需要时调用。
- 可重用性:可用于完成重复性任务,无需重写代码。
常见的MySQL函数类型 📊

在数据库工程的学习过程中,你可能已经使用过多种类型的函数。MySQL中最常见的内置函数包括以下几类。


以下是主要的MySQL内置函数类型:


- 字符串函数:用于操作字符串值。
- 数值函数:包括聚合函数和数学函数。
- 日期与时间函数:用于提取和格式化日期时间值。
- 比较函数:用于比较数据库中的值。
- 控制流函数:用于评估条件并决定查询的执行路径。
字符串函数 🔤

让我们花点时间回顾这些不同类型函数的基础知识,并看看Little Lemon餐厅如何利用它们。首先从字符串函数开始。
字符串函数用于操作字符串值,例如连接字符串或提取字符串的一部分。
示例:CONCAT函数。CONCAT将两个独立表中的数据合并成一个字符串。

代码示例:
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM customers;

Little Lemon可以在其数据库记录上使用CONCAT字符串查询函数,来提取每位客户的信息,例如他们消费了多少钱。

数值函数 🔢
接下来是数值函数。数值函数包括聚合函数和数学函数。这些函数用于对数值数据集执行常见任务。

示例:AVG函数。Little Lemon可以使用AVG数值函数来确定每位客户在餐厅消费的平均金额。

代码示例:
SELECT AVG(bill_amount) AS average_spent FROM orders;


日期与时间函数 📅
MySQL函数的另一个例子是日期与时间函数。

日期与时间函数可用于查询MySQL数据库,以根据查询需求提取各种不同格式的日期和时间值。
在Little Lemon,他们经常提取日期和时间数据来分析客户行为。他们可以利用这些数据找出客人在餐厅停留的时间以及哪些日子最繁忙。

比较函数 ⚖️
接下来是比较函数。你可以使用这些函数来比较数据库中的值,它们可以用于许多不同类型的值,如数字、字符串和字符。


Little Lemon利用比较函数,通过对销售数据使用GREATEST和LEAST比较函数,来识别菜单上最畅销和销量最低的菜品。

控制流函数 🧭
最后是控制流函数。控制流函数用于评估条件并决定查询的执行路径或流程。

示例:CASE函数。CASE函数会遍历CASE块内的一组条件。一旦某个条件匹配,它就返回一个值;如果没有条件匹配,则返回NULL值。
代码示例:
SELECT menu_item_name,
CASE
WHEN cost_price > selling_price THEN 'Loss'
ELSE 'Profit'
END AS profit_status
FROM menu_items;

Little Lemon经常依赖控制流函数来确定其菜单上的哪些菜品是亏损的,哪些菜品已经转为盈利。

在Python中使用MySQL函数 🐍
现在你已经回顾了MySQL中可用的不同函数,让我们了解一下它们如何与Python协同工作。让我们以数值函数为例,看看Little Lemon如何计算每位客户的平均账单。
他们可以创建一个使用AVG函数来确定平均账单金额的SELECT查询。

代码示例:
# 假设使用mysql-connector-python
import mysql.connector
query = "SELECT AVG(bill_amount) AS average_bill FROM orders;"
# ... 执行查询并获取结果的代码

这个查询被传递给数据库执行。一旦查询执行完毕,Little Lemon就可以访问结果,查看每位客户在餐厅消费的平均金额。

总结 ✨
本节课中我们一起学习了MySQL函数的基础知识。我们回顾了函数的定义、优势以及五种常见的函数类型:字符串函数、数值函数、日期与时间函数、比较函数和控制流函数,并通过Little Lemon餐厅的实例了解了它们的应用。最后,我们还简要演示了如何在Python中执行包含MySQL函数的查询。本课程的后续部分将更详细地探讨使用Python访问MySQL函数的方法。
Python 83:使用Python访问MySQL函数
在本节课中,我们将要学习Python中datetime库的日期和时间函数。你将了解如何利用这些函数从数据库中提取和操作时间与日期值,并解决一个实际的餐厅预订时间调整问题。
🕒 Python datetime库概述
datetime是Python的一个内置类,它提供了多个函数,用于格式化、修改和处理时间与日期变量。由于它是Python原生库,无需使用pip安装即可直接导入使用。
上一节我们介绍了datetime库的基本概念,本节中我们来看看它具体提供了哪些功能。
以下是Python datetime库中几个核心函数:

datetime.now():用于获取当前的日期和时间。datetime.date():用于获取当前的日期。datetime.time():用于获取当前的时间。timedelta():用于计算两个时间或日期值之间的差值。

📝 导入与基本语法
要开始使用datetime库,首先需要将其导入到Python环境中。为了提高代码效率,我们通常会给它设置一个简短的别名。
import datetime as dt

通过以上代码,我们创建了一个别名dt。之后,我们就可以使用dt来调用库中的函数,而无需每次都输入完整的datetime。
现在,我们已经成功创建了一个datetime对象,接下来看看如何使用它的功能。

⏰ 使用datetime.now()获取当前时间
让我们从datetime.now()函数开始,学习如何获取当前的日期和时间。
首先,创建一个名为current_time的变量。然后,使用我们定义的别名dt作为模块名,调用datetime.now()函数。最后,指示Python打印出当前的日期和时间值。
current_time = dt.datetime.now()
print(current_time)

执行这段代码,Python将返回你所在位置的日期和时间。日期以年-月-日的格式显示,时间则以时:分:秒的格式显示。
但有时你可能只需要知道当前日期或当前时间。你可以再次使用相同的代码,但这次给Python两个独立的打印指令。
print(dt.datetime.now().date())
print(dt.datetime.now().time())
当代码执行时,Python会分别显示日期值和时间值。
🔮 使用timedelta进行时间计算
在制定计划时,预测未来的日期非常有用。例如,下周的今天是几号?timedelta函数可以计算两个值之间的差值,并以Python友好的格式返回结果,从而回答这类问题。
为了找到七天后的日期,你可以创建一个名为week的新变量。键入dt模块,并将timedelta函数作为一个对象实例进行访问。然后,将7天作为参数传递给它。最后,指示Python打印该变量的结果。
week = dt.timedelta(days=7)
future_date = dt.datetime.now() + week
print(future_date)
执行后,Python将返回一周后的日期值。

🍋 实战:帮助Little Lemon餐厅调整预订时间
现在你已经了解了datetime的工作原理,让我们看看能否帮助Little Lemon餐厅解决实际问题。
正如之前所学,Little Lemon餐厅遇到了日程冲突。为了解决这个问题,他们需要将每个预订时段向后推迟一小时。你可以通过指示Python从bookings表中检索数据,然后为每个预订时间增加一小时来完成此任务。
我们假设Little Lemon已经传递了他们的登录凭据,创建了一个新的游标实例,并将游标指向了他们的数据库。你的第一个任务是导入datetime库,以便处理日期和时间。
import datetime as dt
接下来,编写一条SQL SELECT语句,从bookings表中返回所有数据。
sql_select = “SELECT * FROM bookings”

将该语句作为字符串参数传递给游标的execute模块。

cursor.execute(sql_select)

在进入循环之前,指示Python打印bookings表的列名,以便查看每一行的项目。
print(cursor.column_names)

你可以将这些值分配给变量,并创建一个名为new_booking_slot的新变量,用于保存更新后的时间段值。
要为每个时间段增加一小时,需要将1小时作为参数传递给timedelta函数,然后将该函数加到booking_slot变量上。
最后,指示Python以文本字符串的形式打印新的预订时间段值。这个文本字符串详细说明了每个预订ID的值,以及其各自旧的与新的预订时间段。
以下是循环遍历查询结果并提取booking_id和booking_slot列中行的代码:
results = cursor.fetchall()
for row in results:
booking_id = row[0]
booking_slot = row[3]
new_booking_slot = booking_slot + dt.timedelta(hours=1)
print(f“Booking ID: {booking_id}, Old Slot: {booking_slot}, New Slot: {new_booking_slot}”)
结果显示,booking_id是第一个值(索引0),booking_slot是第四个值(索引3)。


📚 课程总结
本节课中我们一起学习了Python中不同的datetime函数及其使用方法。你学会了如何获取当前日期和时间、分别提取日期或时间、以及使用timedelta进行日期计算。最后,我们应用这些知识,通过为每个预订增加一小时,帮助Little Lemon餐厅解决了日程冲突问题。
处理日期时间函数可能具有一定挑战性,但你已经朝着掌握这个主题迈出了坚实的一步。
Python 84:使用Python处理日期时间函数 📅
在本节课中,我们将要学习Python中内置的datetime库,了解其核心功能,并学习如何运用这些函数来处理数据库中的日期和时间数据。我们将通过一个实际案例——为餐厅预订时间增加一小时——来演示其应用。
概述
作为数据库工程师,您可以使用日期和时间函数从数据库中提取时间与日期值。您也可以使用Python原生datetime库中提供的函数来完成类似任务。本节将介绍Python中可用的不同datetime函数及其使用方法。

Python的datetime类

datetime是Python的一个类,内置了多个可用于格式化和更改时间、日期变量的函数。它是Python的原生库,无需使用Pip即可导入。
以下是Python datetime库提供的主要函数:

datetime.now():用于获取当前日期和时间。datetime.date():用于仅获取当前日期。datetime.time():用于仅获取当前时间。timedelta():用于计算两个值之间的差值。
导入与基本语法

要使用datetime类,首先需要导入它。通常我们会为其创建一个别名以简化代码。
import datetime as dt

通过以上代码,我们导入了datetime库并为其创建了别名dt。现在,您可以使用dt来调用库中的函数,而无需每次都输入完整的datetime。
使用datetime.now()获取当前时间

现在,您的Python环境中已创建了一个datetime对象。让我们看看如何使用datetime.now()函数。
首先,创建一个名为current_time的变量。然后,使用模块别名dt调用datetime.now()函数。最后,指示Python打印当前的日期和时间值。

current_time = dt.datetime.now()
print(current_time)
执行代码后,Python将返回您所在位置的日期和时间。日期以年-月-日的格式显示,时间则以时:分:秒的格式显示。
如果您只需要当前日期或当前时间,可以分别使用以下代码:
print(dt.datetime.now().date()) # 仅打印日期
print(dt.datetime.now().time()) # 仅打印时间

使用timedelta进行时间计算
接下来,我们看一个稍复杂的函数:timedelta。在制定计划时,推算未来日期很有用。例如,下周的今天是几号?您可以使用timedelta函数计算两个值之间的差值,并以Python友好的格式返回结果。
要计算七天后的日期,可以创建一个名为week的新变量。使用dt模块访问timedelta函数,并将7天作为参数传递给它。最后,指示Python打印该变量的结果。
week = dt.timedelta(days=7)
future_date = dt.datetime.now() + week
print(future_date)
执行后,Python将返回一周后的日期。


实战:为Little Lemon餐厅更新预订时间
现在您已经了解了datetime的基本工作原理,让我们来帮助Little Lemon餐厅解决实际问题。

如前所述,Little Lemon餐厅遇到了日程冲突,需要将每个预订时段向后推迟一小时。您可以通过指示Python从bookings表中检索数据,然后为每个预订时间增加一小时来完成此任务。

以下是实现步骤:
- 建立数据库连接:首先,在前端Python客户端和后端数据库之间建立连接,并传递您的登录凭据。这将创建一个新的游标实例,并将游标指向Little Lemon数据库。
- 导入datetime库:在开始处理日期时间之前,需要先导入
datetime库。import datetime as dt - 执行SQL查询:编写一个SQL
SELECT语句以从bookings表中返回所有数据,并将该语句作为字符串参数传递给游标的execute模块。 - 处理并更新数据:进入循环前,指示Python打印
bookings表的列名,以便查看每一行的项目。然后,遍历查询结果,提取bookingID和bookingSlot列的行。要为每个时间段增加一小时,可以向timedelta函数传递1小时的参数,然后将该函数加到bookingSlot变量上。 - 输出结果:最后,指示Python以文本字符串的形式打印新的预订时段值。该字符串详细说明了每个预订ID及其对应的旧、新预订时段。
通过以上步骤,您将成功帮助Little Lemon餐厅更新了所有预订时间。

总结

本节课中,我们一起学习了Python datetime库的核心功能。我们介绍了如何获取当前日期和时间、如何单独提取日期或时间,以及如何使用timedelta进行日期时间的加减计算。最后,我们通过一个为餐厅预订增加一小时的实战案例,综合应用了这些知识。
处理日期时间函数可能具有一定挑战性,但您已经为掌握这个主题打下了良好的基础。
Python 85:存储过程快速回顾 📚
在本节课中,我们将要学习MySQL存储过程的核心概念、语法及其优势。存储过程是数据库工程师用于存储和复用代码的强大工具,能有效提升工作效率和代码质量。
概述
存储过程为数据库工程师提供了一种在需要时存储和调用代码的有效方法。接下来,我们将快速回顾MySQL存储过程的工作原理及其应用。
存储过程的实际应用场景
上一节我们介绍了存储过程的基本概念,本节中我们来看看它在实际场景中的应用。

小柠檬餐厅每天早晨都需要检查数据库中的在线预订,以获取当天到店顾客的名单。他们每天早晨都重写相同的代码来提取这些数据。



然而,他们可以改为调用一个存储过程来提取所需数据,从而无需每天早晨重写大段代码。


在了解具体做法之前,我们先回顾一下存储过程的基础知识。

存储过程基础
一个存储过程是一段代码块,或一个或多个预编译的查询,可以存储在数据库中。你可以在需要时调用或执行这个存储过程。


你可能已经知道,这类似于函数的工作方式。但请不要忘记这两个概念之间的关键区别:函数只能有输入参数,而存储过程既可以有输入参数,也可以有输出参数。

使用存储过程主要包含三个步骤,你应该已经熟悉它们了。

以下是使用存储过程的三个主要步骤:
- 创建存储过程。
- 调用存储过程。
- 删除存储过程。



存储过程的优势
接下来,让我们快速回顾一下存储过程的好处。
以下是存储过程的三个主要优势:
- 代码一致性更高:每次调用时都使用相同的代码块,你可以确切知道它的输出结果。
- 代码可重用:你可以在所有数据库任务中根据需要多次使用它。
- 代码更易于使用和维护:它作为一个代码块存储,可以根据需要被调用、编辑或删除。




存储过程的语法
现在,让我们快速回顾创建存储过程的语法。
要创建存储过程,请以 CREATE PROCEDURE 命令开始。然后写上过程名和一对括号来存放参数。确保将所有必需的参数包含在括号内。
CREATE PROCEDURE procedure_name (parameter1 datatype, ...)
BEGIN
-- 过程逻辑
END;






最后,编写过程逻辑的其余部分。


当你需要调用该过程时,只需键入 CALL 命令后跟过程名。不要忘记包含括号。
CALL procedure_name();

如果你需要从数据库中移除或删除存储过程,则只需键入 DROP PROCEDURE 命令后跟过程名。

DROP PROCEDURE procedure_name;


在这种情况下,你不需要包含任何括号。
应用实例

小柠檬餐厅可以使用以下代码创建一个存储过程,用于提取预定到访餐厅的顾客详情。
他们以 CREATE PROCEDURE 命令开始。然后将过程命名为 daily_customer_details,并添加参数。
CREATE PROCEDURE daily_customer_details()
BEGIN
-- 提取当日顾客详情的SQL逻辑
SELECT * FROM bookings WHERE visit_date = CURDATE();
END;




最后,他们编写过程的逻辑。现在,每天早晨,他们只需键入 CALL 命令后跟 daily_customer_details。存储过程便会从数据库中提取所需的顾客数据。
CALL daily_customer_details();



存储过程与Python
既然你已经回顾了存储过程的概念,你可能会问自己:存储过程与Python有何关系?


存储过程能提升Python应用程序的性能,并减少应用程序与MySQL数据库之间的网络流量。应用程序只需向数据库发送存储过程的名称和参数,而不是一大段SQL语句。




总结
本节课中我们一起学习了存储过程的优势,以及如何在数据库中创建、调用和删除它们。你现在已经准备好学习如何使用Python来执行这些操作了。
Python 86:使用Python访问存储过程 📖
在本节课中,我们将学习如何使用Python来调用MySQL数据库中的存储过程。我们将通过一个为“小柠檬”餐厅筛选符合赠券条件的顾客的实际案例,来演示从创建存储过程到在Python中执行并获取结果的全过程。
概述
存储过程是预编译并存储在数据库中的SQL语句集合,可以像函数一样被调用。在Python中,我们可以通过数据库连接来创建和执行这些存储过程,从而高效地处理复杂的数据操作。
上一节我们介绍了在MySQL中创建存储过程的基础知识,本节中我们来看看如何用Python与之交互。
创建存储过程字符串
第一步,我们需要将创建存储过程的SQL语句定义为一个Python字符串。
以下是创建名为 get_customers_and_bills 的存储过程的代码。该过程通过内连接(INNER JOIN)查询 bookings 和 orders 表,筛选出消费金额大于等于50美元的顾客信息。
stored_procedure_query = """
CREATE PROCEDURE get_customers_and_bills()
BEGIN
SELECT
CONCAT(g.first_name, ' ', g.last_name) AS guest_name,
b.booking_id,
o.bill_amount
FROM bookings b
INNER JOIN orders o ON b.booking_id = o.booking_id
INNER JOIN guests g ON b.guest_id = g.guest_id
WHERE o.bill_amount >= 50;
END
"""
核心概念:在Python API中执行SQL时,整个字符串被视为一个MySQL语句,因此无需像在MySQL客户端中那样设置分隔符(DELIMITER)。所需的结束分号会自动附加。
在数据库中创建存储过程
当执行存储过程时,你需要在MySQL数据库上存储一段代码块,以便在需要时调用。
你可以使用游标(cursor)的 execute 方法来执行这个SQL字符串,从而将存储过程存储在MySQL数据库中。
# 假设 `cursor` 是已建立的数据库游标对象
cursor.execute(stored_procedure_query)
如果执行成功,该过程就被保存在数据库中了。
调用存储过程并获取结果
现在,存储过程已经创建好,我们可以从Python中调用它。
首先,你需要调用或触发这个过程。
你可以使用游标对象的 callproc 方法来调用存储过程,将过程名作为参数传递给该方法。
cursor.callproc('get_customers_and_bills')
接下来,你需要检索存储过程返回的结果。
以下是完成此任务的步骤:
- 使用Python内置的
next()函数从游标的stored_results()迭代器中获取结果集。 - 将结果集保存到一个变量中。
- 使用
fetchall()方法获取所有数据行。
# 获取存储的结果
results = next(cursor.stored_results())
# 获取所有数据行
dataset = results.fetchall()
代码成功运行后,dataset 变量将包含一个Python列表,列表中的每个元素都是一个元组(tuple),代表存储过程返回的一行记录。
处理与查看结果
你可以通过索引访问数据集,或者运行循环来打印所有记录。
# 打印所有记录
for record in dataset:
print(record)
# 或者通过索引访问
# rint(dataset[0])
根据案例,查询结果显示有一位顾客在“小柠檬”消费了50美元或以上,符合获得赠券的条件。

总结


本节课中我们一起学习了使用Python访问MySQL存储过程的完整流程。我们首先将创建存储过程的SQL语句定义为字符串,然后通过游标执行它以在数据库中创建该过程。接着,我们使用 callproc 方法调用存储过程,并通过 stored_results() 和 fetchall() 方法获取和处理返回的数据集。这种方法将数据库的预编译逻辑与Python程序的灵活性结合起来,能有效执行复杂的数据操作。
Python 87:数据库连接池 🏊♂️
在本节课中,我们将要学习数据库连接池的概念。我们将探讨其工作原理,并了解它如何帮助应用程序高效、安全地管理大量数据库连接。
一个MySQL数据库需要同时为许多用户提供访问。每个连接都必须是安全且稳定的,以确保只有经过身份验证的用户才能访问,并且他们的连接没有失败的风险。但是,管理安全稳定的连接需要许多资源密集型的操作。那么,如何才能高效地执行这些操作呢?答案就在于数据库连接池。
什么是数据库连接池?🤔
上一节我们提到了管理连接的开销。本节中,我们来看看数据库连接池的具体定义。

数据库连接池涉及创建和管理一个连接池,以在客户端和MySQL数据库之间运行更快、更高效和更优化的连接。
为了更好地理解连接池的工作原理,让我们探索一个视觉示例。

连接池如何工作?🔧
想象一个包含四个开放连接到MySQL数据库的池。其中两个连接当前正被客户端用于访问数据库。另外两个连接是空闲的,可供任何新用户使用。
一个新用户可以到来并请求访问数据库。连接池随后会为这个新用户分配一个开放的连接。在新用户被分配连接后不久,前两个用户完成了他们的任务,结束了他们的会话并离开了连接池。
即使用户离开了连接池,连接也保持开放。从技术上讲,连接并没有被关闭。它们只是被放回连接池中,在那里它们仍然可供新用户使用。
现在,有三个空闲且随时可用的连接可以分配给新用户。

处理高并发场景 🚀
上一节我们看了连接池的基本工作流程。本节中,我们来看看当所有连接都被占用时会发生什么。
但如果所有四个连接都在使用中,而第五个用户想要加入呢?只有四个连接可用,那么如何满足第五个用户的访问请求?
为了避免这种情况,最佳方法是创建多个池,每个池分配特定数量的连接。这意味着不同的用户可以被分配到不同的池,因此至少在一个池中总是有一个可用的连接供新用户使用。

您还可以对系统进行编程,如果在其他池中没有合适的连接可用,则在一个池内创建新的连接。

连接池的优势 ✨

以下是使用连接池的几个关键优势:
- 高效利用资源:连接池使可用资源得到高效利用。
- 减少连接开销:它减少了建立连接所需的时间和精力。
- 简化编程模型:连接池简化了编程模型。
- 提升应用性能:当Python应用程序连接到MySQL数据库时,连接池提高了其性能。

总结 📝
本节课中,我们一起学习了数据库连接池的概念。你现在应该熟悉了数据库连接池,能够解释其工作原理并描述其优势。关于连接池,本课程还有更多内容可以学习,但你已经有了一个很好的开始。
Python 88:Python MySQL连接池教程 🛠️
在本节课中,我们将要学习如何使用Python的MySQL连接池模块,为数据库创建和管理一个安全、高效的连接池。连接池允许多个用户共享一组预先建立的数据库连接,从而提升应用程序的性能和资源利用率。
连接池概述
数据库连接池是一种为多用户提供安全、认证数据库连接的有效方式。MySQL Connector Python API通过MySQLConnectionPool模块,提供了开发连接池的实用方法。
上一节我们介绍了连接池的基本概念,本节中我们来看看如何具体构建一个连接池。

导入连接池模块
MySQLConnectionPool模块位于mysql.connector.pooling目录中。你可以使用import语法和from关键字将其导入工作环境,以访问其功能。

from mysql.connector.pooling import MySQLConnectionPool

这段代码指示Python访问子目录并返回MySQLConnectionPool库。
连接池模块的功能与属性

MySQLConnectionPool模块包含许多有用的函数和属性。以下是其中几个核心概念:
pool_name:用于标识连接池名称的类属性。如果不指定,则会自动生成一个。你可以根据需要创建任意数量的池。pool_size:声明为池创建的连接数量的属性。默认连接数为5,但单个池最多可创建32个连接。connection_id:分配给池中每个连接的唯一ID。
以下是该模块中可用的几个类方法:
get_connection():用于请求一个连接。如果池中有可用连接,则分配一个空闲连接。如果没有可用连接,则会收到“池耗尽”错误。is_connected():一个布尔函数,根据是否已建立连接返回True或False值。这是避免错误的有效方法。close():通知连接池用户已完成会话。用户不再需要该连接,因此该连接可以放回池中,作为可供需要的新用户使用的可用连接。
为Little Lemon构建连接池

现在你已经熟悉了连接池模块,让我们来帮助Little Lemon公司构建一个连接池。
正如之前所学,Little Lemon希望创建一个连接池,为用户提供高效访问其数据库的途径。在创建连接池之前,首先需要使用MySQL Connector Python API导入MySQLConnectionPool库。
from mysql.connector.pooling import MySQLConnectionPool
导入连接器后,下一步是建立与数据库的连接。将池命名为little_lemon_pool,然后使用pool_size属性指定4个连接。使用localhost作为主机,并将池放置在little_lemon数据库上。最后输入用户名和密码。
pool = MySQLConnectionPool(
pool_name="little_lemon_pool",
pool_size=4,
host="localhost",
database="little_lemon",
user="your_username",
password="your_password"
)

所有这些代码都作为参数传递给MySQLConnectionPool模块并赋值给pool变量。
接下来,你需要为连接池创建一个Python用户列表,可以将其命名为users。
users = ["Anna", "Brian", "Clara", "David"]

用Little Lemon宾客名单的成员填充此列表。
然后,你需要创建一个SQL SELECT语句。该语句必须接受一个整数参数。该整数对应于不同的ID请求,作为数据库用户访问不同的数据点。
sql_select = "SELECT * FROM Bookings WHERE BookingID = %s"


现在,你需要使用for循环。可以将其与range函数结合使用。range函数与pool_size属性一起使用。
for i in range(pool.pool_size):

这意味着无论池有多大,循环总是会运行到结束。

下一步是设置应用程序的连接。编写一个语句,检查池中是否成功建立了连接。此语句还可以避免代码中出现任何错误。

connection = pool.get_connection()
if connection.is_connected():
然后,编写一个语句,从现有的活动池连接实例化一个新游标。此操作必须为与池成功建立的每个新活动连接执行。

cursor = connection.cursor()
接下来,创建一个print语句,在屏幕上显示以下信息:请求数据库信息的用户、分配给此用户的唯一连接ID以及他们请求的唯一预订ID。该print语句使用花括号进行格式化。这些符号按照format函数中指定的顺序获取指定的变量。这意味着信息将按照你指定的顺序打印。
print("User: {} - Connection ID: {} - Booking ID: {}".format(users[i], connection.connection_id, i+1))
代码的下一行是一个参数化的SELECT语句。该语句使用之前的初始SQL SELECT语句,并将其与递增的i结合,为每个用户分配不同的预订ID。
cursor.execute(sql_select, (i+1,))
然后,你可以使用fetchall方法返回与此SQL SELECT语句对应的所有信息,并将信息打印在屏幕上。
results = cursor.fetchall()
for row in results:
print(row)
你还可以创建一个else语句,如果找不到活动连接,则在屏幕上生成错误消息。

else:
print("无法建立连接。")
最后,当用户结束会话时,使用close方法将用户的连接返回到池中。
connection.close()

总结
本节课中我们一起学习了如何使用MySQLConnectionPool模块提供的函数和属性为数据库创建连接池。我们涵盖了从导入模块、配置连接池参数,到从池中获取连接、执行查询以及妥善关闭连接并释放回池中的完整流程。掌握连接池技术对于构建高效、可扩展的数据库应用程序至关重要。
Python 89:模块小结 高级数据库客户端 📚
在本节课中,我们将对“高级数据库客户端”模块进行总结。我们将回顾如何利用Python操作MySQL函数和存储过程,以及如何创建和管理数据库连接池。
模块回顾
恭喜你完成了本课程的第三个模块。现在,你应该已经熟悉了如何使用Python在MySQL数据库中利用函数和存储过程,以及如何创建和管理数据库连接池。

让我们花点时间回顾一下你在本模块课程中获得的关键技能。
第一课:使用Python调用MySQL函数
在模块的第一课中,你学习了如何使用Python调用MySQL函数。
你首先快速回顾了MySQL函数,并重温了函数提供的优势。其主要优势在于消除了执行重复任务的需要。

以下是MySQL函数的主要类别:

- 字符串函数:用于操作字符串值。
- 数值函数:用于对数值数据集执行任务。
- 日期和时间函数:用于从数据库中提取日期和时间值。
- 比较函数:用于比较数据库中的值。
- 控制流函数:用于评估条件并确定查询的执行路径或流程。

接着,你通过探索Little Lemon数据库的示例,学习了如何使用Python访问MySQL函数。你还在实验和测验活动中展示了新掌握的技能和知识。

第二课:使用Python调用存储过程


在模块的第二课中,你重温了存储过程的基础知识。你再次了解到,存储过程是一段可以存储在数据库中并按需调用的代码块。

存储过程提供了几个优势,例如代码一致性、可重用性,以及能够将代码作为一个单独的块进行维护。
然后,你回顾了用于创建存储过程的语法,包括 CREATE PROCEDURE、CALL 和 DROP PROCEDURE 命令,以及 BEGIN...END 代码块。

你还探讨了在Python中使用存储过程的优势,例如提升Python性能和减少Python与MySQL之间的网络流量。
在本课的下一部分,你学习了如何使用Python访问存储过程。你探索了Little Lemon数据库中的一些存储过程示例,例如内连接操作。你看到了如何在Python中利用这些存储过程来查询MySQL数据库。
你还学习了如何在Python中使用 callproc() 方法来调用存储过程。


# 示例:调用存储过程
cursor.callproc('procedure_name', [arg1, arg2])

使用Python的 next() 函数检索结果,并且看到了使用 fetchall() 方法的示例。
当存储过程在Python中成功运行后,数据会以元组列表的形式返回。你可以索引数据集或运行for循环来打印所有记录。
之后,你在实验环境中展示了在Python中使用存储过程的能力,并通过测验测试了你对Python和存储过程的知识。

第三课:连接池

在模块的第三课也是最后一课中,你学习了连接池。在这次回顾中,你了解到连接池资源充足、提供更快的连接速度、简化编程模型,并能提高Python应用程序的性能。
接着,你学习了Python MySQL连接池。你了解到数据库连接池是使用 mysql.connector.pooling 模块来管理和维护的。这个模块需要导入到你的工作环境中,以便访问其功能。

该模块还提供了许多有用的函数和属性,例如:


pool_namepool_sizeconnection_id
此外,还有几个可用的类方法,如 get_connection()、is_connected() 和 close()。这些方法对于管理和维护模块非常有用。

然后,你探索了如何使用MySQL Connector Python API创建MySQL连接池的示例。
你还探讨了数据库连接池的概念。你了解到,数据库连接池涉及创建和管理一个连接池,以在客户端和MySQL数据库之间建立更快、更高效和优化的连接。
连接在客户端之间进行管理,用户可以通过使用活动连接随时加入或退出会话。

你可以创建具有特定连接数的多个池,从而确保每个用户始终有一个可用的连接。
之后,你完成了一个使用连接池的实验,并通过测验测试了你对连接池的知识。



总结
本节课中,我们一起回顾了“高级数据库客户端”模块的核心内容。你现在应该具备了使用Python处理MySQL函数和存储过程所需的技能和知识,并且也应该能够创建和管理数据库连接池。
做得很好。我期待在下一个模块中继续指导你,在那里你将使用数据库客户端进行更深入的工作。
Python 90:数据库客户端课程回顾 🎯
在本节课中,我们将回顾整个数据库客户端课程的核心内容。我们将系统梳理从建立连接到执行高级操作的关键知识点,帮助你巩固所学。
概述
课程主要分为三个模块。第一个模块介绍了如何使用Python连接和操作MySQL数据库。第二个模块深入讲解了增删改查等基本操作。第三个模块则探讨了高级主题,如函数、存储过程和连接池。
模块一:建立连接与基础操作
上一节我们概述了课程结构,本节中我们来看看第一个模块的具体内容。你首先学习了MySQL Connector Python API以及如何使用Pip包。
你随后学习了如何安装一个前端的Python客户端,并将其连接到后端的MySQL数据库。
接着,你探索了如何建立Python与MySQL之间的通信以执行CRUD操作。
一旦建立了连接,你便可以访问一个游标对象。
获得游标对象后,你使用Python创建了一个MySQL数据库和表。
然后,你学习了如何使用Python提交对MySQL数据库的更改。
在模块一的第三课也是最后一课中,你深入探讨了MySQL数据库中游标的概念。
你学习了游标在Python和MySQL中如何工作。你还回顾了游标的关键特性,了解到它们是只读的、不可滚动的且敏感的。
随后,你了解到游标类用于翻译Python和MySQL数据库之间的通信。
并且你也学习了如何识别不同的游标类。
此外,你还回顾了交错请求的基础知识。
模块二:执行CRUD操作与高级查询
在掌握了连接和基础操作后,第二个模块的重点是使用Python在MySQL数据库中执行创建、读取、更新和删除操作。
你从学习如何在数据库中创建和读取记录开始本模块。
你回顾了这个过程的步骤,并发现了Python如何与数据库通信以执行这些操作。
接着,你学习了如何使用Python执行MySQL的更新和删除操作。
并且你学习了如何将这些更改提交到数据库。
你通过完成一系列实验练习结束了第一课,在这些练习中你展示了使用Python在MySQL数据库中执行CRUD操作的能力。
在模块二的第二课中,你学习了如何使用Python在MySQL数据库中执行高级查询。
这些查询中的第一个涉及使用Python在MySQL数据库中对数据进行过滤和排序。
你重新应用了早期课程中学到的MySQL过滤和排序技术基础,并学习了如何将这些相同的技术应用于Python。
接下来,你学习了如何执行一系列不同的连接操作,以使用Python连接MySQL数据库中不同表的数据。随后,你通过一系列实验有机会测试自己使用Python在MySQL数据库中执行高级查询的能力。
模块三:高级数据库客户端技术
在熟悉了基本和高级查询后,模块三专注于高级数据库客户端技术。本模块的第一课首先概述了如何将MySQL函数与Python结合使用。
你首先学习了如何认识MySQL函数的重要性。
并且你回顾了MySQL中可用的不同类型的函数。
你还学习了MySQL如何通过Python使用函数。
在回顾完MySQL函数的基础知识后,
你接着学习了如何使用Python实现或访问MySQL函数。
你还探索了Python中的日期时间函数,并学习了如何利用这些函数通过Python更新MySQL数据库。
随后,你在实验练习中展示了使用这些函数的能力。
在第三模块的第二课中,你探索了如何将MySQL存储过程与Python结合使用。
你重新应用了存储过程的基础知识,并学习了它们与函数的区别以及为何与Python一起使用。
接着,你学习了如何通过使用callproc方法在Python中访问存储过程。
并且你还回顾了分隔符的使用。本模块的第三课也是最后一课专注于连接池。
你首先深入理解了数据库连接池的概念。
你学习了如何解释数据库连接池。
并且你学习了如何识别数据库连接池的优势。
接着,你回顾了为数据库创建连接池的步骤,
包括实现连接池SQL模块的过程。
总结

本节课中,我们一起系统回顾了数据库客户端课程的全部核心内容。我们从建立Python与MySQL的基础连接开始,逐步深入到执行CRUD操作、高级查询,最后探讨了函数、存储过程和连接池等高级主题。每个环节都强调了理论与实践的结合。
你已经完成了本课程的回顾。现在是时候在分级评估中尝试运用你所学的知识了。

祝你好运。😊
Python 91:课程总结
在本节课中,我们将对数据库工程师课程的核心内容进行回顾与总结,并展望未来的学习路径。
你已经完成了这门课程。你付出了努力,并在此过程中掌握了许多新技能。你在MySQL的学习之旅中取得了巨大进步,现在应该已经理解了数据库客户端的概念。
你能够在实验项目中展示部分学习成果,以及你掌握的实用MySQL技能集。

完成该实验项目后,你现在应该能够使用Python与MySQL数据库进行交互、使用Python在MySQL中执行查询,并能运用MySQL的函数、存储过程和连接池。
# 示例:使用Python连接MySQL并执行查询
import mysql.connector
from mysql.connector import pooling
# 创建连接池
connection_pool = pooling.MySQLConnectionPool(
pool_name="mypool",
pool_size=5,
host='localhost',
database='your_database',
user='your_username',
password='your_password'
)
# 从连接池获取连接并执行查询
connection = connection_pool.get_connection()
cursor = connection.cursor()
cursor.execute("SELECT * FROM your_table")
results = cursor.fetchall()
随后的分级评估进一步检验了你对这些技能的掌握程度。然而,你仍有更多知识需要学习。如果你觉得本课程有帮助并希望了解更多,那么不妨注册下一门课程。在每一门数据库工程师课程中,你都将持续发展你的技能集。
在最终的实验项目中,你将运用所学的一切知识,创建一个属于自己的功能完整的数据库系统。
无论你是刚起步的技术专业人士、学生还是商业用户,课程结束时的项目都能证明你对数据库系统价值和能力的理解。该实验通过实际应用巩固了你的技能,但它还有另一个重要益处:这意味着你将拥有一个可以放入作品集的功能完备的数据库。
这有助于向潜在雇主展示你的技能。它不仅向雇主表明你具备自我驱动力和创新精神,也充分体现了你作为个人以及你新获得的知识的价值。一旦你完成了这个专业系列的所有课程,你将获得数据库工程证书。
该证书也可作为进阶其他基于角色的证书的凭证。根据你的目标,你可以选择深入学习高级的基于规则的证书,或者在获得此证书后学习其他基础课程。

感谢你。很荣幸能与你一同踏上这段探索之旅。祝未来一切顺利。
Python 92:高级数据建模简介 🚀
在本课程中,我们将要学习高级数据建模的核心概念与实用技能。我们将从数据模型的基础知识开始,逐步深入到数据库规范化、数据仓库架构、维度建模以及使用工具进行数据分析和可视化。本课程旨在为你构建坚实的理论基础,并通过实践练习帮助你掌握关键技能。
概述
欢迎来到数据库工程学的下一门课程。本课程的重点是高级数据建模。我们将花一些时间来回顾你将在这些模型中发展的一些新技能。
1:高级数据建模入门 📊
上一节我们介绍了课程概述,本节中我们来看看高级数据建模的具体内容。
你将首先学习高级数据库建模这一主题。你将了解到,数据模型提供了不同数据元素的可视化表示,并展示了它们彼此之间的关系。你还将发现数据建模在Meta公司是如何被应用的。




2:数据库模型的类型 🏗️
上一节我们介绍了数据模型的基本概念,本节中我们将更详细地探讨不同类型的数据库模型。
你将了解到数据库模型有三个层次。分别是概念数据模型、逻辑数据模型和物理数据模型。你还将回顾可用于设计数据库的不同种类的模型。


3:数据库规范化 🧹
上一节我们探讨了数据模型的类型,本节中我们来看看如何通过数据库规范化来构建你的表,以消除异常。

这些异常包括插入异常、更新异常和删除异常。你还将探索一个数据模型的示例,并在一个练习中设计一个数据库模型。
4:MySQL Workbench 工具介绍 🛠️

上一节我们学习了数据库规范化,本节中我们将介绍一个强大的可视化工具。


在本模块的下一课中,你将学习MySQL Workbench。你将了解到MySQL Workbench是一个用于数据库建模和管理的统一可视化工具。它提供了一系列有用的功能,用于创建、编辑和管理数据库。

你将发现如何使用MySQL Workbench构建数据模型图,然后学习如何使用MySQL Workbench的正向工程功能将此模型转换为MySQL中的数据库模式。
你还将学习如何使用MySQL逆向工程一个模型。这意味着你可以从现有数据库创建数据模型或ER图。这本质上与正向工程功能相反。
你可以打印模型、共享它,或者应用更改,并使用正向工程方法将其推送到数据库。
你还将通过一个测验项目和一个练习来完成本课,在该练习中,你将在MySQL Workbench中设计自己的数据库模型。
5:数据仓库概述 🏭
上一节我们介绍了MySQL Workbench工具,本节中我们将进入一个新的模块,探讨数据仓库的主题。


在这个模块中,你将学习数据仓库的架构并构建一个维度数据模型。你将从数据仓库概念的概述开始。你将了解到,数据仓库是一个集中式数据存储库,它从多个来源加载、集成、存储和处理大量数据。然后可以查询这些数据以执行数据分析。

你将发现数据仓库由四个关键特征定义:它是面向主题的、集成的、非易失的,并且数据仓库是随时间变化的。你还将回顾数据仓库处理的不同形式的数据,包括结构化数据、半结构化数据和非结构化数据。
然后你将探索数据仓库的架构,并了解到它包括以下组件:数据源、数据暂存区(包括ETL过程)、数据仓库本身和数据集市。
一旦数据从数据源加载,它就会被集成并存储在数据仓库中。然后它被组织在数据集市中,用户可以在那里执行数据分析并展示他们的发现。这些组件控制着来自不同来源的数据流。它们还处理和集成这些数据,以便用户可以执行数据分析。
你还将探索一个真实世界数据项目的案例研究。
6:维度数据建模 ⭐
上一节我们介绍了数据仓库的基础,本节中我们来看看本模块的第二课:维度数据建模。


本课从维度数据建模的基础知识概述开始。你将了解到它基于维度和事实,并使用星型模式和雪花模式进行设计。然后你将探索一些维度数据建模的实践示例,并了解到在创建模型时需要遵循四个关键步骤。


以下是创建维度模型的四个关键步骤:
- 选择要探索的业务流程。
- 选择粒度或详细程度。
- 选择维度。
- 选择事实。
一旦你做出了所有这些选择,你就可以创建模式。最后,你将进行一个练习,在该练习中你将创建自己的维度模型。
7:数据分析基础 📈


上一节我们学习了维度建模,本节中我们将进入本课程的第三个模块,在维度和度量的背景下探索数据分析,并学习如何使用高级分析工具执行可视化数据分析。
你将从数据分析的概述开始。你将回顾数据分析的基础知识,以及你在数据库工程旅程的其他阶段所使用过的关键类型的数据分析。
你还将了解到,你将处理两种通用类型的数据:定量数据(指数值数据)和定性数据(指非数值数据)。


当你确定了需要哪种数据后,你可以使用四种测量尺度来处理和分析它:名义尺度、顺序尺度、等距尺度和比率尺度。

8:数据挖掘与机器学习 🤖
上一节我们介绍了数据分析的类型和测量尺度,本节中我们将学习数据挖掘和机器学习的主题。
你将了解到,数据挖掘是检测数据模式的过程,而机器学习是教会计算机如何学习的过程。机器学习利用数据挖掘模型来处理数据,如分类分析、关联规则、聚类分析和回归分析。



9:数据可视化 🎨
上一节我们探讨了数据挖掘与机器学习,本节中我们来看看数据可视化。
你将了解到,在可视化数据时,你必须考虑你的受众以及他们正在寻找的信息。然后你需要选择一个最能传达此信息的合适图表。
最后,你将通过讨论使用何种数据分析报告来结束本课。
10:Tableau 数据分析工具实践 📊
上一节我们讨论了数据可视化,本节中我们将进入本模块的最后一课,回顾数据分析的主题,并学习如何使用Tableau等数据分析工具。


作为Tableau介绍的一部分,你将了解其主要功能是什么,以及它们如何帮助你执行数据分析。然后你将学习如何使用Tableau分析数据。



以下是使用Tableau进行数据分析的基本步骤:
- 下载、启动和导航Tableau。
- 加载和准备待分析的数据。
- 过滤和可视化数据。
- 创建交互式仪表板。

最后,你将完成一个练习,在该练习中你将在Tableau中执行数据分析。

总结
本节课中我们一起学习了高级数据建模的完整路径。我们从数据模型和规范化开始,探索了数据仓库和维度建模,最后深入到了数据分析、可视化以及使用Tableau等工具进行实践。现在你已经完成了本课程介绍,是时候开始你的高级数据建模之旅了,祝你好运。
Python 93:元数据如何使用数据建模 📊
在本节课中,我们将学习元数据在数据建模过程中的应用。我们将探讨数据建模的行业背景、在Meta等大型科技公司的实践流程、面临的挑战以及工程师在其中的角色和责任。
随着互联网、Web 3.0和元宇宙的发展,行业不断演进。你将从事需要连接数据库的系统开发工作。很少有职位不要求这项技能。因此,这是你为成功职业生涯所能学习的最重要的基础技能之一。
我的名字是Moxie,我使用AM代词,是Meta门洛帕克办公室的一名软件工程师。

数据建模没有放之四海而皆准的流程。为一个新产品开发新数据模型的过程,与改造旧产品以添加新功能或遵守新法规的过程截然不同。因此,你必须根据遇到的需求调整流程。这就是为什么学习这些技能如此重要。
数据建模的参与者 👥
数据建模由不同的人员执行,具体取决于我们正在更改或创建数据模型的背景。
如果我们正在构建一个已有商业案例的新产品,这通常由首席工程师主导,并与产品的高层需求进行讨论。如果我们为用户隐私或特定功能更改数据模型,主导讨论的可能是个人工程师,也可能是参与监管流程的人员。
关于Meta,非常重要的一点是,每位工程师都有权参与讨论并提出更改。因此,尽管最初设计数据模型并将其提出的可能是首席工程师,但每位工程师都应能够参与讨论,并提出自己的想法,以改进我们的数据模型,满足用户和产品的需求。

数据建模的挑战与责任 ⚖️
上一节我们介绍了数据建模的参与者,本节中我们来看看其中的挑战。
在Meta,数据建模面临的挑战之一是确保我们正确使用用户数据,并且在访问新数据时对数据负责。这是一个巨大的挑战,因为我们能够访问大量数据,我们必须确保只用于特定需求,并为所有这些用途获得实际批准。这可能是一个非常艰巨的过程,因为我们必须证明其合理性。

以下是需要详细说明和论证的关键方面:
- 数据来源:我们从哪里获取数据。
- 数据使用:我们如何使用数据。
- 数据存储:我们如何存储数据。
- 存储期限:我们存储数据多长时间。
涉及大量细节。你必须为这些会议做好充分准备,并准备好论证为何包含或不包含某些数据。
管理数据库变更 🔄
管理数据库的变更是一个非常复杂的过程。有许多团队专门负责确保数据安全存储、可靠且有备用方案。
从工程角度,你必须考虑很多因素。但从整体基础设施来看,有许多团队在管理和部署代码及数据库变更,以使这一切正常运行。像Meta或Facebook这样拥有数十亿用户的公司,不可能由单一个体来维护。因此,理解这一点很重要:因为数据库是我们所有产品的共同节点,我们必须非常谨慎地进行更改,并且需要与许多其他不同的团队协调。

数据建模的核心考量 🤔
如果你真的想做好数据建模,你必须认真思考以下几个核心问题:
- 获取数据的目的:你为何获取数据。
- 存储数据的方式:你如何存储数据。
- 保护数据的措施:你如何保护数据。
因此,在进行数据建模时,你必须认真思考用户赋予你的信任。特别是当你处理用户信息时,需要考虑很多方面。构建数据模型需要回答的问题有时很棘手,你需要思考权衡取舍。

总结 📝
本节课中我们一起学习了元数据在数据建模中的应用。数据库是非常复杂的系统,需要大量的协调工作。即使一个单一的数据模型可能由一个人设计,你仍然需要与许多其他技术和跨职能合作伙伴协调,才能构建一个成功的数据库。我希望你能从本视频中学到,数据建模不仅仅是技术设计,更涉及责任、协作和深刻的业务思考。
Python 94:数据建模概述 📊
在本节课中,我们将要学习数据建模的基本概念。数据建模是数据库系统开发的关键前期步骤,它帮助我们规划数据的存储和访问方式,以确保系统的高效运行。我们将探讨数据建模的定义、不同层级模型的作用,并通过一个珠宝店的案例来理解其实际应用。
什么是数据建模? 🤔
上一节我们介绍了课程目标,本节中我们来看看数据建模的核心定义。
开发数据库系统时,需要确保其高效运行并能快速提取信息。创建此类系统的最佳方法是首先设计一个数据模型。通过数据模型,你可以在创建数据库系统之前,规划数据在数据库中的存储和访问方式。
数据模型提供了数据元素的可视化表示,并展示了它们彼此之间的关系。换句话说,它展示了数据库系统的结构。这种结构有助于你理解数据在数据库中如何被存储、访问、更新和查询,同时也确保了结构的一致性和高质量。
数据建模用于开发各种类型的数据库,特别是实体关系数据库。这些数据库是使用实体关系图进行规划的。
数据模型的三个层级 🏗️
理解了数据建模的基本概念后,本节我们将深入探讨其三个不同的抽象层级。
数据建模分为三个层级:概念数据模型、逻辑数据模型和物理数据模型。让我们花些时间来探索这些不同的类型。
概念数据模型
你可能在之前的课程中已经熟悉了概念数据模型。概念数据模型由称为实体的高级抽象数据元素组成。数据元素或实体之间的关系,将数据库系统中相关的数据记录链接起来。概念模型的目的是通过可视化表示其包含的实体及彼此间的关系,来呈现数据库系统的高级概览。
MG珠宝店可以利用概念数据模型来创建他们的数据库系统。他们可以将客户、产品和订单呈现为实体,然后记录这些实体之间的关系。概念模型为逻辑数据模型提供了基础。
逻辑数据模型
同样,你应该对之前课程中的逻辑数据模型示例有基本的了解。逻辑数据模型在概念模型的基础上,提供了实体及其各自关系的更详细概述。它识别每个实体的属性,定义主键并指定外键。
MG可以在其概念数据模型的基础上,用它来创建逻辑数据模型。他们的逻辑数据模型必须包含每个实体所需的所有属性,例如每个实体包含的属性列表。然后,它需要定义这些列中哪些作为每个表的主键。例如,client_id列是clients表的主键。
MG的逻辑数据模型还需要指定他们用于在表之间创建关系的外键。在当前模型中,clients表通过client_id外键连接到orders表。
物理数据模型
物理数据模型用于创建数据库的内部SQL模式,该模式在数据库管理系统中实现。
物理数据模型必须概述诸如数据类型、约束和属性等特性。例如,MG需要为每个属性定义特定的数据类型,比如clients表中full_name属性的VARCHAR类型,或contact_number属性的INTEGER类型。他们还需要应用相关的约束。他们可以为clients表中的每一列施加NOT NULL约束,以确保每一列都包含数据。
此外,还有一系列工具可用于生成和执行物理数据模型的内部模式,这些工具将在后续课程中介绍。
总结与回顾 📝
本节课中,我们一起学习了数据建模的基础知识及其在数据库系统开发中的重要作用。
你现在应该熟悉了数据建模的基础知识,以及它在数据库系统开发中所扮演的重要角色。你也应该能够区分不同层级的数据模型,并解释每个模型如何为数据库系统的创建做出贡献。


通过为MG珠宝店设计从概念到物理的模型,我们看到了一个完整的建模流程如何帮助将业务需求转化为高效、结构清晰的数据库系统。出色的工作。
Python 95:数据模型类型 📊
在本节课中,我们将学习如何为数据库系统选择合适的数据模型。我们将探讨几种主要的数据模型类型,分析它们的优缺点,并了解它们各自适用的场景。
关系数据模型
上一节我们介绍了数据模型的重要性,本节中我们首先来看看最常用的关系数据模型。你可能在之前的课程中已经接触过它。
关系数据模型是一种流行且广泛使用的数据库模型。它将数据库表示为一组关系。每个关系以表格的形式呈现,通过行和列来存储信息。
该模型的一个关键优势是比其他模型更简单易用。你可以快速识别和访问数据。然而,在复杂的关系数据库系统中,数据之间的关系可能变得难以导航。此外,在进行数据分析时,你可能需要以不同的方式组织和构建数据。
实体关系模型
接下来,我们看看与关系模型相似的实体关系模型。
实体关系模型与关系数据模型类似。关键区别在于,你可以通过为每个表分配其独有的属性集,将每个表呈现为一个独立的实体。该模型还涵盖了实体之间的多种关系类型,例如:
- 一对一关系
- 一对多关系
- 多对多关系
例如,M&G公司可以使用实体关系模型来可视化其“客户”表和“订单”表之间的关系。这两个实体通过“客户ID”列连接,形成一对多关系。换句话说,一个或多个订单属于一个特定的客户。
层次数据模型
现在,让我们转向以树状结构组织数据的层次数据模型。
层次数据模型以树状或父子结构组织数据。每条数据记录都有一个父节点,也可以拥有自己的子节点。其主要缺点是只能用于记录节点之间的一对多关系。每个子节点只能有一个父节点。
M&G公司可以使用此模型来描述其“订单”和“客户”实体之间的关系。客户连接到根节点,每个订单连接到相关的客户,而每个客户可以连接到多个订单。M&G可以根据需要继续添加节点。
面向对象模型
数据库开发者的另一个选择是面向对象模型。
面向对象模型基于面向对象的概念。在此模型中,每个对象被转换为一个类,该类定义了对象的特征和行为。
该模型的一个关键优势是,你可以定义对象之间不同类型的关联,例如聚合、组合和继承。这使得面向对象数据库适用于需要面向对象方法的复杂项目。
该模型也严重依赖于继承特性。继承是指一个类从另一个类继承其属性。你可以创建一个父类或超类(也称为基类)来保存公共属性。随后的每个子类都继承父类的属性。
然而,如果你使用此模型,则需要很好地理解面向对象原则和相关的编程技能。
M&G可以利用面向对象模型在类之间保留属性。他们可以创建一个名为“人员实体”的基类或父类,其中包含属性和操作。然后,“员工”和“客户”类从“人员实体”类继承这些属性和操作。因此,每个员工和客户都是一个人。
维度数据模型
最后,我们来了解基于两个关键概念的维度数据模型。
维度数据模型基于两个关键概念:维度和事实。
- 事实是从过程中获得的度量值。例如,从M&G业务数据中获得的销售事实。
- 维度定义了这些度量值的上下文,例如特定的销售期间。
因此,销售事实衡量的是M&G每周销售特定产品的数量。
该模型的关键优势在于,它优化了数据库以实现更快的数据检索,并重组数据以提高数据分析的效率。在本课程后面,你将更详细地探讨维度数据模型。
总结


本节课中,我们一起学习了可用于构建数据库系统的不同类型的数据模型,以及它们的一些关键优点和缺点。你在数据库建模的旅程中取得了很大的进步。
Python 96:关系数据库模型归一化回顾 🔄
在本节课中,我们将要学习数据库规范化的重要性及其应用方法。规范化是数据库设计中的核心过程,旨在通过结构化表来减少数据冗余、避免数据修改异常并简化数据查询。我们将回顾三种主要的范式,并通过实例演示如何应用它们来解决数据异常问题。
规范化的重要性
在数据库工程实践中,处理数据库表时,你经常会遇到可能导致数据不一致的异常。通过应用规范化过程,可以解决这些异常。

上一节我们介绍了规范化的基本概念,本节中我们来看看具体的规范化方法。
常见的数据库异常
以下是三种最常见的数据库异常:

- 插入异常:向表中插入新数据时,需要同时插入额外的、不必要的数据。
- 更新异常:更新表中某一列的一条记录时,发现这会导致表中其他多处数据也需要更新。
- 删除异常:删除一条数据记录时,会导致数据库中其他必需的数据集也被意外删除。
三级规范化方法
接下来,我们快速回顾如何使用数据规范化的三个级别来帮助解决或避免这些异常。
第一范式

第一范式,有时称为 1NF,它强制数据的原子性,并消除数据库表中不必要的重复数据组。换句话说,每个字段中每个值只能有一个实例。

重复的数据组会导致数据冗余和不一致。例如,在 M&G 公司的产品表中,“商品”列的同一单元格中存储了“订婚戒指”和“钻石戒指”两种产品。这违反了原子性规则。每列应只包含一个值的实例。
你可以通过创建两个新表来解决此问题:

- 创建一个
products表,用于保存与产品实体相关的所有数据。为该表分配一个product_id列,以标识每条唯一记录。 - 创建一个
clients表,用于保存与客户实体相关的所有数据。同样,创建一个ID列来标识每条唯一记录。
此解决方案从表中删除了所有不必要的重复数据。


第二范式
上一节我们介绍了如何确保数据的原子性,本节中我们来看看如何消除部分依赖。
要使表符合第二范式,即 2NF,它必须已经满足第一范式,并且不能包含任何基于函数依赖或部分依赖构建的关系。该表必须使用复合主键定义。
例如,M&G 的 delivery_status 表有一个由 order_id 和 product_id 组成的复合主键。为了符合第二范式,你必须识别是否存在任何非键属性仅依赖于复合键的一部分。
delivery_status 表中的 order_date 是一个非键属性。它可以仅通过 order_id 列来确定。这称为部分依赖。这在第二范式中是不允许的,因为所有非键属性必须通过使用复合键的两部分来确定。
可以通过从 delivery_status 表中移除 order_date 属性来解决此问题。换句话说,将 order_date 列保留在 orders 表中。现在,你的表符合第二范式:所有非主键属性都仅依赖于主键值。
第三范式

最后,我们来看第三范式,它主要解决传递依赖问题。

第三范式,即 3NF,旨在移除不必要的数据重复,确保数据的一致性和完整性。同样,一个表必须遵守第一和第二范式,然后才能应用第三范式。

第三范式解决了传递依赖问题。传递依赖是指非键属性相互依赖。
例如,M&G 的 orders 表中的 city 和 zip_code 是非键属性。然而,可以根据 zip_code 值来确定 city 值。如果你更改了 zip_code 值,就需要更改 city 名称值。这意味着一个非键属性依赖于另一个非键属性,这违反了第三范式。
为了解决这个问题,可以将表拆分为两个表:
- 一个
orders表,包含所有相关数据。 - 一个
city表,包含两列:zip_code和city_name。

现在,所有非键属性都仅由每个表中的主键决定。因此,这些表现在满足了 3NF 的要求。

总结
本节课中我们一起学习了数据库规范化的三个基本范式。应用这三种规范化形式是解决数据库中可能出现的任何异常的好方法。通过建模你的数据库,使其易于使用、访问和查询,可以解决任何数据冗余和不一致的问题。你现在应该熟悉了规范化的过程以及如何将其应用到你的数据库中。
Python 97:MySQL Workbench简介 🛠️
在本节课中,我们将学习MySQL Workbench这一数据库建模与管理工具。我们将了解其核心功能、安装步骤,并学习如何创建数据库连接和用户,为后续的数据库设计与管理工作打下基础。
概述
作为数据库工程师,您需要创建、实施和管理满足特定业务或组织需求的数据库系统。这些任务可能很复杂,但有一系列工具和技术可以支持您的工作。其中一个您将使用的工具就是MySQL Workbench。本节视频将探讨MySQL Workbench的基础知识,并学习如何使用该工具来帮助建模和管理数据库。
MySQL Workbench简介

MySQL Workbench是由Oracle开发的一款统一的数据库建模与管理可视化工具。它包含多个对创建、编辑和管理数据库非常有用的关键功能。

以下是MySQL Workbench的一些关键特性:
- 开源与跨平台:它可以在多种操作系统上使用。
- 简化设计与维护:它简化了数据库的设计和维护工作。
- 可视化SQL编辑器:它提供了可视化的SQL编辑器和其他支持开发者的工具。
- 代码辅助功能:它为编写SQL语句提供了自动完成和高亮显示功能。
- 数据迁移支持:它便于在不同版本的MySQL之间,以及MySQL与其他关系型数据库系统之间进行数据迁移。

在本课程中,您将使用MySQL Workbench来建模和管理MySQL数据库中的数据。但首先,您需要在您的操作系统上下载、安装和设置MySQL Workbench。
安装MySQL Workbench
上一节我们介绍了MySQL Workbench的功能,本节中我们来看看如何安装它。安装过程主要分为下载和运行安装向导两个步骤。
以下是安装步骤:

- 下载:从
dev.mysql.com/downloads下载一份MySQL Workbench。请确保为您特定的操作系统下载正确的版本。 - 安装:下载完成后,双击文件在您的计算机上进行安装。
- 运行安装向导:接下来,按照自定义设置跟随安装向导进行操作。运行向导时,请确保安装以下软件:MySQL Server、MySQL Workbench 和 MySQL Shell。
- 寻求帮助:如果遇到任何困难,请阅读MySQL Workbench安装文件以获取指导。
建立连接与创建用户
成功安装MySQL Workbench后,下一步就是启动它并建立数据库连接。我们将从打开软件和了解主界面开始。

启动程序并查看MySQL Workbench主屏幕。主屏幕包含欢迎信息、文档、博客和讨论论坛的链接,并提供对各种工具和功能的访问。

您可以使用主屏幕侧边栏访问MySQL连接、模型和MySQL Workbench迁移向导。选择“连接”选项可以查看连接到本地和远程MySQL实例的列表。

连接功能可用于加载、配置、分组和查看每个MySQL连接的信息。
“模型”部分显示最近使用的模型。每个条目列出了模型最后打开的日期和时间及其关联的数据库。您也可以选择加号来添加新模型,选择文件夹按钮来浏览和打开已保存的模型,或选择“更多”按钮来访问其他命令。

您还可以打开“迁移”选项卡,以显示使用向导的先决条件概述、启动迁移过程、打开ODBC管理器或查看文档。

创建新用户
创建新用户是连接到MySQL数据库最安全的方式,因为您可以管理用户角色和权限。请确保已选择MySQL连接。

以下是创建新用户的步骤:
- 使用root用户登录:首先,使用root用户登录MySQL服务器。输入您在安装MySQL时设置的root用户密码。如果需要,请保存该密码以备将来参考。
- 进入用户管理:接下来,在管理菜单下选择“用户和权限”,以查看当前数据库用户的列表。
- 添加账户:选择“添加账户”以添加新用户。这将打开一个新窗口,您可以在其中输入新用户的详细信息。
- 设置用户信息:将新用户命名为
admin1。输入密码并确认密码。 - 配置权限:您也可以使用此窗口控制用户权限。
- 账户限制:用于限制用户的最大查询数、更新数和连接数。
- 管理角色:此选项卡允许您为新用户分配角色或分配关联权限。在本例中,选择 DBA,该角色授予执行所有任务的权限。
- 架构权限:允许您控制新用户的访问权限。
- 应用创建:选择“应用”按钮以创建新用户。
创建新连接

创建用户后,下一步是从MySQL Workbench主屏幕创建新的MySQL连接。
以下是创建新连接的步骤:
- 打开连接表单:选择加号图标以打开“设置新连接”表单。
- 填写连接信息:填写表单以创建新的服务器实例。您现在可以使用以下值:
- 在连接名称中,使用
Test Server作为服务器实例名称。 - 在用户名文本字段中,键入
admin1。 - 对于表单的所有其他部分,您可以使用默认设置。
- 在连接名称中,使用
- 检查主机与端口:最后,确保您的主机名是
127.0.0.1,端口号是3306。 - 测试连接:单击“测试连接”按钮以检查设置是否有效。系统会提示您输入为
admin1用户设置的密码。 - 保存连接:如果设置正确,MySQL Workbench应确认连接成功。如果没有,请返回表单并检查您输入的信息是否正确。选择“确定”以保存连接。

您的新MySQL连接已添加到主屏幕。现在,您可以使用此连接开始处理数据库模式和SQL查询。
总结

本节课中,我们一起学习了MySQL Workbench工具的基本功能,并掌握了如何使用它来帮助建模和管理数据库。您现在应该熟悉了MySQL Workbench的基本特性,并知道如何用它来创建连接和管理用户。这为您理解高级数据建模奠定了良好的基础。
Python 98:MySQL Workbench中的数据管理 🗄️
在本节课中,我们将学习如何使用MySQL Workbench这一图形化工具来高效地创建和管理数据库系统。我们将涵盖创建数据库、设计表、建立视图、插入数据以及查询数据等核心操作。
创建数据库模式
首先,我们需要为项目创建一个新的数据库模式。在MySQL Workbench中,这被称为“Schema”。
- 连接到你的MySQL服务器实例。
- 在左侧的导航栏中,找到并点击“Schema”菜单。
- 在Schema工具栏中,选择“Create Schema”选项。
执行此操作将打开一个新窗口。在新窗口中,在“Database Name”文本框中输入 MG_schema,然后点击“Apply”按钮。
系统会生成一个名为 CREATE SCHEMA MG_schema`` 的SQL脚本。在出现的审核窗口中检查脚本,确认无误后,再次点击“Apply”按钮。随后会出现一个确认窗口,询问是否执行创建模式语句,点击“Finish”按钮即可完成创建。
现在,MG_schema 已成功创建并会显示在Schema列表中。你可能需要点击刷新图标来查看新创建的模式。
在模式中创建表
上一节我们创建了数据库模式,本节中我们来看看如何在其中创建数据表。M&G公司需要一个名为 staff 的表来存储员工信息。
以下是创建 staff 表的步骤:
- 在
MG_schema的子菜单中,右键点击“Tables”选项。 - 从出现的列表中选择“Create Table”。
- 这会打开一个新的表格设计窗口。在“Table Name”文本框中输入
staff。 - 在中间窗口的列详情部分,按以下要求填充列信息:
- staff_id:数据类型设为
INT,并勾选PK(主键)、NN(非空)、AI(自增) 复选框。 - full_name:数据类型设为
VARCHAR(100),并勾选NN。 - contact_number:数据类型设为
VARCHAR(20)。 - role:数据类型设为
VARCHAR(50)。 - email:数据类型设为
VARCHAR(100)。
- staff_id:数据类型设为
- 完成后,点击“Apply”按钮生成创建表的SQL语句。
- 在审核窗口中检查生成的SQL语句,确认无误后再次点击“Apply”执行,最后点击“Finish”保存更改。
现在,你可以在 MG_schema 中看到新创建的 staff 表。右键点击表名并选择“Table Inspector”或点击信息图标,可以查看表的结构,包括列、索引等信息。另一种快速查看表结构的方法是使用SQL编辑器执行 DESCRIBE staff; 命令。
创建视图
视图是一种虚拟表,基于SQL查询结果。接下来,我们为员工信息创建一个简化视图。
-
在
MG_schema的子菜单中,右键点击“Views”选项。 -
选择“Create View...”以打开SQL编辑器。
-
在编辑器中输入创建视图的SQL语句。例如,创建一个只显示员工全名和联系方式的视图:
CREATE VIEW Staff_View AS SELECT full_name AS ‘姓名‘, contact_number AS ‘联系电话‘ FROM staff; -
点击“Apply”按钮,在审核窗口中你可以看到生成的SQL代码。这里我们为列创建了别名(
AS ‘姓名‘),以便查询时更易读。 -
确认无误后,点击“Apply”执行,然后点击“Finish”。
现在,Staff_View 视图会出现在 MG_schema 的视图列表中。
向表中插入数据
有了表结构之后,我们需要向其中填充数据。虽然通常使用 INSERT INTO SQL语句,但MySQL Workbench允许你直接在表格网格中输入数据。
以下是插入数据的步骤:
- 在
MG_schema的staff表上右键点击。 - 选择“Select Rows – Limit 1000”。这会打开一个类似电子表格的界面。
- 直接在网格中输入员工记录数据。
staff_id列如果是自增的,可以留空或填0。 - 输入完数据后,点击“Apply”按钮。
- 系统会自动生成相应的
INSERT INTO语句。在审核窗口中检查该语句,然后再次点击“Apply”执行。 - 最后,点击“Finish”完成数据插入。
现在,员工记录已经成功存储到 staff 表中。
从数据库查询数据
最后一步是从我们创建的数据库和视图中查询数据。这需要使用MySQL Workbench的SQL编辑器。
-
点击工具栏上的按钮打开一个新的SQL编辑器标签页。
-
编写一个
SELECT查询语句来提取数据。例如,要查看视图中的所有数据:SELECT * FROM Staff_View; -
点击闪电图标或“Execute”按钮来运行查询。
-
查询结果将以表格网格的形式显示在编辑器下方。


本节课中我们一起学习了使用MySQL Workbench进行数据管理的完整流程:从创建数据库模式(Schema)和表(Table),到建立视图(View),再到插入(Insert)和查询(Select)数据。通过这些图形化操作,可以更直观、高效地完成数据库的构建与管理工作。
Python 99:MySQL Workbench中的数据库建模 🛠️
在本节课中,我们将学习如何使用MySQL Workbench这一专业工具来创建和管理数据库模型。我们将重点掌握正向工程和反向工程两大核心功能,它们能帮助我们将设计图转化为实际的数据库,或将现有数据库结构逆向为可视化的模型图。
概述
课程进行至此,你已经理解了数据库模型的重要性。那么,如何创建这些模型呢?你可以使用诸如MySQL Workbench这样的专业数据建模工具。本视频将指导你如何使用MySQL Workbench,并利用其正向工程与反向工程功能。
假设M和G需要开发一个基础数据库来维护他们的客户和订单信息。他们可以使用MySQL Workbench创建模型,然后利用正向工程功能将数据模型转化为SQL架构,并自动在MySQL中实现。
创建新的数据模型
上一节我们介绍了课程目标,本节中我们来看看如何从零开始创建一个新的数据模型。
在MySQL Workbench的主屏幕,点击左侧边栏的“Models”视图,然后点击“Models”旁边的加号图标。这个操作会打开一个新窗口,并创建一个名为myDb的新架构。
双击架构名称,将其修改为mengeta_store_gallo。
设计ER图
接下来是创建数据模型图。这张图对于使用正向工程功能至关重要。你可以在MySQL Workbench中创建数据模型,然后将其转化为可在MySQL中自动实现的SQL架构。
首先,双击“Add Diagram”来创建ER图。这个操作会打开ER图设计器页面。
现在你需要创建表。点击“Add Table”图标,然后在视图区域内点击一个方格。这个操作会创建一个表实体。
双击该实体以加载表编辑器。将默认的table1名称改为customers。
定义表结构
以下是向customers表添加列的步骤:
- 双击一个单元格,这会创建一个默认的
idcustomers列。将其名称改为customer_id。 - 保持数据类型为
INT(整数)。 - 勾选
PK(主键)、NN(非空)和AI(自增)复选框。 - 再添加三个列:
full_name、contact_number和email。 - 根据需要设置数据类型(例如
VARCHAR),并将这三列都标记为NN(非空)。
请遵循相同的步骤创建orders表,并根据需要设置其列的数据类型。
建立外键关系
你还需要为orders表创建外键。在窗口底部的“Foreign Keys”选项卡中,将表的customer_id列定义为外键。
- 在“Foreign Key”文本字段中输入
CustomID_FK。 - 双击“Referenced Table”对应的字段,然后选择
customers表。 - 勾选
customer_id作为被引用的列。 - 将其标记为
ON UPDATE CASCADE和ON DELETE CASCADE。
至此,你已经拥有了一个包含customers和orders表的MG架构ER图可视化表示。
通过点击 File -> Save As 保存你的工作,并将其命名为Mangeta_Gallo_Model。
正向工程:将模型同步到数据库
现在你已经创建了数据模型,接下来可以使用正向工程功能将其同步到MySQL服务器。
选择 Database 选项卡,然后从菜单中选择 Forward Engineer 选项。这将打开“Forward Engineer to Database”向导。
选择你之前创建的用于连接MySQL服务器的连接。保持默认设置不变,点击 Next。
向导会列出一些高级选项,目前可以忽略,直接点击 Next。
一个新窗口“Select Objects to Forward Engineer”会出现,并带有一系列选项。勾选“Export MySQL Table Objects”框,然后点击 Next。
下一步将显示将在MySQL服务器上执行以创建内部架构的SQL脚本。请审阅该脚本,确保它能按需创建架构。
点击 Next 来正向执行SQL脚本。会出现一条消息,显示“Forward engineer finished successfully”。点击 Close 关闭向导。
现在,M和G的数据库已在MySQL中创建成功。你可以在导航器部分的架构列表中查看,或在Workbench的SQL编辑器中执行SHOW DATABASES;语句来确认。
反向工程:从数据库生成模型
M和G还需要使用MySQL Workbench进行反向工程来构建数据模型。这意味着从现有数据库生成数据模型ER图。
上一节我们实践了正向工程,本节中我们来看看反向工程的操作流程。
第一步是进入 Database 选项卡,然后选择 Reverse Engineer 选项。确认连接详情无误后,点击 Next。每个连接都必须正确配置才能与MySQL服务器通信。如果对现有连接不满意,可以选择另一个,然后点击 Next。
出现“Execution completed successfully”消息后,点击 Next。此时会显示服务器上可用的架构列表。
选择你想要进行反向工程的数据库架构,然后点击 Next。
屏幕上出现“Retrieval completed successfully”消息,点击 Next。
一个新屏幕出现,你可以在其中选择“Select All Objects”。屏幕确认所有对象都已检索,点击 Execute。
一旦检索过程成功执行,会显示一条“Operation completed successfully”的消息。选定的对象现已成功反向工程。再次点击 Next。
最后一个屏幕会显示导入摘要。点击 Finish 完成整个过程。
MySQL Workbench会从内部的MySQL架构创建新的ER图。你可以将数据模型打印为PNG图像,与他人分享,或者应用更改并通过正向工程功能将其推送到数据库。

总结

本节课中,我们一起学习了如何使用MySQL Workbench的强大功能。M和G现已使用MySQL Workbench在其数据库中开发了一个基础架构。你现在也应该掌握了如何利用MySQL Workbench中的反向工程功能来开发数据模型图。
做得好!


Python 100:数值函数 📊
在本节课中,我们将学习MySQL中的数值函数。数值函数是处理数据库中数字数据的强大工具,它们可以帮助我们执行计算、汇总和转换等操作。我们将重点介绍两类数值函数:聚合函数和数学函数,并通过珠宝店M&G的业务场景来理解其实际应用。
函数概述
在之前的课程中,我们已经接触过一些基本函数。这里快速回顾一下,在MySQL中,“函数”指的是一段执行特定操作并返回结果的代码。有些函数接受参数,有些则不需要。函数对于处理和操作数据库表中的数据非常有用。
MySQL函数大致可以分为以下五类:
- 数值函数
- 字符串函数
- 日期函数
- 比较函数
- 控制流函数
本节课我们将详细探讨数值函数。
数值函数分类
MySQL的数值函数主要分为两类:
- 聚合函数:用于对一组值进行计算。
- 数学函数:用于对数据执行基本的数学运算。
您应该已经对聚合函数有所了解,我们在之前的课程中曾结合SELECT语句使用它们来计算汇总值。
以下是常用的聚合函数:
SUM:求和AVG:求平均值MAX:求最大值MIN:求最小值COUNT:计数
现在,让我们来看看一些常见的数学函数。ROUND函数可以将数字四舍五入到指定的小数位数。MOD函数则可以返回一个数除以另一个数后的余数。
函数语法与应用
这些函数可以帮助M&G珠宝店在计算每位客户平均消费金额的同时,执行额外的数据处理任务。那么,如何在MySQL数据库中使用这些函数呢?您可以将它们嵌入到SQL的SELECT语句中。
ROUND函数语法:
SELECT ROUND(column_name, decimal_places) FROM table_name;
语法解析:以SELECT命令开始,后跟要查询的列名,然后调用ROUND函数并加上括号。括号内写入必需的参数:第一个参数可以是列名或任何数值,第二个参数必须是小数位数。最后,使用FROM关键字指定表名。
MOD函数语法:
SELECT MOD(column_name, divisor) FROM table_name;
语法解析:与ROUND类似,只是调用MOD函数。在括号内,指定要计算的列或值,以及作为除数的数字。最后指定包含数据的表名。请注意,第一个参数可以是表列或任何数值,而第二个参数必须是除数。
实战演练:M&G的业务场景
让我们通过M&G珠宝店的两个具体任务,来探索如何使用这些数值函数。
任务一:计算客户平均消费(四舍五入)

M&G正在审查客户订单,需要确定每位客户在店内的平均消费金额。公司有一个名为Client_Orders的表,其中Average_Cost列显示了每位客户的平均消费。
目标:将平均消费金额四舍五入到两位小数。
解决方案:
使用ROUND函数。编写SQL语句:SELECT后跟列名,然后对Average_Cost列调用ROUND函数。在括号内,将Average_Cost列作为第一个参数,数字2作为第二个参数(表示保留两位小数)。接着使用FROM关键字指定Client_Orders表,最后按Client_ID分组。
执行查询后,输出将显示所有平均值都被缩减为两位小数。
任务二:识别偶数订单商品
M&G正在补货,需要找出哪些商品的订单数量是偶数。所需数据在MG_Orders表中,相关列包括Order_ID、Item_ID和Quantity。
目标:判断订单数量是奇数还是偶数。
解决方案:
使用MOD函数。将数量除以2,余数即为判断依据。编写SQL语句:SELECT后跟列名,然后调用MOD函数。将Quantity列作为第一个参数,数字2作为第二个参数。
执行查询后,如果某行数据除以2后没有余数,则返回值为0(表示偶数);否则返回余数值。输出结果显示,商品1、3、5和6的订单数量为偶数。

总结
本节课我们一起学习了MySQL中的数值函数。我们回顾了函数的基本概念,重点介绍了两类数值函数:聚合函数(如SUM、AVG)和数学函数(如ROUND、MOD)。通过M&G珠宝店的实际业务案例,我们练习了如何将这些函数嵌入SELECT语句中,以完成计算平均消费(四舍五入)和判断订单数量奇偶性等任务。掌握这些函数对于在MySQL数据库中进行有效的数据处理和操作至关重要。
Python 101:数据仓库概述 📊
在本节课中,我们将要学习数据仓库的基本概念。我们将了解数据仓库是什么,它与常规数据库有何不同,并探讨其核心特征以及数据分析中可能遇到的不同数据类型。
什么是数据仓库?🏗️
常规数据库实时收集、存储和处理来自事务的数据。但是,如果需要聚合和分析来自多个来源的数据,数据仓库就是完美的解决方案。它可以聚合来自一系列来源的数据,并使用不同的工具进行分析。
接下来,我们将更详细地探讨数据仓库的概念。
数据仓库与常规数据库
数据仓库是一个集中式的数据存储库,它聚合、存储和处理来自多个来源的大量数据。它将数据分析工作负载与常规数据库管理系统的标准事务工作负载分离开来。
公式:数据仓库 = 集中式存储库 + 多源数据聚合 + 数据分析

用户随后可以查询这些数据以执行数据分析。这种类型的数据库被称为联机分析处理。
常规数据库侧重于实时收集、存储和处理数据。它也被称为联机事务处理。
数据仓库的四大特征
数据仓库有四个关键特征:面向主题、集成性、非易失性和时变性。让我们从面向主题开始,逐一探讨这些特征。
面向主题

构建数据仓库时,需要选择一个或多个要探索的主题领域。例如,一家公司可以构建一个专注于销售的数据仓库,然后利用该仓库查找所有与销售流程相关的信息,例如最畅销和最滞销的产品。
集成性
集成性意味着数据仓库整合了来自一系列不同来源的数据。数据必须以一致的格式进行集成。集成数据还必须解决诸如命名冲突和数据类型不一致等问题。
非易失性
非易失性意味着数据一旦加载到数据仓库中就不应被删除。数据仓库的目的是分析现有数据。拥有的数据越多,分析结果就越好。
时变性
数据仓库会聚合长时间段内的数据,以便能够衡量数据随时间的变化。这有助于用户发现数据元素之间的趋势、模式和关系。
上一节我们介绍了数据仓库的四大特征,本节中我们来看看数据仓库可能处理的不同数据类型。
数据分析中的数据类型
数据仓库会遇到三种形式的数据:结构化数据、半结构化数据和非结构化数据。以下是每种类型的简要说明。
结构化数据
这是以结构化格式呈现、具有明确定义数据模型的数据。关系数据库模型通常用于结构化数据。其组织有序的表格帮助用户使用SQL访问、管理和搜索数据。数据仓库通常使用结构化数据。这种数据类型为特定目的而组织,因此更容易从中获得洞察并找到特定问题的答案。
代码示例:SQL查询结构化数据
SELECT product_name, SUM(sales_amount)
FROM sales_table
GROUP BY product_name
ORDER BY SUM(sales_amount) DESC;
半结构化数据
半结构化数据是仅部分结构化的数据。进行数据分析需要付出更多努力。电子邮件消息就是半结构化数据的一个例子。它可以包含发件人和主题等结构化数据,但正文是非结构化的,可以包含文本、图像和视频等几种不同类型的数据。
非结构化数据
这种数据类型不遵循任何特定的预定义数据模型。它可以包括任何类型的数据,如文本、视频或音频。这种数据可以在不应用任何数据模型的情况下收集和存储,但分析非结构化数据需要高级数据分析机制,如机器学习和数据挖掘。半结构化和非结构化数据更适合数据湖。数据湖类似于数据仓库,但它可以处理非结构化数据。数据科学家更广泛地使用数据湖。由于准确性考虑,企业更倾向于使用结构化数据和数据仓库。
总结

本节课中我们一起学习了数据仓库的基础知识。你现在应该能够解释什么是数据仓库,概述其主要特征,以及数据分析中可以使用的不同类型的数据。这是很大的进步,我期待在后续课程中继续引导你探索这些主题。
Python 102:数据仓库架构 🏗️
在本节课中,我们将要学习数据仓库的架构。我们将了解其核心组件如何协同工作,以支持数据的收集、集成和分析。
在本课程的这个阶段,你应该已经熟悉了数据仓库的概念。但你或许仍有疑问:数据仓库具体是什么样子?它又是如何工作的?


在本视频中,你将探索数据仓库的架构,并理解其各个组件如何协同工作,以促进数据的收集、集成和分析。

以 Global Superstore 公司为例,他们已经开始构建一个能够聚合、集成和分析数据的数据仓库,以辅助其商业决策。作为一名数据库工程师,理解数据仓库的架构至关重要。因此,让我们一同探索 Global Superstore 数据仓库的架构,并了解其工作原理。
让我们首先快速了解一个典型数据仓库架构的目的和基本构成。
数据仓库的架构必须能够控制来自不同数据源的数据流。它需要能够处理接收到的数据,并以一致的格式进行集成。这样,数据仓库的用户才能进行数据分析并提取有价值的见解。
为了促进这一过程,数据仓库的架构由几个不同的组件构成。每个组件都在数据仓库中扮演着关键角色,以支持数据分析。这些组件包括:数据源、数据暂存区、数据仓库本身以及数据集市。一旦数据在这些组件中被收集和集成,数据仓库用户就可以进行数据分析并展示他们的发现。



接下来,让我们逐一探索这些组件,了解它们如何为数据分析过程做出贡献。


数据源 📥
数据仓库架构的第一个组件是其获取见解所依赖的数据源。这些数据源包括:
- 外部来源:例如 Global Superstore 的在线调查或社交媒体数据。
- 内部来源:例如在公司内部收集的客户和产品信息。
- 运营数据:由日常业务活动(如客户订单)产生的数据。
- 平面文件:这些是没有内部结构的文件,例如客户在线行为数据或日志条目。
确保数据源的准确性至关重要,这可以避免不相关或低质量的数据分析。
数据暂存区 ⚙️




下一个组件是数据暂存区。数据暂存区包含一系列被称为 ETL(提取、转换、加载)流水线的过程。我们将在本课稍后部分更详细地探讨这些术语。

数据存储 🗄️
在获取并暂存数据之后,下一个阶段是存储数据。数据存储在数据存储组件中。这是一个作为数据仓库基础的中央数据库存储库。它使用关系数据库来组织数据。该组件还包含一个元数据存储库,用于保存关于数据的各种信息,例如数据的来源、数据的特征、数据存储的表及其属性。

那么,在数据仓库的语境中,元数据意味着什么呢?元数据本质上是数据仓库中数据的“目录”。它帮助数据库工程师管理和跟踪其源系统、方法和过程中的变更。例如,Global Superstore 的元数据包含诸如数据来源、每个文件的创建时间、创建者以及其他重要信息。
数据集市 🛒
数据仓库中的下一个组件是数据集市。这些是面向主题的数据库,旨在满足特定用户群体的需求。每个数据集市都包含一个数据子集,专注于业务或组织的特定部分。例如,Global Superstore 的数据集市与特定的部门和业务职能相关。他们可以利用这些集市对业务的特定部分进行聚焦的分析处理。
数据分析与呈现 📊
最后,一旦数据准备就绪,就可以进行数据分析。数据分析使用不同的分析技术(如数据挖掘)来执行。分析完数据后,就可以进行数据呈现。数据可以以报告的形式呈现,例如交互式报告、分析报告或静态报告。Global Superstore 的数据分析师可以使用不同的技术来分析其存储库中的数据,然后生成提供关于销售额、利润和其他重要业务方面信息的报告。




上一节我们介绍了数据仓库的各个核心组件,本节中我们来看看在创建和使用数据仓库架构时应遵循的一些最佳实践。
以下是构建数据仓库架构时应遵循的一些关键最佳实践:
- 架构优先:始终将分析型操作和事务型操作分离。
- 利用可扩展的解决方案:使数据仓库能够处理日益增长的数据量。
- 构建灵活的架构:能够纳入和实施新的功能。



此外,还应遵循其他一些最佳实践,例如:
- 确保你的架构包含数据安全功能。
- 开发一个简单且灵活的架构,能够处理不同形式的数据。
- 创建一个易于理解、实施、使用和管理的数据仓库。
- 记录数据仓库的开发过程,这有助于更容易地纳入新功能。





本节课中,我们一起学习了数据仓库的架构。你现在应该已经熟悉了数据仓库的架构,并且能够解释其各个组件如何协同工作,以促进数据的收集、集成和分析。出色的工作。
Python 103:案例研究 - 真实世界的数据项目 🗃️
在本节课中,我们将要学习一个在大型科技公司中至关重要的概念:ETL(提取、转换、加载)管道。我们将探讨它的定义、核心组成部分、目的以及在实际应用中面临的挑战。
概述

处理超大型数据库时,从中获取数据非常困难。ETL管道是确保不同产品能够快速获取所需数据的关键方法之一。
什么是ETL管道?
ETL代表提取(Extract)、转换(Transform)和加载(Load)。这是一种将数据传输到特定区域的常见方式。
其基本流程如下:首先有一个数据源,然后可能有一个数据暂存区,最后是数据的使用者。将流程拆分为不同的数据消费者可以实现两个目标。
- 第一,将原始数据作为备份存储在数据仓库中。
- 第二,在需要使用时,提取并转换数据,然后加载给需要该数据的消费者。

ETL管道的目的
ETL管道的目的因具体用途而异,但其根本要点要么是将大量不同的数据源汇集在一起,要么是将非常庞大的数据源从数据使用者那里抽象出来。
- 提取:汇集所有数据源。
- 转换:进行数据验证、清理、清洗,可能还包括加密。
- 加载:最终使用者实际获取数据的地方。

具体用途取决于实际情况。这意味着ETL管道是一个用于解决许多不同数据问题的非常通用的流程。
ETL管道的设计与优势

ETL管道的部分意义在于,将所有可能在不同系统下构建的不同数据源整合到一个系统中,供特定的消费者使用。
这允许并行化处理。因此,设计决策通常围绕以下几点做出:最终消费者需要什么?我从哪里获取数据?如何组织这些数据?以及什么方式能带来最佳性能?
处理数据管道的常见挑战
处理数据管道时,最常见的问题之一有时是处理数据量和数据源本身。这可能使得确保管道是最新的,并在使用时拥有所需数据变得非常困难。


理解延迟以及这些管道的工作原理至关重要,以确保你不会期望数据消费者能够获取实际上对他们不可用的数据。
应对变更与维护
对数据库的更改可能会触发对你已构建的数据管道进行更改的需求,这取决于消费者的需求以及变更的内容。
因此,这需要对管道的需求、其目标有深刻的理解,并且该管道的利益相关者需要有明确的所有权意识。这类更新一直在发生,并可能触发产品团队中各种不同的变化。这需要对ETL管道有很强的所有权、责任心和理解力,以便在变更发生时知道需要做出哪些调整来适应。
总结
本节课中,我们一起学习了ETL管道。世界上有大量的数据,事实上,数据量多到无法存储在单个数据库中。因此,在大数据、云计算和元宇宙的世界里,ETL管道是一个绝对基础的核心环节。
Python 104:维度数据建模基础 📊
在本节课中,我们将要学习维度数据建模的基础知识。这是一种专门为数据仓库和数据分析设计的模型,旨在优化数据访问和查询性能。
到目前为止,在你的数据库工程学习旅程中,你已经学习并使用了不同的数据模型,例如实体关系模型和面向对象模型。但这些模型是为实时事务处理而构建的。当处理数据仓库或数据分析时,你需要一个能够为特定分析优化数据访问和查询的模型。

什么是维度数据模型?
维度数据模型是一种基于维度和事实这两个核心概念的数据模型。让我们来仔细看看这两个概念。


维度代表了数据的不同元素。维度为你的度量定义了上下文或视角。在Global Superstore的数据库中,时间和地点就是维度数据元素的典型例子。

事实代表了数据库中可量化的数据。Global Superstore事实的典型例子包括已售产品数量和已获利润。
事实表中包含两种度量:存储度量和计算度量。


以下是这两种度量的说明:
- 存储度量:是存储在数据仓库中的聚合度量,例如销售数据和产品价格。这些数据从数据源加载并存储在数据库仓库中。
- 计算度量:是从其他度量计算得出的。例如,Global Superstore可以通过从售价中扣除产品成本来计算利润。这些度量通过依赖于数据仓库数据库中编程的计算规则的查询来执行。

模型结构与层次分析
上一节我们介绍了维度和事实的概念,本节中我们来看看维度数据模型的结构。
一个维度数据模型由事实表和维度表组成。维度表包含维度数据元素,并且可以构建为数据的层次结构。这有助于进行不同级别的数据分析。你可以在层次结构中导航以找到所需的数据,例如,你可以向下钻取或向上汇总数据元素。
事实表则包含度量数据。例如,Global Superstore可以利用这种结构来查找他们在特定时间点的平均销售额。他们可以在不同的维度上下文中探索数据,并在不同层级间钻取。他们可以使用时间和地点维度来探索按年或按城市的平均销售额数据。

然后,他们可以向下钻取这些数据,找到每月、甚至每周或每天的平均销售额。
设计最佳实践与模式
在开始设计维度数据模型之前,有几项最佳实践需要遵循。你需要明确你想要考察哪些业务活动,并且需要知道哪些维度能为你提供最有意义和最有用的上下文。同时,确保你以易于理解、访问和查询的方式组织数据。
设计维度数据模型的一个常用方法是使用模式。数据仓库中最广泛使用的模式之一是星型模式。

星型模式是设计数据仓库中数据的常见模型。它是一种简单的维度数据模型,由组织成星形的事实表和维度表组成。一个或多个事实表位于模式的中心,连接到一个或多个维度表。


Global Superstore可以使用星型模式来组织他们的维度数据模型。销售事实表位于图的中心,连接到多个维度表:供应商、客户、产品、时间和地点。

另一种可用于设计维度数据模型的模式是雪花模式。它之所以被称为雪花模式,是因为模式图类似于雪花。
使用雪花模式时,你应该对维度表进行规范化以消除数据冗余。规范化的最佳方法是将维度数据分组到多个简单的子维度表中。这种模式的缺点是它增加了维度表的数量,并且需要更多的外键来连接表。因此,在执行数据分析时,需要更复杂的查询来连接记录。
例如,Global Superstore可以使用该模式将其产品维度表规范化为三个表:产品表、子类别表和类别表。

总结

本节课中,我们一起学习了维度数据建模的基础知识。你现在应该理解了维度数据建模的概念,并且能够解释星型模式和雪花模式是如何工作的。维度模型通过围绕事实组织维度,为数据分析提供了高效、直观的结构。
Python 105:维度数据建模实践 📊
在本节课中,我们将学习如何构建一个维度数据模型。我们将回顾维度数据模型的核心概念,并详细介绍构建该模型的四个关键步骤。通过一个名为“全球超市”的案例,我们将一步步了解如何应用这些步骤来解决实际的业务问题。
在本课程的这个阶段,你应该已经熟悉了维度数据模型及其相关的许多关键概念。

但是,如何构建一个维度数据模型呢?构建维度数据模型的过程围绕着四个关键步骤展开,这被称为金博尔维度数据建模法。
在本视频中,你将探索这种方法,并详细回顾这四个步骤。让我们从了解全球超市及其对维度数据模型的使用开始。
上一节我们介绍了课程目标,本节中我们来看看具体的案例背景。


全球超市希望进行数据分析,以了解他们近期的销售数据。


这需要构建一个维度数据模型,该模型将帮助他们理解其业务以及影响其销售额和利润的因素。
在探索全球超市的流程之前,让我们快速回顾一下维度数据模型的目的,并概览这四个关键步骤。
维度数据模型必须专注于业务或组织的特定方面,以解决具体问题。


该模型是使用一种系统化的方法创建的,该方法围绕着四个关键步骤。

这些步骤包括:业务过程、粒度、维度和事实。
每个步骤都是一个选择。你需要选择一个你的维度模型必须调查的业务过程。
然后,你需要选择能够提供所需答案的事实和维度。

上一节我们概述了四个步骤,本节中我们将逐一深入探讨,理解它们如何为构建维度数据模型的过程做出贡献。
以下是构建维度数据模型的四个核心步骤:


-
选择业务过程
构建维度数据模型时,第一步是识别或选择要解决的具体业务过程。 -
确定数据粒度
一旦确定了过程,你就可以确定数据模型中数据的粒度。 -
选择维度
流程的下一步是选择维度。在这一步中,你需要选择相关的维度。 -
确定事实
既然你已经确定了业务过程、粒度和维度,那么是时候确定事实了。这基本上是回答“你想测量什么?”这个问题。



现在,让我们通过全球超市的案例来具体应用这些步骤。



第一步:选择业务过程
全球超市已决定要解决的业务过程是他们的销售活动。
第二步:确定数据粒度
一旦决定了过程,接下来就需要选择所需的详细程度。这被称为粒度。数据仓库需要何种粒度或详细程度来解决你的过程问题?以及解决问题所需的最低详细程度是什么?

例如,全球超市需要在年度和日度级别上分析其销售数据。他们还需要在全球和本地级别上调查这些数据。
第三步:选择维度
在这一步,你需要选择相关的维度。换句话说,你需要在什么背景下探索你的业务活动?
正如你已经知道的,全球超市需要分析他们的销售数据,并且他们需要在产品、客户、时间和地点的背景下分析这些数据。

第四步:确定事实
你需要选择包含数值数据的度量,并用这些属性填充你的事实表。
例如,全球超市需要使用维度表(位置、产品、时间)来探索他们的事实。他们可以展示每个维度如何影响销售。


他们还可以包含提供每个维度有用信息的相关属性。
上一节我们完成了四个步骤的选择,本节中我们来看看如何将它们整合成最终的模型。
一旦你决定了需要调查的业务过程的哪个方面,并选择了相关的粒度、事实和维度,你就可以创建你的模式。
安排你的维度和维度表。全球超市可以在星型模式中安排他们的维度和度量。
他们的模式在四个不同维度(客户、产品、地点和时间)的背景下检查其销售活动的表现。在每个维度内,都有一组针对所需数据的相关属性。
全球超市根据其业务需求逐步确定了他们的维度和度量。他们现在可以执行不同形式的数据分析来实现其目标。




总结

在本节课中,我们一起学习了使用系统化方法构建维度数据模型。你现在应该熟悉了构建维度数据模型的四个关键步骤:选择业务过程、确定数据粒度、选择维度和确定事实。你也应该能够识别并解释每个步骤中围绕数据必须做出的决策。你在高级数据建模的旅程中取得了巨大进展。
Python 106:数据仓库与维度建模小结 📊
在本模块中,我们深入探讨了数据仓库的架构,并学习了如何构建维度数据模型。现在,让我们一起来回顾本模块的核心知识与技能。
概述 📋
上一节我们完成了对数据仓库架构的探索,本节将对整个模块的内容进行总结。我们将回顾数据仓库的定义、关键特性、数据类型、架构组件,以及维度数据建模的基础知识、结构和实践步骤。
数据仓库核心概念 🏗️
数据仓库是一个集中式的数据存储库,它从多个来源聚合、存储和处理大量数据。用户可以查询这些数据以执行数据分析。
数据仓库由四个关键特性定义:
- 面向主题:它提供关于选定主题或领域的信息。
- 集成性:它整合来自一系列不同来源的数据。
- 非易失性:数据以加载到数据仓库时的状态被维护。
- 时变性:它聚合长时间段的数据以衡量变化。
数据类型 📂
数据仓库会遇到不同形式的数据,以下是主要类型:
- 结构化数据:以定义良好的结构化格式呈现的数据,易于访问、管理和搜索。
- 半结构化数据:仅部分结构化的数据。它更灵活,但分析起来也需要更多努力。
- 非结构化数据:可以包含没有任何预定义模型的任何类型的数据,但分析非结构化数据比结构化和半结构化数据要困难得多。
数据仓库架构 🧱
在回顾了数据仓库的基础知识后,我们接着探讨了其架构。数据仓库的架构侧重于设计那些在数据仓库中聚合、集成和分析数据的组件。它说明了数据从不同来源的流动,然后处理和集成这些数据,以便用户能够执行数据分析。
数据仓库的架构由以下组件构成:
- 数据源:由组织赖以获取洞察的数据组成。
- 数据暂存区:这是通过ETL(提取、转换、加载) 过程为分析准备数据的地方。
- 数据仓库:数据存储的地方。
- 数据集市:这些是面向主题的数据存储,满足特定用户的需求。
一旦数据在这些组件中被收集和集成,数据仓库用户就可以执行数据分析并呈现他们的发现。在创建和使用数据仓库架构时,遵循最佳实践并记录其开发过程非常重要,以便能够根据需要将新功能纳入架构。
维度数据建模 📐
在接下来的课程中,我们学习了维度数据建模。本课首先概述了维度数据建模的基础知识。
维度数据模型是一种基于维度和事实的模型。
- 事实代表度量,即可量化的数据。
- 维度定义了可以探索度量的上下文。
度量分为两种:
- 存储度量:包括可以存储在数据仓库中的聚合度量。
- 计算度量:侧重于使用其他度量的数据计算得出的数据。
我们还回顾了维度数据模型的结构。维度表可以使用数据的层次结构来构建。这种结构允许不同级别的数据分析。您可以在数据元素中下钻或上卷以找到所需的数据。
维度数据模型也使用模式来设计,例如星型模式。您也可以使用雪花模式。
维度建模实践步骤 🛠️
接着,我们探讨了维度数据建模的一些实践示例。我们了解到,在创建模型时必须遵循四个关键步骤:
- 确定要解决的业务过程。
- 选择粒度。
- 选择相关维度。
- 确定事实表中的度量。
然后,我们进行了一项练习,利用在本模块中获得的知识和技能创建了自己的维度模型。
总结 🎯
在本模块中,我们一起学习了数据仓库及其架构的基础知识,以及维度数据建模的基本原理。现在,您应该已经熟悉了这些核心概念。


出色的工作!我期待在下一模块中继续指导您,在那里您将学习数据建模背景下的高级数据分析。
Python 107:数据分析概述 📊
在本节课中,我们将要学习数据分析的基础知识,包括数据分析的核心类型以及如何对数据进行测量。我们将通过一个名为“全球超市”的案例,来理解如何利用数据洞察来改进业务。
你的数据库从各种不同的来源收集并存储着源源不断的数据。正如你现在应该了解的,这些数据的真正价值在于你如何利用它。当数据能产生有助于改进服务、制定计划和降低风险的洞察时,其价值最大。所有这些洞察都是通过数据分析和高级数据分析产生的。在接下来的时间里,你将回顾数据分析的基础知识,并探索不同类型的数据测量方法。
在全球超市,他们一直在收集大量数据并将其存储在数据库中。这些数据代表着一项重要资产,商店可以利用它来理解和改进其业务活动和绩效。为了充分利用这些数据,他们需要执行不同类型的数据分析,并恰当地测量数据。让我们看看全球超市如何能最大限度地利用其数据,并从回顾数据分析及其可使用的数据分析类型开始。




数据分析类型回顾




正如你从前面的课程中应该了解的,数据分析涉及分析数据以获取有用的信息和有价值的洞察。你可以通过数据分析工具和数据分析来最有效地利用数据。


到目前为止,你已经遇到过并在其他课程中使用过几种关键类型的数据分析。让我们简要回顾一下这些类型。
以下是几种主要的数据分析类型:
- 描述性数据分析:以描述性格式呈现数据。
- 探索性数据分析:用于建立不同变量之间的关系。
- 推断性数据分析:侧重于小样本数据以进行推断。
- 预测性数据分析:识别数据中的模式以对未来表现进行预测。
- 因果性数据分析:探索变量之间的因果关系。








在进行这些类型的数据分析之前,你首先需要了解你正在处理的数据类型,并问自己应该对其应用何种测量方法。
数据类型与测量尺度
你需要问的关于数据的另一个关键问题是:它是定量数据还是定性数据。



- 定量数据指的是数值型数据。这种数据可以被计数或量化。在全球超市的例子中,这包括每天购物的平均顾客数或每笔交易的平均成本。
- 定性数据指的是非数值型数据。这是文本和描述性数据,例如关于产品质量属性的信息。例如,全球超市的定性数据包括类别名称或产品描述,如“家具”或“办公用品”。





一旦确定了正在处理的数据类型,你就需要组织、识别和分析你的数据。你可以使用四种不同的测量尺度来执行这些操作。


以下是四种主要的测量尺度:

- 定类尺度:此尺度描述非数值型数据的“身份”属性。它纯粹是描述性的,意味着它只标识数据。在全球超市的例子中,他们可以使用此尺度来标识库存中的产品,如“椅子”或“桌子”。每个产品都是一个定类数据单位。
- 定序尺度:这是一种定性数据类型尺度,它将数据按特定排名顺序排列。然而,它不包含决定数据元素之间差异的明确标准。例如,全球超市可以使用评级值对椅子进行排名。他们可以用值1代表顶级质量产品,2代表非常好产品,3代表好产品,依此类推。然而,并没有精确的标准来确定每个值之间的测量差异。
- 定距尺度:此尺度包含定类和定序数据尺度的属性。其关键特征是,数据点之间的差异可以使用特定标准清晰识别。该尺度也可以包含正数和负数,并且零不代表绝对的“真”值。全球超市可以使用定距尺度提供从10到-10的产品反馈。
- 定比尺度:此尺度是一种定量数据类型,包含来自定类、定序和定距测量尺度的属性。它定义了数据的身份,对数据进行分类排序,并标记清晰的间隔。然而,它拥有一个绝对的零值。在全球超市,他们可以使用定比尺度来标记产品的重量。例如,一张小桌子重20公斤,一张中等大小的桌子重40公斤,而一张更大的桌子总重60公斤。在这种情况下,变量之间存在明确的顺序,并且每次测量之间有20公斤的相等距离。因此,所有数据点都可以被准确测量。

总结


本节课中,我们一起学习了数据分析的基础知识。你现在应该熟悉了数据分析的基本概念,能够识别不同的数据类型,并解释不同类型的数据测量尺度。掌握这些基础知识是进行有效数据分析的第一步。
Python 108:数据挖掘与机器学习 🧠💾
在本节课中,我们将要学习数据挖掘与机器学习的基本概念。随着数据量的增长,分析和理解数据变得愈发困难。数据库工程师依赖这些高级数据分析方法来发现数据中的模式、范式和趋势,从而帮助企业和组织理解绩效并制定可执行的预测计划。
数据挖掘与机器学习的定义 🔍
上一节我们介绍了数据分析的重要性,本节中我们来看看数据挖掘与机器学习这两个核心概念。虽然这两个术语经常互换使用,但它们的工作方式截然不同。
数据挖掘是检测数据中模式的过程。基于这些模式,可以获得洞察、做出判断并交付预测。
机器学习是教会计算机如何学习的过程。具体来说,它涉及教会机器确定概率并进行预测。


机器学习的主要方法 🤖
以下是机器学习的两种主要方法:
- 监督式机器学习:基于给定的标签对数据进行分类。例如,给计算机提供标记为“椅子”和“桌子”的图片,计算机学习根据这些标签来识别、分类和分组产品图片。
- 无监督式机器学习:基于共享特征对数据进行分类,但不使用标签。例如,计算机根据图片中的形状,学习识别和分类椅子、桌子和书桌等物体的图片。
数据挖掘模型示例 📊
机器学习在处理数据时会利用多种数据挖掘模型。让我们花几分钟时间探索一些这些模型的例子。
以下是几种常见的数据挖掘模型:
- 分类分析:此模型将数据项分配到类别或数据类中。然后,你可以使用这些数据来预测项目的目标类别。例如,许多客户购买低价办公产品,他们可以被归类为“低预算客户”,并针对性地推送低价产品的广告。
- 关联规则:此模型识别不同数据元素之间的关系。它根据特定标准判断这些元素之间是否存在相关性。例如,许多购买手机的客户也购买手机充电器和电池包。这表明这些产品应该一起广告和销售。
- 异常检测:此模型揭示特定数据集中的异常数据。换句话说,它检测不符合预期模式的数据异常值。例如,一群有购买低价产品历史的客户突然开始购买昂贵产品。在这种情况下,公司需要重新分类这些客户,并针对性地推送更昂贵产品的广告。
- 聚类分析:此模型在数据中寻找相似性,然后根据发现的相似性或子集内的共同特征,将数据分离成簇或子集。该模型的工作方式与分类分析模型类似,但分类分析模型最初是分配到预定义的组,而不是新发现的组。例如,可以根据客户在公司网店中相似的浏览行为,将客户分类为低预算和高预算群体。
- 回归分析:此模型考虑影响数据的不同因素,然后确定这些因素之间的关系。例如,数据显示每次商店对某些产品打折都会导致销售额增加,因此商店可以得出结论:折扣会影响销售数据。
总结 📝

本节课中我们一起学习了数据挖掘与机器学习的基本区别,以及机器学习中监督式与无监督式两种主要方法。我们还探讨了五种关键的数据挖掘模型:分类分析、关联规则、异常检测、聚类分析和回归分析,并了解了它们如何帮助企业从海量数据中提取有价值的洞察和预测。掌握这些概念对于管理和分析大型数据库至关重要。
Python 109:数据可视化概述 📊

在本节课中,我们将要学习数据可视化的核心概念、关键考量因素以及几种常用的图表类型。数据可视化不仅仅是展示数据,更是将复杂信息转化为易于理解的视觉故事,以帮助决策者快速解读并做出正确判断。




上一节我们介绍了数据可视化的重要性,本节中我们来看看在创建可视化图表前需要考虑哪些关键因素。


数据可视化指的是以决策者能够快速、轻松解读信息的方式呈现或可视化数据。你的角色是从数据中去除噪音,并以用户友好的方式呈现重要元素,如趋势、模式和异常值。
换句话说,你如何通过数据讲述一个信息丰富且引人入胜的故事?
决定使用何种类型的可视化数据时,需要考虑四个因素。







以下是需要考虑的四个关键因素:



- 目标受众:你向谁展示这些数据?他们的背景是什么?他们对所调查问题或主题的理解程度如何?在演示中要考虑这些问题。
- 信息内容:你还需要仔细考虑你的可视化包含哪些信息。哪些信息能回答受众的问题?哪些信息是冗余的?
- 时间:你希望受众花多少时间检查每个图表?他们应该能在几分钟的观察后就理解图表,还是需要更长时间?
- 准确度:最后,思考你的受众需要何种程度的准确度。他们只需要大致理解数据,还是需要深入更精细的细节层面?




在回答了关键问题、确定了受众并明确了需要展示的数据类型之后,就该决定使用哪种数据可视化图表了。


每种类型的图表都有不同的目的,可以用来解决不同类型的问题或传达不同种类的信息。最重要的是选择一个能以最合适的方式向受众讲述数据故事的图表。
让我们探索几个常用数据可视化图表的例子,并了解每种图表传达的信息类型。
以下是几种常见的图表类型及其用途:







- 条形图:这是一种比较类图表。它帮助受众识别数据值之间的差异或相似之处。你可以水平或垂直呈现数据,以显示跨类别的数值比较。Global Superstore 使用条形图来描绘产品销售额与利润率的关系,这显示了每个产品类别产生了多少利润。
- 折线图:折线图显示连续区间或时间段内的定量数据。折线图通过在笛卡尔坐标系中显示数据点之间的连接来工作。在 Global Superstore,他们使用折线图来显示过去几年的利润趋势。
- 气泡图:气泡图显示数值变量之间的关系。每个变量被分配自己的气泡。受众可以通过比较气泡的大小、位置和颜色来理解气泡图所表达的信息。例如,Global Superstore 气泡图中较大的气泡表明该气泡所描绘的部门比分配给较小气泡的部门利润更高。
- 地图图表:地图图表在地理区域中呈现数据。每个数据变量都可以使用各种不同的方法(如颜色和标签)在地图中反映出来。Global Superstore 使用地图图表来可视化不同全球区域的销售额。
- 散点图:该图表将变量绘制为笛卡尔坐标网格上的点。然后,你可以使用这些数据点来寻找变量之间的关系。你还可以为每个数据组添加趋势线,或使用类别标签来显示选定类别的表现。Global Superstore 使用这种方法来描绘不同类别或部门的销售额和利润。





本节课中我们一起学习了数据可视化的核心概念。你现在应该能够解释影响数据可视化的不同因素,并在下次可视化数据时将这些因素考虑进去。同时,你也应该知道如何选择最能通过数据传达你想要讲述的故事的图表或图形。
Python 110:使用高级分析工具进行数据分析 📊
在本节课中,我们将学习数据分析工具的重要性,并重点介绍一款名为Tableau的流行工具。我们将了解这些工具如何帮助企业从海量数据中获取洞察,并初步探索Tableau的工作环境。
数据分析是一个复杂的过程,其任务超出了传统数据库管理系统的能力范围。因此,数据分析需要使用专门的数据分析工具。这些工具利用人工智能,使用户能够查看和理解大量数据。在本视频中,您将回顾一些知名分析工具的示例,了解它们的关键特性。您还将探索Tableau工具,在本课程后续的您自己的项目中将会用到它。
全球超市(Global Superstore)的数据分析师正在执行高级数据分析,以生成能够帮助指导其业务决策的数据洞察。这种方法需要使用强大的数据分析工具。借助这些工具,全球超市可以利用其数据识别新的商机、促进销售增长并改善服务,以及其他好处。让我们进一步了解这些工具的工作原理,并探索全球超市是如何使用它们的。
数据分析工具概述
数据分析工具帮助数据库用户执行数据分析。数据分析的结果能生成洞察,为商业和其他组织的发展提供信息。这些工具利用人工智能、机器学习和数据挖掘技术,并提供数据可视化工具,以帮助您理解和传达您的发现。
您可以利用多种分析工具。数据库分析师最常依赖的工具包括:
- Tableau
- SAS Business Intelligence
- Microsoft Power BI
核心特性
这些工具提供几个关键特性,使其在处理大型数据库时非常有用。
以下是这些工具的核心优势:
- 处理海量数据:它们能够处理大规模的数据集。
- 支持多种数据格式:它们可以与许多不同格式的数据协同工作。
- 连接多种数据源:它们能够与许多不同的数据源和数据库系统交互。
- 高级分析技术:每个工具都使用高级数据分析技术来生成洞察。
- 高级可视化工具:它们提供高级数据可视化工具。
这些特性使用户查看和理解数据变得容易得多。
聚焦 Tableau 🎨
上一节我们介绍了数据分析工具的通用特性,本节中我们来看看一款具体的工具:Tableau。Tableau是一款广泛使用的数据可视化工具。它提供14天的免费试用,并为教师和学生提供一年的免费许可。
Tableau用户在进行数据可视化时可以利用以下几个关键特性:
- 数据类型支持:它以字符串、日期和时间等不同数据类型存储数据。
- 广泛的数据源连接:它可以连接到广泛的数据源,如
MySQL、Microsoft SQL、MongoDB、BI和Oracle DB。 - 多格式文件交互:它可以与许多不同的数据表和文件系统交互,如
Excel、JSON和PDF。
除了这些特性,Tableau还能:
- 生成实时呈现数据的交互式仪表板。
- 支持
Python和R编程语言的脚本编写。 - 使用拖放等交互式UI工具完成任务。
Tableau有桌面版和云版本。在本课程中,您将使用Tableau桌面版。您可以直接从Tableau官网下载该软件。




探索 Tableau 工作环境
现在您已经熟悉了Tableau工具,让我们更详细地探索它,并了解像全球超市这样的组织是如何使用它的。
首先,点击Tableau桌面图标启动Tableau。这将打开Tableau启动页面。启动页面提供了几个不同的选项:
- 使用“打开工作簿”来打开现有工作簿。
- 在“加速器”部分使用示例工作簿进行工作。
- 在“发现”部分访问有用的学习资源。
- 您还可以使用“连接”窗格连接到您的数据源。
例如,全球超市可以选择一个Microsoft Excel文档作为其数据源,并将文件数据加载到其Tableau工作区中。选择Tableau图标可以从开始页面切换到创作工作区。
连接到数据源后,源连接和相关字段会出现在“数据”窗格中。然后,您可以使用创作工作区的用户界面元素来创建数据的可视化。








创建可视化与仪表板
您可以使用“标记”卡或行和列架子将数据添加到视图中。例如,全球超市可以根据需要在工作区周围拖放度量和维度。这对于比较数据和类别非常有用。
在工具栏中可以快速轻松地访问命令和导航工具。全球超市经常使用排序图标来按升序或降序排列条形图,或者使用仪表板同时查看和处理多个数据源。
您甚至可以创建一个交互式仪表板,将不同的工作表组合起来,向观众呈现相关信息。您还可以使用“故事”工具,它与仪表板类似。“故事”通过呈现一系列工作表和仪表板来讲述您的数据故事。


本节课中我们一起学习了知名数据分析工具及其共享的关键特性。您现在应该能够识别这些工具,并描述它们的许多共同特点。您还应该能够访问和使用Tableau工作环境来可视化您的数据。您在发展对高级数据分析的理解方面取得了良好的进展。
Python 111:在Tableau中导入和准备数据 📊
在本节课中,我们将学习如何在Tableau中连接数据源,并对数据进行清理和准备工作,以便进行后续分析。我们将通过一个名为“全球超市”的案例,演示如何操作一个大型Excel文件。
概述
上一节我们介绍了数据分析的基本概念,本节中我们来看看如何在Tableau这一具体工具中开始工作。首先需要将数据导入Tableau,然后进行必要的清洗和整理,这是确保分析结果准确可靠的关键步骤。
连接数据源
要在Tableau中执行数据分析,首先需要与数据源建立实时连接。
以下是建立实时连接的步骤:
- 打开Tableau,在左侧“连接”选项卡下的连接页面,点击“Microsoft Excel”。
- 这会打开一个对话框,用于导航至您计算机上的Excel文件。
- 选择并打开文件。Excel文件名将显示在屏幕左侧。
连接成功后,Excel文件中的数据会显示在数据窗格中。使用实时连接可以确保对原始数据源的任何更新都能自动反映在您的数据库中。
然而,处理数据提取的速度更快,尤其是在处理大量数据时。
认识数据窗格与元数据
数据窗格的左侧是元数据网格,它显示了关于不同数据字段的相关信息。
您可以通过点击相关按钮来显示或隐藏元数据网格。
现在您已经连接到了所需的数据,可以开始对其进行清理和准备,以便分析。
数据清理与准备
这个过程包括修复数据中的错误,并调整数据形状,使其更易于理解和分析。您可以通过执行不同类型的操作来实现,例如筛选、排序和重命名数据。
这些操作将在后续视频中详细介绍。
每一列的顶部都标明了该列的数据类型,并配有相应的符号。您可以根据需要更改这些数据类型。
让我们以“订单日期”列为例:
- 选择该列上方符号旁边的小箭头。
- 在出现的选项列表中点击它。
- 此操作会显示该数据字段的关键信息。
- 点击“ABC”数据类型,然后选择“日期”数据类型。现在数据类型已更改。
您还可以隐藏不相关的表格细节,以便只关注必要的数据。您也可以更改数据窗格中显示的行数。
让我们隐藏“订单日期”列:
- 再次选择小箭头,然后选择“隐藏”。
- 该列现在已被隐藏。
要再次显示数据,请点击Tableau设置图标,然后选择“显示隐藏字段”选项。此操作会以淡色版本显示字段,以指示哪些内容已被隐藏。
要恢复这些字段,请点击小箭头并选择“取消隐藏”。
拆分与重命名字段
您的下一个任务是将“客户姓名”列拆分为两个单独的列:一列用于客户的名字,另一列用于客户的姓氏。
- 点击小箭头,然后选择“拆分”选项。这将自动创建两个新字段。
- 您可以根据需要重命名它们。点击相应的小箭头,选择“重命名”,将列命名为“名字”和“姓氏”。
创建计算字段
全球超市还需要您为他们的退货创建一个新的数据字段。该字段必须包含根据公司退货政策,每个产品可以退回的最后日期,即购买日期后的15天。
- 选择“订单日期”列中的小箭头,然后点击“创建计算字段”。
- 将这个新字段命名为“退货日期”。
- 在计算编辑器中,输入以下基本公式:
[订单日期] + 15。此公式为每个订单日期值增加15天。 - 这将创建一个新的“退货”列,其中填充了相关数据。完成后,点击“确定”。新的计算字段将被添加到数据窗格中。
总结
本节课中我们一起学习了如何在Tableau中连接数据源,并清理和准备数据以进行分析。全球超市的数据现已清理并准备就绪。您现在应该熟悉了如何在Tableau中连接到数据源,并为您自己的数据分析清理和准备数据。
做得好。




Python 112:在Tableau中过滤和可视化数据 📊
在本节课中,我们将学习如何在Tableau中过滤数据并创建数据分析图表。通过聚焦于所需数据,我们可以更高效地进行数据分析,并利用可视化功能清晰地展示信息。
概述
将数据导入Tableau后,需要为分析做准备。如果只关注需要分析的数据,这个过程会更高效。您可以使用Tableau的过滤和可视化功能来聚焦相关数据。本节将指导您如何过滤数据并在Tableau中创建数据分析图表。
数据过滤的重要性
Global Superstore公司正准备在加拿大开展新的营销活动。首先,他们需要分析销售数据以优化活动。他们可以使用数据过滤技术来整理和排除数据,使记录仅聚焦于加拿大市场。这能提供更相关、可靠和准确的信息。您可以使用Tableau来帮助Global Superstore完成这项任务。
在Tableau中,您可以在“数据源”页面或“工作表”中过滤数据。然而,直接在“数据源”页面过滤数据会限制您的数据分析,并且所有工作表都将仅遵循过滤后的标准。例如,如果Global Superstore将其类别过滤为仅包含办公家具,那么他们将无法在工作表中对其他类别进行数据分析。


在数据源页面应用过滤


上一节我们介绍了数据过滤的基本概念,本节中我们来看看如何在数据源页面进行过滤。

- 点击“过滤器”下的“添加”选项。这将打开一个对话框,列出数据源中的所有可过滤字段。
- 再次点击“添加”以添加一个新的过滤字段。
- 选择“Region”字段,然后点击“确定”。
- 在“常规”选项卡区域,点击“从列表中选择”选项,勾选“Canada”,然后点击“确定”。


现在,数据窗格仅显示来自加拿大的过滤后记录。如果需要,您可以重复此过程以添加更多数据源过滤器。
要移除过滤器,请点击“编辑过滤器”,选择“Canada”,然后点击“移除”和“确定”。
在工作表中过滤数据



您也可以在工作表中过滤数据。打开页面底部的“工作表”选项卡。在工作表中,数据源的列在数据窗格左侧显示为字段。
数据窗格包含多种字段。灰线上方的字段是维度字段。灰线下方的字段是度量字段。维度字段包含分类数据,对于Global Superstore而言,这包括产品类别、类型和日期。度量字段包含数值数据,如销售额、利润和数量。
Global Superstore希望比较在加拿大销售的所有类别产品的销售额。为了帮助他们完成这项任务,请执行以下操作:


- 将数据窗格维度部分的“Category”字段拖到“行”功能区。
- 将数据窗格度量部分的“Sales”字段拖到“列”功能区。

出现的水平条形图显示了不同产品类别的信息。现在需要过滤此数据以仅显示在加拿大销售的产品。

以下是具体步骤:
- 将“Region”维度从数据窗格拖到“过滤器”功能区。这将打开一个弹出窗口。
- 在“常规”选项卡中,选择“Canada”,然后点击“应用”和“确定”。
您的数据现在已被过滤,仅显示加拿大的销售额。

优化图表可读性




您可以采取进一步措施使图表更易于阅读和理解。



- 点击“交换”图标,将水平条形图更改为垂直图表。
- 点击“降序排序”图标,按销售额从高到低过滤数据。
- 将“Sales”拖到屏幕“标记”部分的“颜色”功能区,根据销售额更改条形颜色。
- 将“Profits”从数据窗格的度量部分拖到“标签”标记。这将在图表中显示每个类别的利润。
- 您还可以为工作表提供标题。在本例中,可以将其命名为“Sales in Canada”。

图表中的许多信息是通用的。为了更好地展示销售和利润的细节,最好将子类别添加到视图中。

- 将数据窗格维度部分的“Subcategory”字段拖到“列”功能区。
- 然后点击“降序排序”图标,按最大值到最小值过滤数据。
您现在可以查看所有类别和子类别。您甚至可以专注于一个类别,如“Furniture”。

- 将“Category”维度从左侧数据窗格拖到“过滤器”功能区。
- 然后使用“过滤分类数据”选项,保留“Furniture”类别,同时取消勾选“Technology”和“Office Supplies”类别。
- 点击“应用”,然后点击“确定”。

高级过滤技巧


您还可以根据畅销商品过滤类别。



- 将“Subcategory”拖到“过滤器”功能区,然后选择“顶部”选项卡。
- 勾选“按字段”,并输入数值“2”以查看前两个类别,然后点击“应用”。
通配符也可用于过滤特定模式的数据。例如,您可以在文本字段中键入“chair”,以包含包含此文本值的子类别。在本例中,数据将返回“Chair”子类别。


另一种过滤技术是条件过滤。您可以使用条件过滤来选择数据字段并定义要应用的特定规则。例如,您可以选择“Sales”字段,然后指定总和值大于500,000。点击“应用”,然后点击“确定”。这将返回数据中所有大于500,000的值。
要移除所有子类别过滤器,只需右键单击“Subcategory”并点击“移除”。您也可以移除“Category”过滤器,仅保留“Region”过滤器以专注于加拿大。



您现在可以查看与加拿大“Furniture”类别和子类别相关的所有销售数据。

总结
本节课中我们一起学习了如何在Tableau中应用数据过滤。Global Superstore现已使用Tableau过滤了数据分析所需的数据。您现在也应该能够使用Tableau对数据应用不同的过滤技术。您在数据分析之旅中取得了巨大进展。
Python 113:高级数据分析模块小结 🎯
在本节课中,我们将回顾并总结高级数据建模课程的第三个模块——“高级数据分析”的核心内容。我们将系统梳理数据分析的基础概念、关键技能以及如何使用Tableau这一可视化分析工具进行实践。
恭喜你完成了高级数据建模课程的第三个模块。在本模块中,你探索了数据建模背景下的数据分析,并学习了如何使用可视化分析工具进行数据分析。
让我们花几分钟时间来回顾一下你在本模块课程中获得的一些关键技能。
数据分析概述 📊
你从本模块的第一课——数据分析概述开始学习。你了解到,数据分析涉及将聚合数据转换和处理成有用且有意义的信息。



你还探讨了数据分析的主题。在你的数据库工程学习过程中,会遇到几种关键的数据分析类型。
以下是主要的数据分析类型:
- 描述性数据分析:以描述性格式呈现数据。
- 探索性数据分析:用于建立不同变量之间的关系。
- 推断性数据分析:专注于小样本数据以进行推断。
- 预测性数据分析:识别数据模式以预测未来表现。
- 因果性数据分析:探索变量之间的因果关系。
此外,你还了解到需要处理两种类型的数据:定量数据(指数值型数据)和定性数据(指非数值型数据)。
数据测量与组织 📏
一旦确定了要处理的数据类型,接下来就需要组织、识别和分析它。你可以使用四种测量尺度来执行这些操作。




以下是四种主要的测量尺度:


- 定类尺度:用于标记数据,不分配任何定量值或顺序。
- 定序尺度:将数据按特定排名顺序排列。
- 定距尺度:使用特定标准识别数据点之间的明确差异,也可以表示负值。
- 定比尺度:定义数据的同一性,对数据进行分类排序,并标记明确的间隔,但不能表示负值。
数据挖掘与机器学习 🤖

接着,你探讨了数据挖掘和机器学习的主题。你了解到,数据挖掘是检测数据模式的过程,而机器学习是教会计算机如何学习的过程。这可以通过监督式或无监督式机器学习来完成。

机器学习在处理数据时会利用几种不同类型的数据挖掘模型。

以下是几种主要的数据挖掘模型:
- 分类分析:将数据项分配到类别中。
- 关联规则:识别不同数据元素之间的关系或关联。
- 异常检测:检测不符合预期模式的数据异常值或异常。
- 聚类分析:在数据集中搜索相似性,然后将它们分离成簇。
- 回归分析:考虑影响数据的不同因素,然后确定这些因素之间的关系。
数据可视化的重要性 📈
在本课程的下一个部分,你学习了数据可视化的重要性。这意味着你必须以能让决策者快速、轻松地解读信息的方式来呈现或可视化你的数据。



在可视化数据时,你必须考虑以下问题:你的受众是谁?他们需要知道什么信息?他们应该花多少时间来检查这些信息?他们需要什么级别的准确性?

回答了这些问题后,你就可以选择合适的数据可视化图表。有许多不同类型的图表可供选择,包括条形图、折线图和气泡图。你也可以使用地图图表或散点图。每种图表都有不同的用途。最重要的是选择最能向你的受众传达信息的图表。

然后,你通过一个讨论结束了这节课,思考了你接触过哪些类型的数据分析报告,以及它们如何帮助你的任务。

高级数据分析工具:Tableau 🛠️

在本模块的下一课中,你回顾了高级数据分析的主题。你了解到数据分析工具可以帮助数据库用户执行数据分析,数据分析的结果为其业务或组织的发展提供信息。
本课程中使用的数据分析工具是 Tableau。它的主要功能如下:
- 以不同数据类型的形式存储数据。
- 可以连接到广泛的数据源。
- 可以与许多不同的数据表和文件系统交互。
除了这些功能,Tableau还可以生成交互式仪表板,支持多种语言的脚本编写,并且还提供拖放等交互式UI工具。


你首先学习了如何下载、启动和导航Tableau。然后你学习了如何在Tableau中导入和准备数据。这涉及到设置到数据源的实时连接或将数据导入工具,以及清理和准备数据以供分析。


这第二步通常涉及以下操作:
- 过滤不相关的数据。
- 拆分数据以提高可访问性。
- 根据需要创建新的数据字段。
- 修复数据类型。
连接到数据源或导入数据后,你就可以在Tableau中过滤、分析和可视化数据。你可以使用数据源页面或工作表来过滤数据。Tableau还允许你使用条件或添加子类别来过滤数据。
然后,你学习了如何使用Tableau工作表创建交互式仪表板。最后,你进行了一个练习,在Tableau中执行了数据分析。

总结 🏁




本节课中,我们一起学习了高级数据分析模块的核心内容。你现在应该熟悉了数据分析和数据分析软件,这是巨大的进步。我期待在下一个模块中指导你完成一个数据建模项目。
Python 114:23_高级数据建模课程回顾 📚
在本节课中,我们将回顾《高级数据建模》课程的核心内容。课程涵盖了从基础数据模型概念到高级数据分析工具的完整知识体系,旨在帮助你巩固所学,为后续的评估做好准备。

课程概述 🗺️

课程从高级数据库建模的简介开始。你了解到,数据模型是对不同数据元素及其相互关系的可视化表示。


数据模型的层次与类型 🏗️

上一节我们介绍了数据模型的基本概念,本节中我们来看看数据模型的不同层次和类型。
你学习了数据库模型的三个层次:
- 概念数据模型:描述业务概念和它们之间的关系。
- 逻辑数据模型:定义数据结构,如实体、属性和关系,独立于任何数据库管理系统。
- 物理数据模型:描述数据在特定数据库管理系统中的实际存储方式。
你还回顾了可用于设计数据库的不同类型的数据模型,例如实体关系模型和面向对象模型。
数据库规范化 🧹

接下来,你学习了如何通过数据库规范化来构建表结构,以处理数据异常。以下是三种主要的异常类型:
- 插入异常:无法插入某些数据,除非其他无关数据也存在。
- 更新异常:更新一个数据项需要修改多行记录,可能导致数据不一致。
- 删除异常:删除一个数据项会导致其他重要信息丢失。




你还通过一个示例数据模型进行了探索,并在练习中设计了一个数据库模型。

MySQL Workbench 工具 🛠️
在本模块的下一课中,你认识了 MySQL Workbench。这是一个用于数据库建模和管理的统一可视化工具,提供了一系列创建、编辑和管理数据库的有用功能。
你随后学习了如何使用 MySQL Workbench 的正向工程功能来构建数据模型图。你还学会了如何使用其反向工程功能,即从现有的 MySQL 数据库模式创建数据模型,这本质上是正向工程的逆过程。
此外,你可以打印模型、分享模型,或应用更改并通过正向工程将其推送到数据库。
你通过一个测验项和一个练习完成了本课,在练习中你使用 MySQL Workbench 设计了自己的数据库模型。



数据仓库架构 📦

在下一个模块中,你探索了数据仓库的主题。你学习了数据仓库的架构,并构建了一个维度数据模型。
你首先概述了数据仓库的概念。数据仓库是一个集中式的数据存储库,它从多个来源聚合、集成、存储和处理大量数据,用户可以查询这些数据以执行数据分析。
你随后发现数据仓库由四个关键特征定义:
- 面向主题
- 集成性
- 非易失性
- 时变性
你还回顾了数据仓库处理的不同形式的数据,包括:
- 结构化数据
- 半结构化数据
- 非结构化数据
接着,你探索了数据仓库的架构,了解到它包括以下组件:数据源、包含ETL过程的数据暂存区、数据仓库本身以及数据集市。数据从数据源聚合后,在数据仓库中进行集成和存储,然后在数据集市中组织起来,供用户进行数据分析和呈现结果。这些组件控制着来自不同源的数据流,以进行数据分析和报告。

你还探索了一个真实世界数据项目的案例研究。




维度数据建模 ⭐

在本模块的第二课中,你探索了维度数据建模。课程从维度数据建模的基础知识概述开始。
你了解到维度数据模型基于维度和事实,并使用星型模式和雪花模式进行设计。
你随后探索了一些维度数据建模的实例,并了解到创建模型时有四个关键步骤:
- 选择业务过程。
- 确定粒度。
- 确定维度。
- 确定事实。
最后,你进行了一个练习,在其中创建了自己的维度模型。


数据分析基础与可视化 📊




在本课程的第三个模块中,你在维度和度量的背景下探索了数据分析,并学习了如何使用高级分析工具执行可视化数据分析。
你从数据分析的概述开始,回顾了数据分析的基础知识以及在数据库工程旅程中使用过的关键类型。
你还了解到你将处理两种通用类型的数据:定量数据(指数值数据)和定性数据(指非数值数据)。


当你确定了需要哪种数据后,可以使用四种测量尺度来处理和分析它:
- 定类尺度
- 定序尺度
- 定距尺度
- 定比尺度
接下来,你学习了数据挖掘和机器学习的主题。数据挖掘是检测数据中模式的过程,而机器学习是教会计算机如何学习的过程。机器学习利用数据挖掘模型来处理数据,例如:
- 分类分析
- 关联规则
- 聚类分析
- 回归分析
然后你学习了数据可视化。在可视化数据时,你必须考虑你的受众以及他们寻找的信息,然后需要选择一个能最好地传达此信息的合适图表。
最后,你通过一个讨论提示结束了本课,该提示围绕你在工作中使用何种数据分析报告展开。
Tableau 数据分析工具 🎨



在本模块的最后一课中,你回顾了数据分析的主题,并学习了如何使用像 Tableau 这样的数据分析工具。




作为 Tableau 介绍的一部分,你了解了它的主要功能以及它如何帮助你进行数据分析。然后你学习了如何使用 Tableau 分析数据,这包括以下步骤:
- 下载、启动并导航 Tableau。
- 加载并准备待分析的数据。
- 过滤和可视化数据。
- 创建交互式仪表板。
最后,你进行了一个实验练习,在 Tableau 中执行了数据分析。


总结 🎯

本节课中我们一起回顾了《高级数据建模》课程的全部核心内容。我们从数据模型的基础概念出发,逐步深入到数据库规范化、MySQL Workbench 工具的使用、数据仓库的架构与维度建模,最后学习了数据分析的基础知识以及如何使用 Tableau 进行可视化分析。现在,是时候在分级评估中尝试运用你所学的知识了。祝你好运!
Python 115:恭喜您完成了高级数据建模 🎉
在本节课中,我们将对您在整个高级数据建模课程中的学习成果进行总结,并展望后续的学习路径与职业发展机会。
恭喜您,您已经完成了这门课程的学习。
您付出了巨大的努力才走到这一步,并在此过程中掌握了许多新技能。

您在高级数据建模的旅程中取得了卓越的进展。
现在,您应该对数据库建模有了深入的理解。
您能够通过一项练习来展示部分学习成果。
完成这项练习后,您现在应该能够:
- 在 MySQL Workbench 中设计数据库模型。
- 理解数据仓库在数据分析流程中的作用。
- 使用数据仓库创建维度数据模型。
- 使用 Tableau 进行数据分析,并运用数据可视化技术展示您的结果。
随后的分级评估进一步检验了您对这些技能的掌握程度。
然而,您仍有更多知识需要学习。
因此,如果您觉得本课程有所帮助并希望探索更多内容,何不注册下一门课程呢?
在每一门数据库工程师课程中,您都将持续发展您的技能组合。
在最终的毕业项目中,您将运用所学的一切知识,创建您自己功能完整的数据库系统。
无论您是刚刚起步的技术专业人士、学生还是商业用户,本课程和项目都能证明您对数据库系统价值和能力的理解。
该项目通过实际应用来巩固您的技能。
但该项目还有另一个重要的益处。
这意味着您将拥有一个完全可运行的数据库,可以将其纳入您的作品集中。
这有助于向潜在雇主展示您的技能。
它不仅向雇主表明您具备自主驱动力和创新精神,也充分展现了您作为个人以及您新获得的知识。
一旦您完成了该专业认证中的所有课程,您将获得数据库工程证书。
根据您的目标,此证书也可作为进阶其他基于角色的证书的跳板。您可以选择深入学习高级角色证书,或者在获得此证书后学习其他基础课程。
感谢您。很荣幸能与您一同踏上这段探索之旅。祝您未来一切顺利。

本节课中,我们一起回顾了您在高级数据建模课程中取得的成就,包括掌握的核心技能和完成的实践项目。我们还探讨了如何将所学知识应用于毕业项目以构建作品集,并了解了获得专业认证后的后续学习与发展路径。
数据库工程师毕业项目:P116:0_课程介绍 🎯
在本节课中,我们将要学习毕业项目的整体介绍。你将了解在数据库工程师学习旅程的最后阶段,需要完成的一系列核心任务,以及完成这些任务所需的关键工具和技能。
欢迎来到毕业项目课程。现在,你距离完成数据库工程师的学习旅程已经非常接近了。


在这门最终的课程中,你需要通过帮助“小柠檬”餐厅完成一系列数据库相关任务来证明你新掌握的技能。

项目任务概览 📋
以下是你在毕业项目中需要完成的主要任务:
- 设置数据库:在MySQL Workbench中使用MySQL服务器设置数据库。
- 设计并实现数据模型:创建实体关系图(ER图)并在MySQL Workbench中实现它。
- 版本控制:使用Git提交项目。
- 生成销售报告:从数据库中的数据创建销售报告。
- 构建预订系统:建立一个餐桌预订系统。
- 生成数据洞察:使用数据分析生成业务洞察。
- 创建数据库客户端:创建一个数据库客户端应用程序。
任务详解与工具 🔧
上一节我们介绍了项目的整体任务,本节中我们来看看完成这些任务的具体过程和工具。
1. 数据库设计与建模



在第一组任务中,你将帮助“小柠檬”构建一个关系型数据库系统。你需要设计一个结构良好、符合三大基本范式(1NF, 2NF, 3NF)的实体模型或ER图。




你将使用MySQL Workbench来设计ER图。这是一个用于数据库建模和管理的统一可视化工具。你将利用MySQL Workbench的一个关键功能:将你的数据库模型转换为MySQL服务器中的物理数据库模式。


创建好“小柠檬”数据库后,你将使用版本控制系统Git来提交你的项目。你还会使用GitHub来存储你的Git仓库。
2. 创建销售报告

你的下一个任务是从“小柠檬”数据库的数据中创建销售报告。你将使用数据库查询、存储过程和预处理语句来创建这些报告。
让我们更详细地了解一下这些技术:



- 视图:你将使用虚拟表(视图)来利用其他表中存在的数据,并简化数据访问和查询。
- 连接查询:你还会使用不同类型的
JOIN子句,基于公共列将一个或多个表中的数据记录链接起来。例如:SELECT * FROM Orders JOIN Customers ON Orders.CustomerID = Customers.CustomerID; - 存储过程:你将帮助“小柠檬”使用存储过程来创建可重用的代码,这些代码可以根据需要被调用和执行。
- 预处理语句:你还会依赖预处理语句,它们可以重复使用,而无需编译或占用宝贵的MySQL资源。

3. 构建餐桌预订系统
你将协助“小柠檬”在数据库中构建一个餐桌预订系统,用于跟踪来餐厅用餐的客人。这个任务主要包括使用SQL查询和事务。
让我们回顾一下你将使用的一些SQL查询和事务示例:
- 插入数据:使用标准的
INSERT INTO语句创建数据。 - 更新数据:使用
UPDATE语句更改数据库中的数据。 - 删除数据:使用
DELETE语句删除或移除数据。 - 读取数据:使用
SELECT语句等读取查询来读取数据。
你还会使用触发器,将一组操作以存储程序的形式保存起来,当特定事件发生时可以自动调用。


一旦你确认代码正确,就可以将进度提交到Git。
4. 生成业务洞察
在下一个任务中,你将帮助“小柠檬”利用他们的数据生成业务洞察。你将使用数据可视化工具Tableau来完成此任务。
让我们回顾一下完成此任务需要遵循的步骤:
- 连接数据源:首先将你的数据源连接到Tableau。
- 准备数据:然后为分析准备数据,并专注于最相关的数据。
- 创建可视化:下一步是使用其UI元素创建数据的可视化。
- 生成仪表板:最后,你将使用Tableau以仪表板的形式生成交互式、实时的数据可视化。
这些步骤将有助于为“小柠檬”的重要业务问题提供清晰且相关的答案。



5. 创建数据库客户端

你的最终任务是帮助“小柠檬”创建一个数据库客户端,以便他们可以使用基于Python的应用程序与数据库进行交互。
首先,你需要确认你的机器上运行的是哪个版本的Python。确认你运行的是最新版本的Python后,你需要安装Jupyter IDE来运行你的代码。
然后,你可以打开一个新的Jupyter Notebook实例,并使用它将Python连接到“小柠檬”的MySQL数据库。你可以使用Python库mysql-connector-python和pip软件包管理器来建立此连接。例如:pip install mysql-connector-python。
设置好Python环境后,你就可以开始处理你的数据库客户端了。

总结与开始 🚀



本节课中我们一起学习了毕业项目的全部内容。你现在已经熟悉了需要完成的任务,是时候开始了。

别担心,我会在此过程中为你提供指导。如果你需要更多帮助,也可以参考之前课程的相关学习材料。
祝你好运!
Python 117:项目概述与设置 🚀
在本节课中,我们将学习如何为 Little Lemon 餐厅设置数据库项目。我们将回顾并应用三个关键步骤:在 MySQL Workbench 中设置数据库、创建并实现实体关系图,以及使用 Git 提交项目。
项目设置的关键步骤
上一节我们介绍了课程目标,本节中我们来看看设置项目的具体步骤。以下是完成项目设置所需的三个核心步骤:
- 使用 MySQL 实例服务器在 MySQL Workbench 中设置数据库。
- 创建实体关系图并在 MySQL Workbench 中实现它。
- 提交项目。
在接下来的内容中,我们将逐一回顾这些主题,并学习如何在本课程中应用它们,以帮助 Little Lemon 构建其关系型数据库系统。
设计数据模型 📐
首先,你需要设计一个结构良好的实体关系数据模型,即 ER 图。



你需要确保该图符合三个基本范式。通过遵循这些范式,你将确保数据库的完整性,并避免插入、更新和删除异常。正如你在之前的课程中所了解的,有许多专业工具可用于设计 ER 图。

在本项目中,你将使用 MySQL Workbench。你应该在其他课程中已经熟悉了 MySQL Workbench,因此现在让我们快速回顾一下基础知识。
认识 MySQL Workbench 🛠️
MySQL Workbench 是一个统一的视觉化工具,用于数据库建模和数据管理。它的主要优势在于开源、跨平台,并提供可视化 SQL 编辑器的支持。它还可以让你将数据模型转换为 MySQL 服务器中的物理数据库模式。



如果你尚未在操作系统中安装 MySQL Workbench,可以从 dev.mysql.com/downloads 下载并安装。
以下是安装时需要确保安装的组件:

- MySQL 服务器
- MySQL Workbench
- MySQL Shell
安装过程相对简单。但是,如果遇到任何挑战,可以参考之前课程中的安装材料,或访问 Oracle 网站获取详细的安装说明。
提交项目与版本控制 💾

创建好 Little Lemon 数据库后,你需要提交你的项目。
你可以使用 Git 来提交项目。Git 是一个免费、开源的分布式版本控制系统。你可以使用它来管理所有源代码的历史记录。你可以保留提交历史、恢复到以前的版本,并共享代码以与其他开发人员协作。
你可以从 git-scm.com/downloads 下载并安装 Git。
你的 Git 仓库通常存储在 GitHub 上。GitHub 包含了 Git 的源代码管理功能以及其他有用的功能,例如项目管理、支持工单管理和错误跟踪。你也可以用它来共享访问权限和存储仓库,包括备份。
要注册 GitHub 并开始使用,请访问官方网站 github.com。



总结与开始 🎯


现在你已经熟悉了所需的技术,可以开始帮助 Little Lemon 开发他们的数据库系统了。
你可以按照以下流程操作:在 MySQL Workbench 中设置数据库,创建 ER 图并实现模型,最后提交你的模型。如果你需要关于这些主题的更多信息,可以复习之前课程的学习材料。
祝你好运!
Python 118:模块小结 📚
在本节课中,我们将回顾为Little Lemon餐厅建立数据库项目的关键步骤。我们将总结如何使用MySQL Workbench设置数据库、设计并实现实体关系图,以及如何使用Git进行版本控制。
项目设置回顾 🛠️



上一节我们介绍了为Little Lemon建立数据库系统的整体目标。本节中,我们来看看完成此项目的三个核心步骤。
为Little Lemon设置数据库项目包含以下三个关键步骤:

- 使用MySQL服务器实例在MySQL Workbench中设置数据库。
- 创建实体关系图并在MySQL Workbench中实现它。
- 使用Git提交项目。
数据库设计与规范化 📐
为了帮助Little Lemon构建一个关系型数据库系统,我们设计了一个结构良好、符合三大基本范式的实体关系数据模型。

通过遵循这些范式,我们确保了数据库的完整性,并避免了插入、更新和删除异常。有许多专业工具可用于设计ER图,在本模块中,我们使用了MySQL Workbench。
MySQL Workbench工具介绍 💻
MySQL Workbench是一个用于数据库建模和数据管理的统一可视化工具。在我们的项目中,我们利用了该工具的以下几个关键优势。
以下是MySQL Workbench的主要优势:

- 开源:可以免费使用。
- 跨平台:支持多种操作系统。
- 可视化SQL编辑器:提供图形化界面编写和管理SQL。
- 模型转换:允许将数据模型转换为MySQL服务器中的物理数据库模式。


你可以从 dev.mysql.com/downloads 下载并安装它。安装时,请确保安装以下组件:
- MySQL Server
- MySQL Workbench
- MySQL Shell
版本控制与Git 🌳
创建Little Lemon数据库后,我们使用Git提交了项目。Git是一个免费、开源的分布式版本控制系统。
我们用它来管理所有源代码的历史记录、保存提交历史、回退到先前版本,并与其他开发者共享代码以进行协作。你可以从 git-scm.com/downloads 下载并安装Git。
你可以将Git仓库存储在GitHub上。GitHub除了包含Git的源代码管理功能外,还提供了其他有用特性。
以下是GitHub提供的一些关键功能:
- 项目管理
- 支持工单管理
- 错误跟踪
- 共享、访问和存储仓库(包括备份)



总结与下一步 🚀



本节课中,我们一起学习了为Little Lemon建立数据库项目的完整流程:从使用MySQL Workbench进行数据库设计和实现,到利用Git进行版本控制。

现在你已经完成了本模块的总结,下一阶段是完成模块测验并复习附加资源。完成这些任务后,你就可以进入下一个模块了。
Python 119:为Little Lemon销售数据创建报告查询 📊
在本节课中,我们将学习如何为Little Lemon餐厅创建销售报告。我们将利用虚拟表、连接、存储过程和预处理语句等技术,从数据库中查询和整理所需的数据。

概述
Little Lemon需要从其数据库中的数据创建销售报告。我们可以通过查询数据来帮助他们生成这份报告。查询数据时,我们将使用虚拟表、连接、存储过程和预处理语句。
虚拟表(视图) 📋
上一节我们介绍了本课程的目标,本节中我们来看看虚拟表。虚拟表利用其他表中存在的数据,它本身并不物理存储任何数据。它更像是一个提供数据库数据访问的接口。
使用虚拟表有几个好处。以下是其主要优点:
- 简化数据访问和查询。
- 可用于创建虚拟表和基表之间的连接。
- 可以高效地操作和过滤数据。
- 支持数据库安全。
创建虚拟表时,您将使用连接从多个表中构建视图。
连接(JOIN) 🔗



上一节我们介绍了虚拟表,本节中我们来看看连接。连接用于基于一个公共列将一个或多个表中的数据记录链接起来。

您可能使用连接来查找数据库中特定活动或对象的信息,或者您可能需要查找相关信息存在于多个表中的情况。
在这些课程中,我们探讨了几种类型的连接。这些包括:
- INNER JOIN:返回两个表中匹配的行。
- LEFT JOIN:返回左表的所有行,以及右表中匹配的行。
- RIGHT JOIN:返回右表的所有行,以及左表中匹配的行。
- SELF JOIN:表与自身连接。
- FULL OUTER JOIN:返回两个表中所有的行。
您可以使用这些连接来查询Little Lemon的数据库并检索他们所需的信息。
存储过程 🛠️
上一节我们介绍了如何使用连接查询数据,本节中我们来看看存储过程。存储过程的主要目的是创建可重用的代码块,这些代码块可以被高效地调用和执行。

这使您的代码更加一致、可重用,并且更易于使用和维护。因此,您无需重复键入相同的代码,而是可以将代码块保存为存储过程,然后在需要时调用。



您可以创建任意数量的存储过程,它们可以包含多个参数。您的代码也可以包含各种类型的SQL代码。只需确保每个存储过程都有唯一的名称。

请记住,创建存储过程的方式取决于您需要完成的任务。
预处理语句 ⚡
上一节我们介绍了存储过程,本节中我们来看看预处理语句。每次创建SQL语句时,MySQL都需要在语句执行之前对其进行编译和解析。

一个更高效的方法是创建一个预处理语句,它只需要编译一次,然后就可以重复使用。换句话说,您可以创建一个预处理语句,MySQL在执行前仅编译和解析一次。


因此,每次调用该语句时,MySQL都知道它已准备就绪并且可以安全执行。

预处理语句是一种更高效、更优化的执行语句方式,无需消耗宝贵的MySQL资源。
总结
本节课中,我们一起学习了为Little Lemon创建销售报告所需的技术和方法。您现在应该熟悉了使用虚拟表、连接、存储过程和预处理语句来查询和整理数据。如果您需要更多关于这些主题的信息,请记住您可以复习之前课程的学习材料。
Python 120:开发桌面预订系统 🍋
在本节课中,我们将学习如何为Little Lemon餐厅开发一个数据库内的餐桌预订系统。我们将运用SQL事务、CRUD操作以及触发器的知识,来创建、管理和测试这个系统。

开发预订系统的基础:SQL事务与CRUD操作
开发一个餐桌预订系统需要使用SQL事务或查询。

正如目前所了解的,事务是在数据库内执行的语句。需要用到的主要语句类型包括创建、读取、更新和删除查询,这些也被称为CRUD操作。
接下来,我们将回顾如何使用这些查询来完成本课任务的基础知识。
创建数据:新增预订
您可以通过创建新预订形式的数据,来帮助Little Lemon开发和填充其餐桌预订系统。
可以使用标准的INSERT INTO语句来创建数据。请确保在语法中明确以下几点:
- 要插入数据的表名。
- 必须填充的列。
- 这些列需要包含的值。
执行此语句即可在数据库中创建数据。
示例代码:
INSERT INTO Bookings (GuestName, BookingDate, TableNumber)
VALUES ('John Doe', '2023-10-27 19:00', 5);


更新与删除数据:处理变更
有时,最初创建的数据可能需要更改。例如,客人可能想更新预订,或者取消了预订,因此需要从表中删除其数据。您可以使用UPDATE和DELETE语句来执行这些操作。
使用UPDATE查询来修改表中的信息。在查询中需明确以下信息:
- 要更新的表名。
- 要更新的列。
- 要添加到这些列的新值。
示例公式:
UPDATE 表名 SET 列名 = 新值 WHERE 条件;
如果您要从表中删除或移除信息,则需要使用DELETE查询。您的删除查询必须包含以下信息:
- 包含待删除数据的表名。
- 与该数据相关的任何条件。您可以使用
WHERE子句来设定这些条件。
验证操作:读取数据
在预订表中创建、更新或删除数据后,您需要运行测试以确保查询已成功执行。



您可以通过读取数据来进行这些测试。读取查询会返回与语句中条件匹配的所有信息。一个基本的读取查询示例是SELECT语句。在这种情况下,必须确保SELECT语句包含以下内容:
- 存储数据的表和列的名称。
- 您需要的值。
- 帮助您定位数据所需的任何条件。
示例代码:
SELECT * FROM Bookings WHERE BookingDate = '2023-10-27';
在本课程中,您已经探索了许多读取查询的示例。重要的是要记住,确保在语句中包含能精确定位所需数据的条件。这条建议适用于所有类型的操作。
增强功能:使用触发器
您还可以通过使用触发器来增强事务。MySQL触发器是一组以存储程序形式存在的操作。当某些事件发生时,这组操作会自动调用。

您可以为不同类型的事件(如CRUD操作)使用触发器。要使用触发器,首先需要使用CREATE TRIGGER语句创建它,然后定义触发器类型(是插入、更新还是删除触发器),以及它应该在事件之前还是之后执行。您还需要定义触发器的逻辑,指定它分配给哪个表,以及应如何应用于该表。
版本控制与提交
一旦确认代码正确,您可以将进度提交到Git。实施版本控制也是一个好主意。这样,您可以跟踪显示项目不同开发阶段的快照,并在需要时回滚到以前的版本。
总结
本节课中,我们一起学习了如何利用SQL查询和事务来帮助Little Lemon在其数据库中开发预订表系统。我们涵盖了使用INSERT创建预订、使用UPDATE和DELETE管理变更、使用SELECT验证数据,以及使用触发器自动化操作。最后,我们还提到了使用Git进行版本控制的重要性。现在,您应该已经准备好运用这些知识来构建系统了。如果需要更多信息,请记得复习之前课程的学习材料。祝您好运。
Python 121:模块小结 📊
在本模块中,我们帮助小柠檬餐厅从其数据库中的数据创建了销售报告,并协助他们构建了一个餐桌预订系统。现在,让我们花几分钟时间来回顾一下在本模块中完成的任务、使用的流程和工具。
任务一回顾:创建销售报告
在第一个任务中,我们通过使用虚拟表、连接、存储过程和预处理语句查询数据库,为小柠檬餐厅创建了销售报告。
虚拟表的使用
我们帮助小柠檬餐厅使用虚拟表来查询数据库,以便利用存在于其他表中的数据。虚拟表的好处包括:
- 简化数据访问和查询。
- 能够从虚拟表和基表创建连接。
- 高效地操作和筛选数据。
- 支持数据库安全性。


虚拟表可以通过 CREATE VIEW 语句创建:
CREATE VIEW view_name AS
SELECT column1, column2, ...
FROM table_name
WHERE condition;



连接(JOIN)子句

我们还使用了连接子句,基于一个共同的列来链接一个或多个表之间的数据记录。在本模块中,我们使用了以下几种连接类型:

- 内连接(INNER JOIN):返回两个表中匹配的记录。
SELECT * FROM table1 INNER JOIN table2 ON table1.column = table2.column; - 左连接(LEFT JOIN):返回左表的所有记录,以及右表中匹配的记录。
SELECT * FROM table1 LEFT JOIN table2 ON table1.column = table2.column; - 右连接(RIGHT JOIN):返回右表的所有记录,以及左表中匹配的记录。
SELECT * FROM table1 RIGHT JOIN table2 ON table1.column = table2.column; - 自连接(SELF JOIN):表与自身连接。
- 全外连接(FULL OUTER JOIN):返回两个表中所有的记录。
存储过程
我们帮助小柠檬餐厅使用了存储过程。存储过程用于创建可重用的代码块,可以高效地调用和执行。使用存储过程使代码更加一致、可重用,并且更易于使用和维护。这样,我们无需重复输入相同的代码,而是可以将代码块保存为存储过程,在需要时调用。
我们可以创建多个存储过程,每个过程可以包含多个参数。在创建过程中,我们可以包含各种语法元素,如SQL语句、变量和控制结构,同时确保每个存储过程都有唯一的名称。创建存储过程的方式取决于需要完成的任务。
存储过程的基本创建语法如下:
DELIMITER //
CREATE PROCEDURE procedure_name (IN param1 datatype, ...)
BEGIN
-- SQL statements
END //
DELIMITER ;
预处理语句


我们还协助小柠檬餐厅使用了预处理语句。每次小柠檬创建SQL语句时,MySQL都需要在执行前对其进行编译和解析。我们向他们展示了一种更高效的方法是创建预处理语句。




预处理语句可以重复使用,无需每次编译。这是一种更高效、更优化的执行语句方式,不会占用宝贵的MySQL资源。MySQL在预处理语句执行前仅编译和解析一次。

预处理语句的使用示例:
PREPARE stmt_name FROM 'SELECT * FROM table WHERE column = ?';
SET @value = 'some_value';
EXECUTE stmt_name USING @value;
DEALLOCATE PREPARE stmt_name;



任务二回顾:构建餐桌预订系统
在本模块的第二课中,我们帮助小柠檬餐厅在其数据库中构建了一个餐桌预订系统,用于跟踪到访餐厅的客人。
数据的创建、更新与删除
我们通过创建新预订形式的数据,帮助小柠檬餐厅开发和填充其餐桌预订系统。我们使用标准的 INSERT INTO 语句创建数据,并在语法中明确以下内容:要插入数据的表、要填充的列以及它们需要包含的值。然后,我们执行 INSERT INTO 语句以在数据库中创建数据。
有时,最初创建的数据需要更改。我们能够使用 UPDATE 和 DELETE 语句来执行这些操作。我们使用 UPDATE 查询来更改表中的信息,同时在每个查询中明确关键信息。当需要从表中删除信息时,我们再次使用 DELETE 查询,并确保明确关键信息。
以下是基本语法示例:
-- 插入数据
INSERT INTO table_name (column1, column2) VALUES (value1, value2);
-- 更新数据
UPDATE table_name SET column1 = new_value WHERE condition;



-- 删除数据
DELETE FROM table_name WHERE condition;



数据验证与查询
在预订表中创建、更新或删除数据后,我们运行测试以确保查询成功执行。我们使用 SELECT 语句等读取查询来执行这些测试。在这种情况下,我们确保 SELECT 语句包含以下内容:包含数据的表和列的名称、所需的值以及任何有助于定位数据的条件。
SELECT column1, column2 FROM table_name WHERE condition;

触发器(Triggers)的使用
我们还使用了触发器,将一组操作以存储程序的形式保存起来,当特定事件发生时可以自动调用。要使用触发器,首先使用 CREATE TRIGGER 语句创建它们。然后定义触发器类型,例如,指定它们是插入、更新还是删除触发器,以及它们应该在事件之前还是之后执行。我们还定义了触发器的逻辑,指定了它们被分配到的表以及应如何应用于该表。
创建触发器的基本语法:
CREATE TRIGGER trigger_name
BEFORE/AFTER INSERT/UPDATE/DELETE ON table_name
FOR EACH ROW
BEGIN
-- trigger logic
END;
一旦确信代码正确,我们便提交进度以获得一个已实施的版本控制。


总结
在本节课中,我们一起学习了如何帮助小柠檬餐厅使用数据库查询、存储过程和预处理语句来创建销售报告和餐桌预订系统。我们回顾了虚拟表、各种连接、存储过程、预处理语句的创建与使用,以及如何在预订系统中进行数据的增删改查和利用触发器自动化任务。掌握这些工具和技术对于高效管理和操作数据库至关重要。期待在下一个模块中继续为大家提供更多指导。
Python 122:6_数据分析和可视化 📊
在本节课中,我们将学习如何使用 Tableau 这一强大的数据可视化工具进行高级数据分析,以生成能够指导商业决策的数据洞察。我们将回顾 Tableau 的关键功能、数据处理步骤以及如何创建交互式仪表板。
Little Lemon 需要进行高级数据分析,以生成能够帮助指导其商业决策的数据洞察。


他们可以利用这些数据洞察来指导商业决策,例如识别新的增长机会或改进服务。
这项任务需要使用强大的数据分析工具,例如 Tableau。借助 Tableau,Little Lemon 可以利用其数据分析功能生成洞察。
他们还需要将数据源连接到软件,为分析准备数据,并使用工作表与交互式仪表板来呈现洞察。
在本视频中,你将回顾该工具的关键流程步骤和功能,并了解如何利用 Tableau 来帮助 Little Lemon 生成商业洞察。
Tableau 是一个广泛使用的数据可视化工具。它提供了几个关键功能,用户可以在分析数据时加以利用。
例如,使用 Tableau,你可以连接到多种数据源,处理大量不同类型的数据,并创建可视化的数据图表。
你还可以生成交互式实时仪表板,编写 Python 和 R 脚本,并使用交互式 UI 工具完成任务。



仪表板界面为数据分析提供了许多有用的功能。



你可以使用启动页面中的“连接”窗格将数据源连接到 Tableau。
连接到数据源后,相关字段会出现在“数据”窗格中。
然后,你可以使用创作工作区的 UI 元素,通过工作表创建数据的可视化。
你也可以使用工作表,通过“标记”卡将数据添加到视图中,或者使用行和列功能区来分析和可视化数据。
你可以利用 Tableau 的其他有用功能,例如在工具栏菜单中访问命令和工具,在仪表板视图中处理多个数据源,使用排序图标按升序或降序排列数据,以及使用“故事”来呈现工作表和仪表板。


将数据加载到 Tableau 后,你需要为分析准备数据。


这个过程涉及几个步骤,包括拆分数据以提高可访问性、创建计算数据字段、修复数据类型以及筛选数据。
通过使用软件的筛选和可视化功能,你可以专注于相关数据。通过筛选数据,你可以只关注所需的数据。
你还可以向下钻取、向上汇总和筛选数据,以从不同角度或不同详细程度展示数据。
Tableau 也可以用于通过工作表或源数据页面筛选数据。然而,直接在数据源页面筛选数据会将所有工作表的数据分析限制在筛选后的标准内。
Tableau 的一个关键功能是能够以仪表板的形式生成交互式实时数据可视化。
一个组织良好的仪表板可以帮助清晰展示数据,并为 Little Lemon 的重要商业问题提供相关答案。
在 Tableau 的工作表中分析数据后,你可以合并来自多个来源的数据,添加筛选器,或向下钻取/向上汇总到特定信息。



你现在已经回顾了 Tableau 工具的关键功能。你现在应该知道如何利用这个工具创建工作表和交互式仪表板,以帮助 Little Lemon 从其数据中生成商业洞察。



如果你需要关于这些主题的更多信息,请记住你可以回顾之前课程的学习材料。
本节课中,我们一起学习了 Tableau 数据分析与可视化的核心流程。我们了解了如何连接数据源、准备数据、利用工作表进行可视化分析,以及最终构建交互式仪表板来呈现商业洞察。掌握这些步骤,你将能够有效地利用数据驱动决策。
Python 123:创建数据库客户端 🛠️
在本节课中,我们将学习如何为Little Lemon餐厅创建一个数据库客户端。我们将通过Python应用程序与MySQL数据库进行交互。具体任务包括:检查Python版本、安装合适的集成开发环境(IDE),以及将Python连接到Little Lemon的MySQL数据库。

检查Python版本 🐍
首先,我们需要确认您的计算机上安装的Python版本。这是确保后续步骤兼容性的基础。
打开命令提示符,输入以下命令来检查Python版本:
python --version
如果Python已正确安装,控制台将显示类似 Python 3.x.x 的信息。这表明您正在运行Python 3版本。请确保显示的版本号与Python官方网站(python.org)上的最新版本相匹配。
如果您看到“Python 不是内部或外部命令”的提示,则需要重新检查Python的安装,或参考Python官网的相关文档进行配置。



安装集成开发环境(IDE) 💻



上一节我们确认了Python环境,本节中我们来看看如何安装一个合适的IDE来编写和运行代码。IDE是用于显示和编辑代码的软件。


在本课程中,我们将使用Jupyter IDE来演示Python代码。要安装Jupyter,请在您的Python环境中输入以下命令:
python -m pip install jupyter
然后,按照Jupyter的安装流程进行操作。安装完成后,输入 jupyter notebook 命令,这将在您的默认浏览器中打开一个新的Jupyter笔记本实例,供您使用。
连接Python到MySQL数据库 🔌
现在我们已经准备好了Python和IDE,下一步是将Python连接到MySQL数据库。为此,我们需要使用一个专为MySQL设计的Python库,名为 mysql-connector-python。这个库是一个API,提供了许多操作MySQL的实用功能。
mysql-connector-python 库需要通过Python的包管理工具 pip 单独安装。pip 通常随Python软件一同安装。
首先,在Jupyter中创建一个新的笔记本实例,并将其命名为 configuring_mysql_connector。


以下是安装该库的步骤:


-
在Jupyter笔记本的一个单元格中,输入以下命令来调用pip并安装连接器:
!pip install mysql-connector-python请注意,库的名称中
python的 ‘p’ 是小写。



- 按下
Shift + Enter或点击“运行”按钮来执行这行代码。



验证环境配置 ✅
最后一步是检查您的环境是否已正确配置。我们将尝试导入刚刚安装的库。

在Jupyter的新单元格中,输入以下代码:


import mysql.connector as connector
然后运行该单元格。如果单元格没有输出任何错误信息,则表明 mysql.connector 库已成功导入。这意味着您的Python环境现在已经准备好与MySQL数据库进行交互了。
总结 📝

本节课中我们一起学习了为Little Lemon创建数据库客户端的基础准备工作。我们完成了三个核心任务:检查并确认了Python 3的运行环境;安装并启动了Jupyter IDE作为开发工具;最后,使用 pip 安装了 mysql-connector-python 库,并成功验证了Python与MySQL的连接能力。


如果您对本节课的任何部分需要更多指导,可以回顾之前课程中的具体学习材料。
Python 124:模块小结 🎯
在本模块中,我们帮助小柠檬餐厅进行了高级数据分析以生成数据洞察,并为他们的业务决策提供信息。我们还帮助他们创建了一个数据库客户端,使他们能够通过基于Python的应用程序与数据库进行交互。
现在,让我们花几分钟回顾一下本模块中使用的任务、流程和工具。
第一课:使用Tableau进行数据分析 📊
上一节我们介绍了本模块的目标,本节中我们来看看第一课的具体内容。在第一课中,我们使用Tableau帮助小柠檬餐厅利用其数据分析功能生成洞察。
Tableau是一个广泛使用的数据可视化工具。它提供了几个关键功能,我们在分析数据时得以利用。
以下是Tableau的主要功能:
- 连接多种数据源:能够连接到广泛的数据源。
- 处理大量不同数据类型:可以处理大量不同类型的数据。
- 创建可视化数据图表:能够创建可视化的数据图表。
- 生成实时交互式仪表板:可以生成实时交互式仪表板。
- 支持Python和R脚本:支持使用Python和R编写脚本。
- 使用交互式UI工具完成任务:可以通过交互式用户界面工具完成任务。
我们还利用了仪表板功能来分析数据。我们通过启动页面的“连接”窗格将数据源连接到Tableau。
连接数据源后,我们使用创作工作区的UI元素(如工作表、仪表板和故事)来创建数据可视化。我们使用工作表将数据添加到视图中,利用“标记”卡进行分析和可视化数据,并使用行和列功能区。
然后,我们通过一系列处理步骤为分析准备数据,例如:
- 拆分数据以提高可访问性。
- 创建计算数据字段。
- 修正数据类型。
- 使用Tableau过滤数据。
我们还利用软件的过滤和可视化功能来聚焦相关数据,以便只关注所需的数据。我们使用了下钻、上卷和其他过滤功能,从不同角度或不同详细程度展示数据。
此外,我们使用Tableau以仪表板的形式生成交互式、实时的数据可视化。我们精心组织的仪表板有助于为小柠檬餐厅的重要业务问题提供清晰的视图和相关答案。
第二课:使用Python创建数据库客户端 🐍
在学习了如何使用Tableau进行可视化分析后,本节我们将转向编程工具。在下一课中,我们帮助小柠檬餐厅创建了一个数据库客户端,使他们能够通过基于Python的应用程序与数据库交互。
我们首先使用命令提示符确认了机器上运行的Python版本。在确认正确安装了Python后,我们检查了正在运行的Python 3的具体迭代版本,并确保它与Python官方网站上的最新迭代版本匹配。
确认Python环境后,我们选择了一个IDE(集成开发环境)来运行代码。在本课程中,我们使用Jupyter IDE来演示Python。我们遵循了Jupyter的安装过程,然后输入jupyter notebook命令,在默认浏览器中打开一个新的Jupyter笔记本实例。
接着,我们将Python连接到小柠檬的MySQL数据库。我们使用一个专门构建的Python库——mysql-connector-python——来完成安装。我们能够使用Pip软件包管理器来实现这一点。安装后,我们检查了环境是否配置正确,以确保库被成功导入。
以下是关键的命令行操作:
# 检查Python版本
python --version
# 使用pip安装MySQL连接器
pip install mysql-connector-python
# 启动Jupyter Notebook
jupyter notebook
设置好Python环境后,我们便可以开始使用数据库客户端。我们完成了一个练习,在其中使用Python添加或实现了查询函数来查询小柠檬数据库。最后,我们将进度提交到了Git。

总结 📝
在本节课中,我们一起学习了如何帮助小柠檬餐厅执行高级数据分析以生成数据洞察,从而为他们的业务决策提供信息。同时,我们也帮助他们创建了一个可以使用基于Python的应用程序进行交互的数据库客户端。

做得好。我期待在下一个模块中为您提供更多指导。
Python 125:项目总结与课程回顾 📚
在本节课中,我们将回顾整个数据库工程项目中完成的主要任务、使用的工具和关键技术。通过总结,你将清晰地看到从数据库设计到应用开发的完整流程。
概述
恭喜你,你已接近这门顶点课程的尾声,也即将完成数据库工程师的学习旅程。在这个最终模块中,你需要通过同行评审练习和分级评估来展示你的知识。但在开始之前,让我们先回顾一下你在本课程中帮助小柠檬餐厅完成的任务。





任务回顾

以下是你在本课程中协助小柠檬餐厅完成的一系列核心任务。
数据库设计与构建


在第一个任务集中,你帮助小柠檬餐厅构建了一个关系型数据库系统。具体步骤如下:
- 设计实体关系图:你设计了一个结构良好、符合三大基本范式(1NF, 2NF, 3NF)的实体模型或ER图。
- 使用MySQL Workbench:你使用MySQL Workbench这一统一的数据库建模与管理可视化工具来设计ER图。其关键特性在于能够将数据模型转换为MySQL服务器中的物理数据库模式。
- 创建数据库:一旦在MySQL Workbench中创建了小柠檬数据库,你便使用版本控制系统Git提交了你的项目,并利用GitHub来存储你的Git仓库。
创建销售报告
你的下一个任务涉及从小柠檬数据库的数据中创建销售报告。你使用了以下数据库技术来生成这些报告:
- 视图:你使用了虚拟表来利用其他表中存在的数据,并简化数据访问和查询。
- 连接子句:你使用了不同类型的JOIN子句,基于共同的列来关联一个或多个表之间的数据记录。
- 存储过程:你帮助小柠檬餐厅使用存储过程来创建可重用的代码,他们可以根据需要调用和执行。
- 预处理语句:你还依赖了预处理语句,这些语句只需编译一次,然后可以重复使用。

构建餐桌预订系统




你协助小柠檬餐厅的另一个任务是构建一个餐桌预订系统,用于跟踪来访餐厅的客人。此任务主要包括使用SQL查询和事务。



以下是使用的一些SQL查询和事务示例:
- 插入数据:使用
INSERT INTO语句。 - 更新数据:使用
UPDATE语句更改数据库中的数据。 - 删除数据:使用
DELETE语句删除或移除数据。 - 读取数据:使用
SELECT语句等读取查询来读取数据。 - 触发器:你还使用了触发器,将一组操作以存储程序的形式保存,当特定事件发生时可以自动调用。
在确认代码正确后,你将进度提交到Git以进行版本控制。
生成商业洞察

在接下来的任务中,你帮助小柠檬餐厅利用其数据生成商业洞察。你使用数据可视化工具Tableau来完成此任务。


以下是完成此任务所遵循的步骤:
- 连接数据源:首先将数据源连接到Tableau。
- 准备数据:然后为分析准备数据,并专注于最相关的数据。
- 创建可视化:下一步是使用其UI元素创建数据的可视化。
- 构建仪表板:最后,使用Tableau以仪表板的形式生成交互式、实时的数据可视化。


这些步骤有助于为小柠檬餐厅的重要商业问题提供清晰且相关的答案。
创建数据库客户端
你的最终任务是帮助小柠檬餐厅创建一个数据库客户端,以便他们可以使用基于Python的应用程序与数据库交互。
以下是具体步骤:
- 确认Python环境:首先,确认你机器上运行的Python版本。在确认运行的是最新迭代版本后,安装Jupyter IDE来运行代码。
- 连接数据库:然后,打开一个新的Jupyter Notebook实例,并使用它来连接Python和小柠檬MySQL数据库。你使用Python库
mysql-connector和pandas软件包建立了此连接。 - 开发客户端:设置好Python环境后,你便开始处理数据库客户端。


总结




本节课中,我们一起回顾了在整个数据库工程项目中完成的核心任务,包括:
- 使用MySQL Workbench设计和实现符合范式的数据库。
- 运用SQL高级查询、存储过程和触发器来生成报告和构建业务系统。
- 利用Tableau进行数据可视化分析,生成商业洞察。
- 通过Python和
mysql-connector创建数据库客户端应用程序。 - 全程使用Git进行版本控制。
现在,你已经回顾了所有任务,是时候开始同行评审项目了。请放心,你已经努力走到了这一步,相信你会在项目中发挥出最佳水平。祝你好运!
Python 126:项目完成与回顾 🎉
在本节课中,我们将对您完成的毕业项目进行总结与回顾,并展望未来的学习与发展路径。
恭喜您完成了这门毕业项目课程。您付出了巨大的努力,并在此过程中掌握了许多新技能。您在MySQL的学习之旅中取得了巨大进步。这门课程以及您所取得的成就,实际上是您在本数据库工程师项目中完成的所有先前课程的结晶。
已掌握的核心技能回顾
上一节我们介绍了项目完成的里程碑,本节中我们来看看您在整个项目中巩固了哪些核心技能。
以下是您通过本专项课程所建立的知识体系:




- 数据库工程与MySQL基础:您理解了数据库工程的基本原理和MySQL语法。
- 数据库结构与管理的坚实基础:您对数据库结构和管理有了扎实的理解。
- 高级MySQL:您熟悉了高级MySQL功能。
- Python基础:您掌握了Python编程的基础知识。
- 高级数据建模技术:您理解并能实现高级数据建模技术。
在本毕业项目中,您通过为“小柠檬”设计一个完整的数据库系统,强化并展示了您在整个项目中学到的知识和实践开发技能集。
项目评估与个人反思
项目中的分级评估进一步检验了您在数据库工程方面的知识。既然您已经完成了最终项目,现在是一个停下来反思整个旅程的好时机。
您可以从多个角度来反思已完成的课程:
- 思考本课程与您已完成的其他课程之间的联系。
- 反思完成项目的过程本身。例如,项目中哪些部分最具挑战性?哪些部分相对容易?
- 从项目工作中获得了哪些经验?
- 重新回顾之前的课程是否会带来新的收获?


无论您是刚起步的技术专业人士、学生还是业务用户,这个毕业项目都证明了您对数据库系统价值和能力的理解。该项目不仅巩固了您在实际应用中的技能,还带来了另一个重要的好处:它意味着您拥有了一个可以放入作品集的、功能完整的数据库。


作品集价值与职业发展
这个作品集项目可以向潜在雇主展示您的技能。它不仅向雇主表明您具有自我驱动力和创新精神,也充分展现了您作为个人以及您新获得的知识。
您已经完成了本专项的所有课程,并获得了数据库工程师证书。根据您的目标,您可以选择深入学习高级的角色专项证书,或学习其他基础课程。
认证提供了全球认可且行业背书的、掌握技术技能的证明。您做得非常出色,应该为自己的进步感到自豪。您所获得的经验向潜在雇主表明,您积极主动、能力出众,并且不畏惧学习新事物。
总结与祝福


本节课中我们一起学习了项目完成的总结、核心技能的回顾以及项目对未来职业发展的价值。



感谢您。与您一同踏上这段探索之旅是一种荣幸。祝您未来一切顺利。
Python 127:0_课程介绍
在本节课中,我们将要学习Meta《数据库工程师》课程中关于编程面试准备的介绍部分。我们将了解课程的整体结构、涵盖的核心概念以及学习目标,为后续深入学习打下基础。
课程概述
欢迎来到编程面试准备课程。本课程将帮助你为编程面试中独特且具有挑战性的环节做好准备,包括你需要了解或应用的一些问题解决方法与计算机科学基础知识。
课程内容预览
以下是本课程将涵盖的关键概念与技能概览。
第一模块:面试基础与计算机科学入门
上一节我们介绍了课程目标,本节中我们来看看第一个模块的内容。你将首先了解什么是编程面试、它可能包含的内容以及你可能遇到的各种面试类型。
你还会探索如何为编程面试做准备,重点包括沟通技巧,例如解释你的思考过程、处理错误以及STAR方法。你也将学习如何使用伪代码来演示你如何得出解决方案。
以下是一些有助于任何实际解决方案设计的重要提示,以及如何测试你的解决方案。
接下来,你将学习计算机科学入门知识,从二进制的基本概念开始,了解二进制如何与现实生活中的硬件和计算相关联。
你将探索内存以及计算机内存的关键组件:随机存取存储器(RAM)和只读存储器(ROM),并了解你的计算机如何使用内存来执行任务、处理信息和存储数据。
随后,你将深入学习时间复杂度的核心概念——大O表示法。

公式: O(n), O(log n), O(n²) 等。

你将了解一些大O表示法的类型,以及它如何应用于算法处理。
你还会探索空间复杂度,这本质上是计算结果所需的空间。
第二模块:数据结构
在了解了计算机科学基础后,本节我们将转向数据结构。你将学习数据结构,并理解每种数据结构都伴随着特定的优点和局限性,因此在设计解决方案时理解它们至关重要。
你将从基本数据结构开始,了解不同编程语言中数据结构的实现与能力,以及其总体架构的相似模式。
你将探索主要的基本数据结构:字符串、整数、布尔值、数组和对象。
接下来,你将研究一些集合数据结构,从列表和集合开始。

然后,你将学习栈、队列和树。

代码示例(栈的LIFO原则):
stack = []
stack.append(‘A‘) # 入栈
stack.append(‘B‘)
top_element = stack.pop() # 出栈,返回 ‘B‘
在学习了基础与集合数据结构后,我们将继续学习一些高级数据结构,即哈希表、堆和图。
代码示例(哈希表查找):
hash_table = {‘key1‘: ‘value1‘, ‘key2‘: ‘value2‘}
value = hash_table.get(‘key1‘) # 高效查找,返回 ‘value1‘
第三模块:算法
掌握了数据结构后,本节我们将进入算法世界。你将学习算法入门,包括可用的算法类型以及如何最好地使用它们来排序和搜索数据。
你将首先探索排序算法,了解处理已排序数据或能够对自有数据进行排序如何能显著节省时间。你将探索三种主要排序类型:选择排序、插入排序和快速排序。

你将了解到每种方法都有其权衡,在某些环境下比在其他环境下更有效。
接下来,你将探索搜索算法,了解每种类型如何为其自身的问题解决提供框架。
公式(二分查找时间复杂度): O(log n)
你还将深入了解搜索和排序算法中的时间与空间复杂度。
你将深入探讨分治法、递归、动态规划和贪心算法所涉及的过程与底层机制。

最终模块:复习与测验


最后,在最后一个模块中,你将有机会在参加分级课程测验前,复习在整个课程中学到的所有内容。该测验将测试你在整个课程中学到的所有关键概念和技能。
总结
本节课中,我们一起学习了本课程的广泛概述。具体来说,你了解了本课程将如何帮助你为潜在的编程面试中独特且具有挑战性的方面做好准备,包括你可能需要了解或应用的一些问题解决方法与计算机科学基础知识。
现在,让我们开始学习吧。
Python 128:技术招聘过程介绍 🎯
在本节课中,我们将一起了解大型科技公司(以Meta为例)完整的技术招聘流程。我们将从流程概览开始,逐步深入到申请、面试和录用后的各个阶段,并学习来自Meta工程师们的宝贵建议。
流程总览
上一节我们介绍了课程背景,本节中我们来看看技术招聘的整体框架。根据Meta工程师们的分享,整个招聘过程可以大致分为三个主要阶段。
以下是这三个核心阶段:
- 申请阶段:简历筛选与初步沟通。
- 面试阶段:包含技术、行为和系统设计等多轮评估。
- 校准与录用阶段:面试官讨论并决定是否发放录用通知。
第一阶段:申请与筛选
在申请阶段,招聘人员会对候选人进行初步筛选。这个阶段会淘汰大量候选人,因此精心准备至关重要。
以下是申请阶段的关键环节:
- 简历筛选:招聘人员会审查你的简历和工作经验。
- 初步沟通:招聘人员会与你交流,以更好地了解你的技能、经验以及职业目标,确保你与职位相匹配。
第二阶段:面试环节详解
申请通过后,你将进入正式的面试环节。面试不仅考察编程能力,还评估人际交往、项目推动和团队协作等综合能力。
面试通常包含以下几种类型:
- 技术面试:可能涉及1到4轮甚至更多。例如代码面试,你需要在电话或语音聊天中与招聘人员或工程师一起解决技术挑战。
- 行为面试:面试官会了解你的工作方式以及你如何解决问题。
- 系统设计面试:你需要设计一个端到端的产品,并讨论其完整的系统架构。
核心公式:成功的面试表现 = 技术能力 + 沟通协作 + 问题解决过程
对于特定技术方向的职位(如iOS、Android、ML/AI),除了通用的算法和数据结构问题,你还需要准备该领域相关的专业知识。
第三阶段:校准与录用
所有面试结束后,招聘团队会聚在一起讨论你在各轮面试中的表现,并决定是否向你发出录用通知。
如果你接受了录用通知,你将进入一个称为“Bootcamp”的流程。在这个过程中,你将学习如何在Meta工作,并与你感兴趣的团队会面,最终由你选择加入哪个团队。
来自面试官的建议与常见陷阱
了解了流程后,我们来看看如何更好地准备以及需要避免哪些常见错误。工程师们指出,沟通和结构化思考是许多候选人的薄弱环节。
以下是面试官观察到的常见问题及建议:
- 代码面试中的沟通缺失:候选人不解释思路、不提问澄清问题、或不听取面试官的提示。
- 缺乏结构化解题过程:面对陌生问题时,没有清晰的解决步骤,直接开始“蛮干式”编码。
- 过于执着:遇到困难时陷入僵局,无法接受反馈。面试官看重的是你解决问题的整体方法,而不仅仅是最终答案。
核心建议:在模拟面试或练习时,即使遇到难题,也要完整地走完整个面试流程,这能为真实面试提供极佳的练习。

心态与长期准备
最后,我们来谈谈心态和长期职业规划。保持真实自我并选择与个人价值观相符的公司至关重要。
以下是关于心态和准备的建议:
- 做真实的自己:以真实的面貌呈现自己,这会减轻压力并增加成功几率。
- 明确个人价值观:在选择公司时,除了薪酬和声望,还应考虑那些影响你工作幸福感的因素。
- 大量练习与申请:尽可能多地进行模拟面试,并向多家公司投递简历。每一次实战都是宝贵的经验。
- 保持学习与坚持:面试过程必有起伏,这些都是可以学习的经验。持续学习和推动自己,终将开启精彩的技术生涯。
代码块示例:模拟面试心态
# 保持积极,从每次经历中学习
def learn_from_interview(feedback):
if feedback == "success":
celebrate_and_prepare_for_next()
else:
analyze_weaknesses()
practice_more()
return growth
# 坚持是成功的关键
while not job_offer:
keep_applying()
keep_learning()
总结

本节课中我们一起学习了大型科技公司技术招聘的完整流程,包括申请、面试和录用三个阶段。我们深入探讨了技术、行为和系统设计等面试类型,并了解了面试官看重的核心能力——技术实力、沟通协作和结构化的问题解决过程。最后,我们获得了保持真实自我、进行大量练习以及明确个人职业价值观的重要建议。记住,充分的准备将使你有能力在世界范围内产生巨大影响,因为软件无处不在,被数十亿人使用。祝你面试顺利!
Python 129:什么是编码面试 👨💻
在本节课中,我们将学习什么是技术面试,并掌握一套系统的方法来应对编码面试。我们将从面试的目的开始,逐步介绍准备和解题的核心步骤,包括概念理解、工具运用和代码优化。

概述

技术面试是您展示编码能力以证明自己胜任某个职位的环节。通常,您已经通过了初步的筛选电话面试,证明了您的软技能符合公司要求。软技能指的是您的社交行为能力,包括清晰的沟通、良好的职业道德,以及您的个人表现与公司价值观是否一致。技术面试的目的则是确定您在技术上能否承担该职位的责任。
面试方法步骤
面对编码面试时,牢记以下步骤将对您有所帮助。

以下是应对编码面试的四个关键步骤:

- 准备成功:为面试做好充分准备。
- 先进行概念性解题:在编写代码前,先在概念层面理解并解决问题。
- 运用合适的工具:选择恰当的数据结构和算法。
- 优化解决方案:改进代码的效率和质量。
深入理解这些概念将帮助您掌握如何应用这套方法。
第一步:准备成功
许多候选人在参加技术面试时可能会感到忐忑。如果被问到问题而大脑一片空白怎么办?幸运的是,您可以采取一些步骤来为成功做好准备。未能准备就是在准备失败。
第二步:先进行概念性解题
在实施具体解决方案之前,先对问题进行概念性思考是一个好主意。您需要先对问题和答案的形态有一个清晰的认识。
花些时间确保您清楚问题的要求。面试官不会介意您从一开始就寻求澄清。如果有白板,请使用它。在勾勒潜在解决方案之前,先记下问题的主要要点。
这是一个绝佳的机会,可以在编写任何一行代码之前,展示您使用伪代码推理问题的能力。展示您解决问题的能力已经成功了一半。请记住,编码能力可以后天培养,而解决问题的能力则是备受追捧的才能。在分析问题时,请大声说出您的思考过程,向面试官展示您如何参与问题解决,以及为什么选择某种方法而非另一种。
如果您能将问题与已知的问题联系起来,将会大有帮助。在本课程后面,有一个关于“分治法”实践的视频。现在就是运用它的好时机。将大问题分解成小问题有助于解决看似复杂的问题。如果存在额外的时间限制并且您超出了允许的时间,您仍然能够展示出功能完整的代码块。
第三步:运用合适的工具
编码面试中提出的问题类型需要在面试时间内完成。因此,解决方案本质上不会过于复杂。它们旨在微观层面测试您解决问题的能力以及您对可用工具的认知。
考虑经典的“数袜子”问题。您会获得一个代表袜子颜色的数组。黄色袜子用数字1表示,蓝色袜子用2表示,红色袜子用3表示,绿色袜子用4表示,橙色袜子用5表示。袜子颜色对应的数字如下:1,2,2,1,1,3,5,1,4,4。请确定存在多少双相同颜色的袜子。
这里有四个1,相当于两双黄袜子。数字3和5代表无法配对的单只袜子(一只红袜和一只橙袜)。有两个2和两个4,分别代表一双蓝袜子和一双绿袜子。
为了简洁地解决这个问题,您可以利用合适的数据结构。在本课程后面,您将复习数据结构。有一个视频概述了字典如何存储键值对。一种解决方案是将袜子颜色作为键,数量作为值存入字典,然后遍历字典并找出所有计数为奇数的键(表示存在无法配对的袜子)。
尽管有很多编程方法可以解决这个问题,但使用现有的数据结构可以最大限度地减少所需代码,并展示对基础构建模块的熟悉程度。只要可能,尽量利用现有的方法,而不是尝试手动实现解决方案。
除了熟悉常用的数据结构外,在进行任何技术面试之前,请复习常见的排序和搜索算法。
第四步:优化代码

优化代码是一种良好的实践;这意味着编写或重写代码,使程序使用尽可能少的内存或磁盘空间,并最小化CPU时间或网络带宽。
编写出解决方案是迈向一个体面解决方案的良好一步。请确保留出时间来优化您的代码。您将在本课程中遇到的另一个概念是时间和空间复杂度。您能否向面试官证明您理解这些关键概念?简单来说,这是一种衡量您的解决方案运行速度和占用空间的方法。
在呈现答案时,概述您解决方案的时间和空间复杂度,然后看看是否可以改进。



识别任何重复或重叠的代码。您可以将这些代码模块化成一个可重复调用的函数,并在可能时重用代码。优秀编程的一个常被重复的原则是DRY(Don‘t Repeat Yourself)。其思想是在代码中只表达一次,然后根据需要尽可能多地重用。此外,如果您的代码中有部分由于模块化或未完成的思路而不再需要,请将其删除。
避免过多的循环调用。如果您要在数组中搜索一个值,请在找到该项时终止循环。一个非常容易实现的代码优化是,在找到值时包含一个返回语句,或者使用一个依赖于布尔值的循环。一旦找到结果,循环就可以终止。这提高了整体效率并降低了时间复杂度。
空间复杂度完全是关于巧妙地使用内存。只要有可能,避免创建超出需要的变量。
总结
在本视频中,您学习了一些无论面对何种挑战都可以使用的方法。即使您不熟悉某个问题,或者在规定时间内没有得出结果,也要始终努力展示您的推理过程和最佳实践方法。
通过在线解答练习题来为技术面试做准备,并在可能的情况下,对每个挑战采用类似的方法论。这样,无论面对何种挑战,您都能在一个熟悉的框架下工作。编码面试可能看起来是一项艰巨的任务,总会涉及未知因素,而您对成功的渴望可能会带来一些面试前的紧张情绪。请保持冷静,进行逻辑思考。

祝您好运。 🍀
Python 130:3_交流
在本节课中,我们将学习面试成功的关键要素——沟通。面试的成功与否,几乎完全取决于你如何与面试官交流。你希望传达你的胜任力,而公司则希望找到适合该职位的候选人。本节视频将介绍语言沟通和非语言沟通的技巧。
第一印象的力量
永远不要低估第一印象的力量。作为潜在雇员,你与面试官的每一次互动都应反映出你将为组织带来的能力。你能展示的第一个非语言信号就是守时。
守时:最好在预定会议开始前至少10分钟到达,尤其是在你不确定面试具体地点的情况下。找到地点需要时间,你希望自己看起来沉着冷静、准备就绪,而不是气喘吁吁、在整个面试过程中都显得慌乱。
非语言沟通技巧
上一节我们提到了守时,本节中我们来看看其他重要的非语言沟通技巧。确保在面试过程中保持眼神交流,并积极倾听被问到的问题。
着装得体:通常,工作面试要求你穿着专业或商务装。确保你的衣服干净整洁。这显示出尊重,并为你自己树立了积极形象。
保持良好姿态:保持良好的姿势,避免坐立不安、不必要地触摸脸部或绞手。虽然在会议前和会议中感到紧张是可以理解的,但这些手势可能会无意中传达出你觉得自己无法胜任这项任务的感觉。
缓解紧张:一个缓解紧张的好方法是在会议前做好充分的准备。确保你了解工作的内容、公司的业务及其所代表的价值观。
语言沟通技巧
尽管理解非语言沟通的重要性很关键,但语言沟通同样重要。你需要能够与面试官交谈。
观察与倾听:在面试中如何表现自己的一个良好指标是观察面试官。仔细倾听。他们会通过提问来了解你是否符合所需的技能和个性特征。通常,面试官会遵循80/20法则:他们说话占20%的时间,让你展示自己占80%的时间。因此,在回答之前,请让面试官完全把问题引导给你。
清晰简洁:在回答中使用清晰简洁的语言。一个常见的诱惑,尤其是在你做了充分准备的情况下,是试图用你所知道的关于该主题的一切来回答问题。这可能导致回答冗长、偏离主题。更好的回答是紧扣主题,并为后续提问留出机会。一个好的面试官会跟进相关问题,这样可以让对话流畅进行。
实事求是:避免夸大你的能力或对自己持消极态度。注意不要使用可能传达对自己负面态度的情绪化词语。例如,与其说“我在那个任务上失败了”,不如说“那个任务很有挑战性,但它为我未来探索的研究领域提供了一些思路”。此外,避免使用过多的俚语、脏话或不恰当的幽默。
STAR回答法
在面试中遵循的一个好方法是STAR方法。最初,面试官会试图让你感到受欢迎,给你机会谈论自己:你的简历上有什么?你对公司或职位了解多少?随着面试的进行,讨论将更多地集中在你的能力和对职位的适合度上。重要的是,你要能够传达为什么你是一个合适的人选。通常,问题会集中在业务需求上,无论是正在使用的技术还是必须克服的问题。面试官想知道你在工作中遇到问题时将如何应对。
因此,尝试使用STAR方法来回答问题。在回答问题时包含以下四点:情境、任务、行动和结果。
以下是更清晰地演示该方法的一些示例:
- 情境:当时的情况背景是什么?是什么项目?面临哪些挑战?
- 任务:你的职责和任务是什么?
- 行动:你采取了哪些行动来纠正或应对挑战?
- 结果:你的行动带来了什么结果或成果?采取这种方法对结果产生了什么影响?
使用这种方法作为回答的模板,将使你的回答更有深度。它提供了一个可行的回答框架。同时也给了面试官机会,就你感觉舒适的讨论领域提出更多相关问题。
总结

本节课中我们一起学习了面试沟通的核心要点。面试官会寻找能够清晰传达概念的候选人。你的首要任务是通过沟通说明你为什么适合这个职位。这需要通过语言和非语言两种方式来完成。最后,STAR方法是应对面试过程中出现的技术性问题的一个非常高效的框架。

在任何公司的任何职位上,你可能都需要与利益相关者打交道,无论是处理工作中的复杂问题,还是解释为什么某个解决方案是最优路径。因此,请将你学到的关于沟通的知识自信地应用到实践中。
Python 131:技术面试期待什么 🎯
在本节课中,我们将学习Meta工程师们分享的技术面试经验,了解面试的构成、准备方法以及面试官看重的核心素质。我们将拆解技术面试、架构面试和行为面试,并提供实用的准备建议。
面试类型概览 📋

根据一家知名招聘网站的数据,近一半的软件开发人员认为编码面试是所有技术面试环节中压力最大的部分。面试中,你将被问到许多技术问题、架构问题和组织问题。面试官希望了解你的个人特质和价值观。
上一节我们了解了面试的整体压力来源,本节中我们来看看Meta面试通常包含的三种主要类型。
技术面试
技术面试即常规的LeetCode编码问题。在面试流程中,你通常会遇到2到4轮此类面试。其中一到两轮是初步筛选,通过初筛后还会有几轮。每道题的答题时间约为20到30分钟,内容就是经典的编码问题。
架构面试
架构面试时长约45分钟到1小时。你会被问到如何构建一个端到端的功能。问题可能更偏向产品导向(例如:构建俄罗斯方块),也可能更偏向后端导向,重点关注数据流和如何为海量用户扩展系统。
行为面试
在行为面试中,你可以预期会被问到关于你与他人合作的经验、曾面临的挑战以及参与过的激动人心的项目等问题。
面试官视角与经典问题 👥
为了让你更好地理解面试官的期待,我们来听听Meta的工程师们分享他们的看法和常问的问题。
Maria Ballardo(软件工程师,FB Web3货币化团队):“我通常会问的一个问题是:‘你在团队合作中,事情进展不顺利的一次经历是什么?’ 我问这个问题的主要原因是,在Meta,你需要与很多人合作,这不是一份孤立的工作。因此,你需要学习如何沟通,以及如何真正与他人一起学习和成长。”
Maxxie Herrera(软件工程师,社会影响力奖团队):“当我面试时,我被问到了很多我作为iOS工程师预期会遇到的通用问题。例如,‘我将如何构建Facebook应用中的新闻推送界面?我会创建哪些对象?这些对象将如何相互通信?我期望使用哪些网络API?’ 能够从高层次描述我将如何应对这些挑战,以及作为iOS工程师我将如何构建应用程序的结构,这是一个非常经典的问题。”
高效准备策略 💡
上一节我们了解了面试官会问什么,本节中我们来看看如何有效地为这些面试做准备。
练习阐述解决方案
一个练习面试问题的好方法是,在白板编程时大声讲解你的解决方案。你可以与朋友或同事一起练习。当你写出解决方案时,解释你的思考过程:你在考虑时间复杂度吗?你在考虑如何让它更快、如何减少空间占用吗?作为面试官,我们也希望看到这些,因为在实际工作中编码时,你需要思考这些事情。这是一个很好的练习,让你在讲解代码时能说明“我这样做是因为X、Y、Z,同时我也在考虑这一点”。
面试中的沟通技巧
有时在技术挑战中你会卡住。你能做的最糟糕的事情就是什么都不说。因为面试官无法读懂你的想法,也不知道你在做什么。你应该解释你在思考什么、你卡在哪里、为什么卡住。因为即使你没有得到正确答案,如果你能表现出对问题的良好理解,这足以让你进入下一轮。
着装与态度
在面试着装方面,关键是要做自己,穿你觉得舒服的衣服。没有人指望你穿着西装出现。我见过很多面试者只是穿着T恤和牛仔裤。我真正寻找的候选人是愿意解释他们的想法、愿意深入参与并展现出高度自信和知识水平的人。
常见误区与加分项 ⚠️⭐
了解了如何准备,我们还需要避开一些常见陷阱,并了解哪些表现会真正打动面试官。
最常见的错误
我看到人们最常犯的错误是,他们可能是一名非常有才华的iOS工程师,但他们的通用软件技能可能有所欠缺。因此,请确保你为那些通用的算法和数据结构类型的问题做好准备,因为无论你面试的是哪个职位方向,这些问题都会出现。
真正打动面试官的特质
- 充分的准备与研究:当候选人为面试做了充分准备,他们显然应该如此。但当他们对公司做了研究,了解公司的价值观,并知道如何将这些价值观应用到自身以及他们能为Meta带来什么时,这让我印象深刻。
- 接受反馈的能力:在面试中,真正让我印象深刻的候选人是那些能够接受我反馈的人。即使他们已经走在正确的轨道上,有时如果我能看到这一点并稍微推动他们一下,这是一个非常好的迹象,表明他们能听取我的反馈并与我合作解决手头的任何问题。这很好地表明这是我在现实生活中愿意与之共事的人。
- 热情与积极:一个充满热情、对参加面试感到兴奋并具有非常积极态度的候选人,这真正显示出他是否是我想要共事的人,一个会对所做工作充满热情的人。我认为这正是通往成功的激情所在。

面试的本质与收获 🌟
面试实际上是展示你是谁的过程,是展示你的知识、成长和学习方式的过程。这没有任何单一的技巧。你真的需要了解自己一点,以及你如何展示这些特质,并让它为你所用。
在面试的另一端,尽管过程可能很长,但能够开始在像Meta这样的地方,着手开发人们每天使用的产品,是非常有回报的。在这里,事物的规模如此之大,看到你构建的功能被数百万用户使用,这真的很酷。你可以与我一生中见过的最聪明的人一起工作,这将帮助你成长为一名工程师。你会惊讶于在这里短时间内能学到和成长多少。
总结 📝
本节课中,我们一起学习了Meta技术面试的核心要点:
- 面试类型:包括技术编码面试、架构设计面试和行为面试。
- 面试官期待:他们希望考察你的技术能力、系统设计思维、沟通协作能力以及与公司文化的契合度。
- 准备方法:通过练习讲解解题思路、加强通用算法与数据结构知识、研究公司背景来做好准备。
- 关键技巧:面试中保持沟通、积极思考、坦然接受反馈,并展现出你的热情和专业素养。
- 面试本质:面试是一个双向展示与选择的过程,真诚地展示你的能力和潜力至关重要。
感谢观看,希望你能学到一些在Meta面试的好技巧,祝你接下来的旅程好运。
Python 132:二进制基础
在本节课中,我们将要学习二进制数,了解它们是什么,以及计算机如何使用它们来表示人类语言。我们将探讨位置编码如何将有限的数字集合转化为无限大小的数值表示。最后,我们将学习如何通过计算一个数的幂,来确定这种简单表示法可以容纳多少种状态。
十进制计数法
上一节我们介绍了课程目标,本节中我们来看看人类最熟悉的计数系统——十进制。

传统上,我们使用0到9这10个不同的数字进行计数。这源于数学的早期发展,是人类拥有10根手指和10根脚趾的自然结果。使用10个数字进行计数被称为十进制。
公式:Base 10

十进制意味着在使用完10个不同的数字之前,你不需要添加新的数位。每次数字范围用尽时,你都会重置左边的数字,并在右边添加一个0。这个新的数位必须比它右边的数位大10倍。右边的数字被重置,计数重新开始。

以下是十进制计数的过程示例:
- 从0开始,依次增加到9。
- 到达9后,个位重置为0,十位从0变为1,得到10。
- 这个过程持续下去,形成11, 12, ... 99, 然后变为100。
使用数字的位置来表示数值的渐进增长,这被称为位置记数法。当我们思考它时,会发现这是一种允许记录无限多数值的早期算法实现。它实现简单,但效果非常强大。

二进制计数法

上一节我们回顾了十进制,本节中我们来看看计算机的核心语言——二进制。
二进制使用相同的位置记数法原理。它是另一种常见的计数方法,被称为二进制。
公式:Base 2
这意味着所有的值都只用1或0来表示。计算机以字节为单位存储信息。每个字节由8个位组成,每个位可以是1或0。
就像在十进制中计数到9后会添加一位并重置一样,二进制中也会发生同样的事情。但在这种情况下,只使用两个数字来推进计数:你将数字向左移动,将1向左移动,直到所有1和0的组合都被使用完毕,此时你在末尾添加另一个0。在这个阶段,除了开头的一个1之外,所有数字都重置为0。

让我们一步步探索它。以下是二进制计数的步骤:
- 从
0开始计数。 - 加1得到
1。 - 再加1,个位从1变为0,并向十位进1,得到
10(读作“一零”,代表十进制中的2)。 - 在
10的基础上加1,得到11(十进制3)。 - 再次从0开始,但在左边加一个1。一旦所有的1都满了(即
11),就再次回到0,并向左边的数字加1,但那个数字已经是1了。所以它也回到0,并向左边的下一个位置加1,得到100(十进制4)。
二进制在计算中的应用
上一节我们学习了二进制如何计数,本节中我们来看看它的实际用途。
二进制在计算中有许多用途。它是将电信号转化为计算机代码的一种非常方便的方式。如果存在信号,则显示为1,否则使用0。

二进制计数系统允许这些基数为二的信号承载、传输和存储大量的信息。布尔值的存储方式与此相同。一个布尔值要么是1(代表真),要么是0(代表假)。利用这种简单的信息表示法,可以构建一些强大的应用程序。
ASCII码(美国信息交换标准代码)是一种二进制到字符的编码映射,或者说是一种从二进制到文本的映射。它为每个数字、字符以及许多特殊字符(如问号、括号、句点甚至空格键)都保留了一个二进制数字。前面提到,一个字节由8位组成。每位可以取0或1的值。

计算可能的状态数
上一节我们了解了二进制如何表示字符,本节中我们来解答一个关键问题:一个字节能表示多少种不同的值?
这就引出了一个问题:在这里的每个字节中,可以表示多少种不同的值?为此,我们将使用指数运算,即计算一个数的幂。
一个例子是 2的3次方。即 2 * 2 * 2,等于8。
现在,假设你有一个由四个不同数位组成的密码锁。每个数位可以是0或1。这个锁可能有多少个潜在的密码数字?
答案是 2的4次方,即 2 * 2 * 2 * 2 = 16。你正在处理一个二进制锁,因此每个数位只能是0或1。所以你可以取四个数位,每次乘以2,总数是16。
每次增加一个可能的数位,你都会增加可能的排列组合。所以,同样的锁如果有五个数位,将会有 2的5次方,即32种不同的组合。
现在,回到我们最初的问题:一个字节中可以有多少种不同的表示?前面提到,一个字节由8位组成,每位可以是0或1。8位将会有 2的8次方,即256种不同的组合。
总结
本节课中我们一起学习了二进制数,即计算机的语言。虽然乍一看它似乎仅限于0和1,但我们了解到,通过使用位置编码,它可以用来表示更大的数字集合。

我们学习了计算机如何利用电信号来存储和读取数字,以及指数运算(计算一个数的幂)如何与计算唯一状态数相关联,并如何用它来计算一个数字锁可能拥有的组合数量。
二进制是计算机的语言,理解它如何用于存储信息,将使你在讨论数据及其存储结构时拥有更深刻的理解。
Python 133:6_内存
在本节课中,我们将要学习计算机内存的核心概念,包括中央处理单元(CPU)的角色以及不同类型内存的功能与区别。我们将从最基础的比特和字节开始,逐步深入到缓存、主存和辅存,帮助你理解计算机如何高效地处理和存储信息。
计算机与CPU基础
在之前的视频中,我们介绍了字节。每个字节由8个比特组成。比特是计算机内存最简单的形式。
计算机通常由一系列内存块组成,这些内存块既包含信息,也包含如何处理这些信息的指令。内存容量指的是计算机能够容纳的字节数量。
为了理解内存的各个层级,首先需要了解计算机的工作原理。计算机围绕中央处理单元(CPU)运行。CPU接收信息以及如何处理这些信息的指令。所有这些信息都以字节或一系列由微小电流决定的1和0的形式存在。
内存层级与传输速率
CPU处理信息的速度可以快于信息传输给它的速度。CPU通常会近乎同时地处理多个不同的任务。在不同任务之间切换,可以让信息被传输到缓存中进行处理,并将结果存储到适当的位置。
内存单元与CPU的物理距离会影响信息加载所需的时间。因此,更快、更昂贵的内存总是位于CPU附近。讨论内存时,一个重要的概念是传输速率。这关系到计算机将内存传输到缓存中进行处理的速度。
现在,你对处理部分有了更好的理解,接下来让我们探讨不同类型的内存,首先从缓存开始。
缓存内存
缓存内存是最昂贵的内存形式,位于CPU芯片附近。当CPU收到处理某些信息的指令时,它首先检查缓存中是否存在该信息。如果信息在缓存中可用,则直接处理。如果在此处未找到所需信息,则信息不会被处理。CPU随后会查询更大、更慢的主内存,然后将该信息加载到缓存中进行处理。
将最近访问的信息存储在缓存中,可以减少常用数据的搜索和传输时间,从而提高系统效率。就像大都市的地铁一样,缓存内存按重要性分区组织。最急需的信息位于1区,随后的每个区域重要性递减,编号为2区、3区、4区等。
主内存
接下来,你将了解主内存。计算机的主内存由随机存取存储器(RAM)和只读存储器(ROM)组成。主内存仅保存计算机当前正在处理的信息。它可以是易失性的或非易失性的。
- 易失性内存:主动存储信息,如果计算机断电,信息就会丢失。
- 非易失性内存:在断电时保留其信息。
ROM,顾名思义,是只读的,意味着信息不能被覆盖。这种内存通常在工厂编程一次,无法更改。通常,你会在这里找到对计算机功能至关重要的指令和数据。ROM在计算机启动并加载所需应用程序的信息时最为繁忙。
RAM是可编程的。它可以保留新的信息和指令。RAM保存当前正在使用的数据和指令。计算机拥有的RAM数量与其运行速度直接相关,这归因于传输速率。大量的RAM意味着系统不需要不断地传输信息。相反,它可以使用RAM同时保存和运行多个应用程序。运行这些应用程序所需的所有内存都需要从你的RAM中获取。打开过多的程序会耗尽你的RAM内存,从而影响系统性能。
有许多用于读取和存储这些内存地址的算法,这超出了本课程的范围。
辅助内存
现在,让我们更深入地探讨辅助内存。辅助内存指的是可以外部插入、用于增加系统存储容量的外部存储器。访问辅助内存速度较慢,并且需要将所有所需信息和指令传输到RAM中。

以下是辅助内存的例子:
- 云存储
- 外置硬盘
- U盘
总结

本节课中,我们一起学习了内存的各个组成部分。你了解了所有内存分配都围绕CPU进行,CPU负责监督计算机上信息的读取、处理和存储。你也学习了不同类型的内存,它们在速度和重要性上各不相同。这决定了它们与CPU的距离,更快、更昂贵的内存单元更靠近源头。这些信息应该能帮助你更好地理解计算机的工作原理。
Python 134:时间复杂度 ⏱️
在本节课中,我们将学习如何评估算法或任务的效率,特别是时间效率。我们将介绍时间复杂度的概念,以及如何使用大O表示法来衡量代码在不同输入规模下的运行时间。理解这些概念对于开发高性能应用程序至关重要。
评估效率的维度
在计算机科学中,评估效率通常考虑两个方面:时间和空间。本节我们将重点讨论时间效率,即衡量完成一项任务所需的时间。这被称为任务的时间复杂度。
一个应用程序必须在可接受的时间范围内返回信息。如今,用户点击网站时期望得到即时响应。不过,根据用户需求和期望,对于更复杂的查询,可能会给予一些额外的时间宽容度。
理解大O表示法 🧮


大O表示法是衡量算法效率的指标。简单来说,它估算了你的代码在不同输入集上运行所需的时间。在本视频中,我们关注算法将花费的时间量。
以下是一些你将遇到的大O表示法:
- O(1)
- O(log log N)
- O(log N)
- O(N)
- ...等等

常见的时间复杂度分析
上一节我们介绍了大O表示法的概念,本节中我们来看看几种具体的时间复杂度及其含义。
常数时间:O(1)
如何衡量某件事可能被计算的最快时间?你需要使用常数时间算法,其计算时间为O(1)。简单来说,这意味着无论向系统输入什么,都只需要一次计算。
一个简单的例子是打印数组中的第一个元素。在这个例子中,无论数组中有多少个值,该方法的时间复杂度都是O(1)。
# 示例:O(1) 操作
def print_first_item(array):
print(array[0]) # 无论数组多大,只执行一次操作
线性时间:O(N)
如果你需要进行搜索,情况会变得更复杂。假设你有一个包含10个项目的数组,并且你想知道某个特定值是否在这个数组中。你可能会应用一个循环,并检查每个项目以查看该值是否存在。在这个例子中,复杂度被称为O(n)。这被称为线性时间。
搜索所需时间将等于数组的长度。数组越大,搜索所需的时间就越多。所以,如果数组有100个项目而不是10个,那么搜索将花费10倍的时间。


让我们探讨一个例子。每个操作在时间复杂度上都有一个“时间代价”。所以,O(1)意味着它花费一次计算,而O(n)意味着它花费n次计算。例如,你不会说它花了45秒,你会说复杂度是n。所以,对于每一个n操作,我们的最终复杂度结果就加一。
如果n等于100,那就是100次检查。复杂度仍然是O(N)。只是n意味着它长了10倍。这意味着你的应用程序速度取决于正在处理的数据大小。
打印数组第N个位置是O(1)操作的一个例子。这意味着打印第n个元素。无论n有多大,代价始终是1。
对数时间:O(log N)
这种搜索的强度低于O(n),但比O(1)差。O(log n)是对数搜索,因此它会随着新输入的添加而增加,但这些输入只带来边际的增长。

一个很好的实例是二分查找。想象你正在玩一个猜数字游戏,提示是:太高、太低、正确。给定一个从1到100的范围。

你可能会决定系统地处理这个问题。首先,你猜50,太高了。然后你猜25,仍然太高。然后你决定猜12或13,仍然太高。这里发生的情况是,你每猜一次,搜索空间就减半。
所以,虽然这个函数的输入是100,但使用二分查找方法,你应该在6到7次猜测内找到答案。这个解决方案的时间复杂度可以说是O(log N)。即使n(输入的数字范围)变大10倍,所需的猜测次数也不会增加10倍。
二次时间:O(N²)
O(N²) 计算量很大。这是一种二次复杂度,意味着对于数组中的每个元素,工作量都会翻倍。
可视化这一点的一个好方法是考虑你有一个数组的数组。第一个循环将等于输入元素的数量,即N。第二个循环也会查看输入元素的数量N。因此,运行这种方法的总体复杂度可以说是n乘以N,即n²。
复杂度对比与最佳/最坏情况
那么如何直观地表示这个问题呢?下图展示了时间复杂度的算法。X轴与输入数量相关,Y轴与所花费的时间相关。
请注意,随着输入数量的增加,它对所有情况下的线条梯度都有不同的影响,除了O(1)。在这个关于N与所进行计算次数关系的图形表示中,最佳目标是O(1)。O(log N)仍然非常好。O(n)可以接受,而O(n²)则不太理想。

当然,并不总是能判断一个方法需要多长时间。让我们回到在循环中查找某物的例子。虽然你可以说搜索一个循环需要O(n)时间,但这可能并非总是如此。
考虑被搜索的项目是数组中的第一个元素。那么返回将在O(1)时间内完成,非常好。同样,元素可能缺失,因此必须搜索每个项目,即O(N)时间。中间情况是它在循环的中间附近被找到,即O(N/2)。
在评估一种方法时,会使用三个定义:最佳情况、最坏情况和平均情况。
总结
在本节课中,我们介绍了与复杂度相关的时间概念。在实施问题解决方案之前,我们获得了一些需要考虑的因素。开始之前要问自己的一个好问题是:我的解决方案采用了多少次计算,是否有更好的方法?

现在你使用了一个指标来评估你对给定问题的解决方案,你可以开始思考它在时间复杂度方面的效率了。这不是考虑解决方案的唯一方式,在下一个视频中,重点将放在空间复杂度上。
Python 135:空间复杂度 📊
在本节课中,我们将学习算法评估的另一个关键维度:空间复杂度。我们将了解如何衡量算法对内存的使用,以及它与时间复杂度的权衡关系。
概述
上一节我们介绍了时间复杂度,它衡量算法执行所需的时间。本节中,我们来看看空间复杂度,它衡量算法执行所需的内存空间。评估一个解决方案的适用性时,空间占用是需要考虑的另一个重要因素。
空间复杂度的概念
一个给定解决方案会占用多少内存?这通常与时间效率存在权衡关系。数据结构的选择将取决于你的优先级是速度还是紧凑性。
例如,本课程后面将学到的哈希表等算法,能在 O(1) 时间内提供非常快速的查找。然而,为了高效工作,它们必须为存储的每个元素预留查找空间,这导致了 O(N) 的空间复杂度。
大O表示法与空间
空间复杂度的大O表示法与时间复杂度的相同,包括 O(1)、O(log N)、O(N) 等。在这些表示法中,N 指的是输入数据的大小,通常以字节为单位衡量。
不同编程语言有不同的内存开销。例如,在Java中:
- 一个整数需要 4 字节内存。
- 一个空数组会消耗 12 字节用于头对象,外加 4 字节用于填充。
因此,如果 N 指的是一个大小为4的整数数组,那么总内存需求是 32 字节。
讨论空间复杂度时,必须考虑输入大小增加对整体使用量的影响。
辅助空间与输入空间
问题的空间复杂度可以分为两个部分:辅助空间和输入空间。
- 辅助空间 是保存解决方案所需的所有数据的空间。它指的是计算给定解决方案所需的临时空间。
- 输入空间 指的是向正在评估的函数、算法、应用或系统添加数据所需的空间。
考虑学习长除法时,你可能学过一种系统性的方法,将每个计算分解为更简单的步骤。为此,你会创建一个表格来存放临时计算结果。一些复杂问题同样需要分配额外的空间来临时存放计算过程中的中间数据。
大O空间复杂度允许包含得出给定解决方案所需的辅助空间。因此可以说:空间复杂度 = 输入空间 + 辅助空间,即计算一个结果所需的总空间。
空间复杂度计算示例
还记得我们计算过一个整数数组的空间复杂度吗?一个整数占4字节,加上12字节的头对象和4字节填充,总共是32字节。然而,考虑将数组大小加倍到8个整数。
空间复杂度以同样的方式计算,总数将是48字节。空间复杂度变高了。增加额外的输入并没有增加辅助空间的大小。因此,在计算大O时,如果辅助空间的大小不受输入大小增加的影响,可以将其忽略。
影响内存使用的常见操作
知道计算解决方案时所做的每个决策都需要内存,值得注意那些会增加内存使用的方面。
以下是常见的增加内存使用的操作:
- 分配变量:在计算解决方案时创建临时变量,就像之前长除法的类比。
- 创建新的数据结构:一些解决方案需要创建一个新数组来存放值,或者一个保留索引位置的副本数组。创建一个新的数据结构实例会产生 O(N) 的辅助内存成本。
- 函数调用和分配:函数调用和内存分配也会产生额外的内存开销。
在设计应用程序时,牢记空间是如何被使用的非常重要。创建一个新变量来存放值,而不是覆盖现有的变量,会影响你的空间效率。
空间使用效率的注意事项

如果毫无必要地复制数组或具有高数据开销的复杂数据结构,这种影响会大大增加。
此外,在更简单、开销更小的结构就足够的情况下,编写使用复杂结构的函数可能会招致性能损失,特别是在计算解决方案时需要复制这些结构时。
总结

本节课中,我们将大O的概念从专注于时间考量扩展到了包含空间复杂度。我们强调了在速度与内存效率之间通常存在的权衡关系。此外,还提出了一些在设计解决方案时值得牢记的空间高效使用建议。
Python 136:模块小结与编码面试介绍
在本节课中,我们将回顾编码面试准备模块的核心内容。我们将总结技术面试、沟通技巧、计算机科学基础(二进制与内存)以及算法复杂度(时间与空间)等关键知识点。
模块回顾
上一节我们完成了编码面试模块的学习,现在来回顾一下整个模块的内容。
你首先学习了课程介绍,了解了编码面试准备课程的整体结构。
随后,你进入了编码面试课程。第一课聚焦于技术编码面试,其主要目的是评估你是否具备承担职位职责的技术能力。你学习了在面试过程中必须牢记的几个步骤。


课程强调,使用合适的工具始终很重要,并且必须将时间限制考虑在内。
接着,你学习了代码优化,现在应该能够编写或重写代码,使程序使用尽可能少的内存或磁盘空间,并最小化CPU时间或网络带宽。
总而言之,你学习了一些无论面对何种挑战都可以使用的通用方法。
即使你对问题不熟悉或在规定时间内未能得出结果,也应始终努力展示你的推理过程和最佳实践方法。
通过练习在线问题的解决方案来准备技术面试,并在可能的情况下,对每个挑战采用相似的方法论。这将有助于你在未来无论面对何种挑战时,都能在一个熟悉的框架下工作。
沟通与第一印象
上一节我们介绍了技术面试,本节中我们来看看沟通的重要性。
你将注意力转向沟通和第一印象的重要性。课程介绍了语言和非语言沟通,以及两者的重要性。
你学习了STAR方法,以及如何在面试官沟通时利用它来获益。你现在应该能够审视情境背景、面临的挑战、相关任务的责任、解决挑战所需的行动,以及最终需要达成的结果。
总而言之,你现在应该能够在面试中清晰地传达一个概念。
以语言和非语言的方式沟通你为什么适合这个角色。
最后,在面试过程中出现技术问题时,使用STAR方法进行互动。
计算机科学基础
在学习了沟通技巧后,我们进入下一课,开始学习计算机科学基础知识。
你从二进制开始,学习了十进制(base 10)和二进制(base 2)的区别。
接着,你发现了位置记数法。这是利用数字的位置来表示数值的递增。
然后,课程介绍了计算机如何以字节存储数据,以及每个字节由8个比特组成,每个比特可以是1或0。课程也提供了一些例子。
你研究了幂运算的概念,即计算一个数的幂。
随后用了一个不同位数密码锁的例子来解释这个概念。
你现在应该能够应用这些知识,并理解二进制是计算机的语言。
内存
在理解了二进制之后,我们进一步探索计算机的内存。
你学习的第一个概念是内存容量,它指的是计算机可以容纳的字节数。
你还学习了需要考虑的不同类型的内存,即高速缓存、主内存和辅助内存。
你现在应该知道,为了更好地理解内存的各个层次,停下来思考计算机的工作原理是很重要的。
你学习了传输速率,即计算机将内存数据转移到缓存中进行处理的速度。




接着,你探索了高速缓存和辅助内存,现在应该能够描述它们之间的区别。
然后,课程介绍了计算机主内存由随机存取存储器(RAM)和只读存储器(ROM)组成的概念。你应该能够描述主内存的作用,并区分RAM和ROM。
你现在应该能更好地处理与内存相关的工作了。

时间复杂度


了解了内存之后,我们来看看如何衡量算法的效率,首先是时间复杂度。

你开始探索时间复杂度,学习了如何通过完成任务所需的时间来评估时间效率或衡量性能。
你发现了大O表示法,这是一种用于确定算法效率的度量标准。

因此,它可以估算你的代码在不同输入集上运行所需的时间,或者说,它考虑的是算法将花费的时间量。
课程给出了一些例子,你现在应该对如何衡量时间复杂度有了扎实的理解。

空间复杂度

除了速度,算法占用的内存量同样关键,接下来我们学习空间复杂度。
你接着学习了空间复杂度。重要的不仅仅是算法的速度,还有一个给定解决方案需要占用多少内存。
为了理解空间复杂度,课程引入了辅助空间的概念,这是保存解决方案所需的所有数据所需的空间。

也指计算给定解决方案所需的临时空间。
另一个概念是输入空间,它指的是向正在评估的函数、算法、应用程序或系统添加数据所需的空间。

总而言之,空间复杂度等于输入空间加上辅助空间;即计算一个结果所需的总空间。

学习成果

你对上述所有主题都进行了一些测验,这是你本课程学习之旅的一个良好开端。
所有这些内容应该能使你在未来的编码面试中表现出色。

本节课总结
在本节课中,我们一起回顾了编码面试准备模块的全部内容。我们总结了技术面试的步骤与优化方法,学习了有效沟通与STAR面试法,掌握了二进制、内存层次结构等计算机科学基础,并深入理解了用大O表示法衡量的时间与空间复杂度。这些核心知识为你应对未来的技术面试奠定了坚实的基础。
Python 137:基本数据结构 📚
在本节课中,我们将要学习数据结构的基础知识。数据结构是组织和存储数据的方式,对于任何编程任务都至关重要。理解不同的数据结构及其适用场景,能帮助你编写更高效、更可靠的代码。
什么是数据结构?🔍
一个数据结构用于在计算机内存中建模和存储对象,使其易于组织和访问。它可以是简单的、创建后不可更改的不可变结构,也可以是允许对其内容执行操作的可变结构。

这些操作可能包括对结构内容的更新和查询。
可变与不可变结构 ⚖️

表面上看,似乎应该总是使用可变结构。然而,可变结构需要时间和精力来建模,并且有些对象非常复杂,不易建模。其他因素,如空间占用,也可能是一个考量点。
理解数据结构的底层机制是一个巨大优势,因为选择使用特定数据结构的决定可能对项目进展产生深远影响。

数据结构的分类 📊

虽然不同编程语言中数据结构的实现和功能可能有所不同,但其总体架构通常遵循相似的模式。

以下是数据结构的通用分类,将不同类型分为两个主要分支:线性和非线性。这关系到元素在数据结构中的存储方式。
线性结构 📈
线性结构与信息的存储方式有关。结构中的元素一个接一个地、或按顺序排列,反映了它们被输入的顺序。
以下是线性结构的例子:
- 数组
- 队列
- 栈
- 列表
线性结构意味着每个元素都连接到它前面的元素。有些语言要求同一结构中只能存储相似类型的数据,因此会有整数数组或字符串数组。其他语言则允许混合数组,这意味着在同一数组中存储整数和字符串并不被禁止。但这种简便的方法可能会在后续的错误处理中付出代价。
索引与访问 🔢

一旦创建了简单的结构(如列表或数组),它将包含一个索引。索引是一种访问元素的方式,这些元素不一定是第一个或最后一个实例。
通常,索引的使用是通过在变量名后附加方括号和表示位置的整数来实现的。例如,array[4] 表示所需的元素是数组的第四项。然而,编程语言主要采用0基索引,这意味着计数从0开始。因此,array[4] 实际上是数组中的第五个元素。
如果请求的索引位置(例如位置8)不存在于数组中,访问数组时可能会抛出错误。这些结构的一个常见特性是,大多数语言都有一个内置的长度方法,可以告知数组有多大。

作为一等对象的结构 🏷️
数组和列表通常是一等对象。这意味着所有可用于其他变量的功能也适用于它们。这个定义通常表明,数据结构可以作为参数传递给函数、作为结果返回或赋值给变量。
将列表或数组传递给函数时,应注意传递的是结构本身,而不仅仅是结构的引用。这可以作为一种节省内存的机制,防止复制信息。然而,如果对结构的更改无意中影响了调用环境中的数组,这种情况可能会导致错误。
因此,更好的做法是创建数组的副本,并将副本传递给函数。
内存管理 💾
另一个需要注意的与内存相关的问题是内存泄漏。如前所述,内存可以被任意分配。如果这块内存不再使用,良好的做法是释放该内存位置。由于粗心的编程或其他问题,程序可能会重复调用,导致分配了过多内存且未释放。
随着时间的推移或通过重复调用,这可能导致应用程序内存耗尽并崩溃。大多数编译器都有复杂的算法来检测和释放内存,以避免此问题。
非线性结构 🌳
上一节我们介绍了线性结构,本节中我们来看看非线性结构。与线性结构相反,存在非线性实例,如树或图。这些结构不允许你一次性平滑地遍历所有数据。相反,你可以探索特定的路径。

这些结构的构成意味着它们可以包含自然排序,这使得查询特定数据非常快速。你将在课程后面学习不同类型的排序。

总结 📝
本节课中我们一起学习了数据结构。我们了解了数据结构的两种主要类型:线性和非线性。我们还学习了在决定应使用哪种数据结构时应考虑的一些因素,包括可变性、索引访问、内存管理以及作为一等对象的行为。随着你在本模块中的深入学习,你将进一步探索这些结构,并了解它们各自的优点和缺点。
Python 138:列表和集合 📚
在本节课中,我们将要学习两种重要的数据结构:列表和集合。我们将探讨它们的基本概念、内部实现、各自的优缺点以及适用场景。

列表:有序的数据容器 📋
你是否曾经需要存储一些数据,但不确定该使用哪种数据结构?这是一个常见的编程问题。本节中,我们将探索第一种数据结构:列表。
列表是许多编程语言中常见的数据结构。在大多数编程语言中,列表被表示为对象。这意味着除了存储数据,它们还拥有自己的内置方法。例如,可以使用内置的排序方法来排列列表中的数字。
与数组类似,我们通常会看到声明为字符串、整数或浮点数类型的列表。在某些编程语言中,列表可以包含混合类型的元素。
列表是一个抽象概念,指的是一个元素的容器。列表的一种稳定实现是使用数组或链表。
基于数组的列表
基于数组的列表是使用数组作为底层数据结构构建的有序集合。因此,它们具有与数组相同的优势和局限性。
基于数组的实现涉及到初始大小的设定,而不是像链表那样简单地指向另一个节点。有些语言要求你最初确定结构的大小,而另一些语言则允许动态增长的结构。
需要注意的是,这种自由在某种程度上是表面上的。对于许多动态结构,在实例化时会自动配置一个初始大小。当达到此限制时,数组会将自己复制到一个具有更大空间分配的新结构中。因此,选择不在开始时任意分配空间,可能会在运行时付出代价,因为此类数据结构可能需要在执行其他操作期间多次扩展。
考虑一个列表在循环中执行操作时动态增长的计算成本。在这种情况下,将初始列表大小设置得更大会更有帮助,而不是动态增长,因为动态增长需要创建并将值复制到越来越大的列表中,成本很高。
链表
链表的工作方式不同。链表包含两部分信息:数据和指向下一个列表项的指针。链表从一个空列表开始,可以通过向列表引入新单元来动态增长。

要扩展链表,你只需添加一个新节点并将列表指向其位置即可。这使得它们对于存储大量数据非常快速。
链表的灵活性是通过包含一些额外的存储要求来实现的,特别是在每个节点中,必须有一些对周围节点的引用。链表还有一个头节点和一个尾节点。头节点是一个独特的节点,表示它是列表的开始,而尾节点表示列表的结束。

这种扩展数据结构大小的方法非常强大,可以产生非常大但易于管理的数据集。

集合:无序且唯一的容器 🔍
上一节我们介绍了列表,本节中我们来看看集合。集合与列表非常相似。然而,集合会以无序的方式存储其元素。尽管有一些有序集合的可能实现,但集合有一些不寻常的特性:集合只保存唯一的元素。因此,向集合中添加一个已存在的元素不会对存储的数据产生任何影响。
集合存储信息的无序过程意味着打印一个集合不一定反映元素被添加到集合中的顺序。一旦一个值被添加到集合中,它就不能改变。相反,你必须删除它并添加一个新值。
集合的搜索速度异常快。这是由于其内部机制。集合使用哈希表来确定存储集合元素的位置。因此,传递给集合的每个数字都会应用一个哈希函数。

哈希函数与快速搜索

哈希函数可以定义为一个算法,它接收一些数据并将其映射到一个固定大小的值。理论上,该值是唯一的,并且每次对该数据应用该函数时,都会返回相同的值。

这意味着搜索一个集合可以在 O(1) 时间内完成。这是由于用于在集合中保存值的机制。你将在课程后面更详细地学习哈希函数。
一种 O(N) 的方法是遍历整个数据结构以检查值是否存在。而集合则对输入数据应用映射函数,并检查结果输出来查看值是否存在。

如果存在,则返回值。如果它不存在于集合中,则数据未存储在集合中,因此将返回 false。

集合的局限性
虽然集合可以执行异常快速的搜索,但在处理非常大的数据集时,性能会下降。这是由于哈希函数的性质。保留的值越多,发生冲突的风险就越大。冲突是指哈希函数为两个不同的值返回相同的唯一映射。使用的数据集越大,就越容易发生冲突。
总结 📝
本节课中,我们一起探索了两种非常重要且有用的数据结构:列表和集合,并学习了它们各自固有的优点和缺点。

你现在应该更清楚何时使用每种数据结构,这取决于解决方案的存储需求。列表适用于需要保持顺序或允许重复元素的场景,而集合则适用于需要快速查找和确保元素唯一性的场景。
Python 139:栈和队列 🧱📚
在本节课中,我们将要学习两种重要的数据结构:栈和队列。我们将探讨它们的定义、工作原理、核心方法以及它们之间的关键区别。理解这些概念将帮助你在编程时,根据具体需求选择合适的数据结构来管理和访问数据。

栈和队列是抽象数据结构,它们有多种不同的实现方式,具体取决于编程语言。两者共同的核心原则在于元素是如何被添加和移除的。
与允许随机访问的列表和数组不同,栈和队列采用顺序访问。这种有限的数据持有方式在你希望控制数据访问顺序时非常有用。
栈:后进先出(LIFO) 📚
上一节我们介绍了栈和队列的基本概念,本节中我们来看看栈的详细工作原理。
栈是一种线性数据结构,具有严格的添加和移除项目的方式。顾名思义,栈是元素一个接一个堆叠起来的集合。这意味着不可能从中间抽取项目。相反,栈遵循严格的后进先出原则。这也可以表述为先进后出。这是一个简单而强大的概念,它表明项目只能从栈顶检索,这决定了你检索它们的顺序。
一个生动的例子是在Word文档或任何编码环境中按 Ctrl+Z。Ctrl+Z 撤销最后一个操作,再次按下则会撤销上一个操作,依此类推。延伸这个类比,Ctrl+Y 会重做操作,或者说通过将其添加回栈来“推入”它。

栈通常只有很少的方法。以下是栈的核心方法:
push(item):将一个项目添加到栈顶。pop():从栈顶移除并返回一个项目。is_empty():检查栈是否为空。is_full():一个布尔值,如果栈已满(在某些有容量限制的实现中)则返回True。peek():查看栈顶的项目但不移除它。
这些方法的功能与其名称相关。push 会将一个项目添加到栈中,而 pop 会将其移除。is_empty 检查栈是否为空。你可能听说过一个流行的计算机问答平台,就是以栈的一个常见问题命名的,即栈溢出。
因此,调用 pop() 会从栈顶取出项目,再次调用 pop() 将返回栈中的下一个项目。可以重复调用 pop() 直到栈中空无一物。push() 则会将一个项目放置在栈顶。值得注意的是,调用 pop() 或 push() 会改变栈的状态。

现在,你已经了解了除 peek() 之外的所有方法。那么 peek() 是做什么的呢?要查看栈的内容,可以调用 peek(),它允许你查看栈顶的项目而不将其从栈中移除。因此,调用 peek() 不会改变数据结构的状态,这与会永久改变栈的 pop() 或 push() 不同。有些实现可能包含一个用于遍历栈的搜索功能,但这并非总是如此。

现在,让我们探索一个例子。想象一个应用程序生成了一副牌。你可以创建一个包含52张扑克牌的栈,每次发牌时,就像真实的牌堆一样,从栈顶移除一张牌。以这种方式使用栈可以简化维护牌堆状态所需的代码。

队列:先进先出(FIFO) 🍔
了解了栈的LIFO特性后,本节中我们来看看与之相似的队列。
队列与栈非常相似,它往往具有相同的方法。它可以创建、插入、移除和检查队列的状态。与栈不同,队列基于先进先出的原则工作。同样,其名称很好地指示了该结构的工作方式。

举个例子,想象有一队人在快餐店排队买汉堡。第一个进入队列的人会先得到服务。随后的每位顾客都站在前一位后面,并依次被处理。
与栈类似,队列也会从结构中“弹出”选定的项目,尽管不同语言对此有不同的实现。从队列中移除的元素是位于底部的那个。换句话说,是最近添加的项目,或者说是最先加入队列的项目。
用一个真实的IT例子来说,服务器负载均衡系统通常使用队列来检索任务。该结构会按照插入顺序保存每个任务,当有服务器可用时,进入队列的第一个任务将被移除并传递给该服务器处理。

总结 📝
本节课中我们一起学习了栈和队列这两种数据结构及其区别。栈遵循后进先出原则,而队列遵循先进先出原则。它们是编程工具箱中非常有用的工具,了解它们将在处理需要结构化方式访问和插入数据的问题时为你带来优势。
Python 140:树结构入门
在本节课中,我们将要学习一种新的数据结构——树。我们将了解树的基本概念、术语、不同类型以及使用树结构的优势。
概述
在之前的课程中,我们已经学习了列表、栈和队列等数据结构。本节我们将介绍另一种强大的数据结构:树。树结构在数据的添加和搜索方面提供了极大的灵活性,其内在结构能帮助我们理解数据之间的关系,从而在提取信息时节省大量时间和代码。
什么是树结构?
树是一种非常复杂的数据结构,其设计类似于自然界中的树。它由相互连接的节点组成。一个节点可以是父节点或子节点。父节点可以拥有一组相连的子节点,没有子节点的节点被称为叶节点。就像一棵树一样,节点可以向不同方向分支,这为搜索和存储功能提供了强大的支持。
通常,我们可以将树视为一种图状结构,其中节点包含数据,边则模拟了每个节点之间的关系。
树结构术语
在讨论树时,理解一些术语非常重要。
以下是树结构中的关键术语:
- 根节点:位于最顶层的节点。
- 子节点:连接到根节点或任何父节点的后续节点。
- 兄弟节点:拥有相同父节点的节点,它们被认为处于同一层级。
- 路径:一系列相连的节点。可以通过确定最短路径来假设两个节点之间的连接,即从一个节点移动到另一个节点的最快方式。直观上,路径较短的节点之间共同点更多。
- 节点深度:从该节点到根节点之间的边数,或最长路径的长度。
- 树的高度:从最顶层节点到结构中最深节点之间的边数。
- 树的大小:树中节点的总数。
树的类型与优势
树有许多变体和实现方式,例如二叉树、B树和B+树,还有四叉树和AVL树等。虽然它们都包含上述概述的基本主题,但具体用途和实现细节会根据所应用的树类型略有不同。
将数据存储在树状结构中有许多优势。节点之间的连接表明了数据中固有的关系。它们可以以分层方式存储信息,最顶层的内容存储在上层节点中,而更深入的信息可以通过遍历树的特定分支来获取。由于其灵活的实现方式,树在插入和删除数据时也非常高效。
树的非线性特性意味着有多种遍历数据的方式。在二叉树中,这一特性在存储数据时非常有用。左节点的值较小,而右节点的值较大。
让我们用一些数据值来演示这一点。第一个数据包含值 23。然后添加 4。因为它小于 23,所以它被放到左边。接下来是 1,它也小于 23,但同时也小于 4,所以它也被放到左边。下一个数字是 30,因为它现在大于 23,所以被放到右边。添加 24,因为它小于 30,所以被放到左边。但随后添加的 56 再次被放到 30 的右边。
遍历树可以采用深度优先或广度优先的方法。深度优先方法涉及按顺序从上到下访问每个节点。广度优先方法则是在上升到下一层级之前,先搜索同一层级上的每个节点,并重复此过程直到到达根节点。
树的更多好处包括:它们可以用来模拟笔记本电脑上的文件系统、Java中的类层次结构或组织中的层级模型。

总结

本节课中,我们一起探索了树结构提供的基本结构和固有特性。我们还学习了一些不同类型的树以及实现树数据结构的优势。树是一种功能强大且灵活的数据结构,对于组织和检索分层数据至关重要。
Python 141:哈希表 🗂️
在本节课中,我们将要学习哈希表。你将了解哈希表是什么、它的结构和固有特性,以及它是如何工作的。我们还将探讨使用哈希表的一些优势,并理解哈希碰撞的含义。
概述


在课程的这个阶段,你已经接触了几种不同的数据结构。你会发现,存储信息并没有一种完美的方法。相反,存在多种多样的方法,每种方法都是特定问题的合适解决方案。
哈希表的结构与工作原理
哈希表包含多个槽位或桶,用于存放键值对。它需要一个哈希函数来确定将数据放入哪个正确的桶中。
一个哈希函数是应用于键以生成唯一数字的任何算法或公式。
每个要存储的数据项都必须有一个键和一个值。获取键,并对其应用哈希函数,将其缩减为一个固定大小的值。
有多种哈希函数可供应用。你可能在压缩方面对它们有所了解。当你想通过互联网发送信息时,可能会先将其压缩到可管理的字节数,然后发送,最后在另一端解压。这就是哈希工作原理的一个例子。它将键缩减为一个小的、可管理的大小,然后作为索引指示器。

用于生成索引的信息取决于具体的应用。如果数据本身足够小,它可能就是数据本身;也可能是员工ID的最后四位数字;或者可能是字典中的一个键。大多数编程语言都有内置的哈希函数,如MD5、SHA或CRC32。因此,实现哈希函数是一项直接的工作。

哈希表的优势:时间复杂度
在讨论大O表示法时,我们曾介绍过速度和空间常常相互矛盾的观点。这意味着你可以减少检索项目所需的时间,但这样做会增加应用程序的开销。

哈希表优先考虑速度而非空间,可以在 O(1) 时间内检索一个项目。回想一下关于数组的讨论。当你想检查一个值是否存在时,必须执行一个搜索,检查列表的每个元素并与目标值进行比较。在最坏的情况下,这将花费 O(n) 时间,换句话说,如果元素在数组的末尾,它必须进行n次检查。

哈希表提供了一种存储和搜索数据的替代方法。这是通过使用索引来实现的。你必须实现一个算法,该算法接收一个键并将其映射到一个存储在索引中的值。

然后,当出现一个新键时,算法只需运行相同的函数,并确定值在索引中的位置。这很像一本书的索引,它将极大地加快识别某些数据位置所需的时间。
你可能会在缓存、字典、数据库索引和集合中找到哈希表的使用。
一个简单的哈希表示例
考虑一个场景,你有一个包含10个键的数组,键是数字0到9。你将选择使用一个哈希函数来决定在内存中存储这些数字的位置。

你选择了一种简单的方法,对数字应用模20运算。因此,对于从0到9的每个键,应用你的哈希函数。从 0 mod 20 = 0 开始,1 mod 20 = 1,2 mod 20 = 2,3 mod 20 = 3,依此类推。通过这种方式,你将生成9个唯一的值,这些值用于表示内存中与这些键关联的数据的放置位置。这个例子很简单,但说明了创建哈希映射背后的机制。

当要存储的键的数量增长超过20时,问题就出现了。记住,1 mod 20 = 1,但 21 mod 20 也等于 1。
哈希碰撞及其解决方案
接下来,我们看看哈希表中的碰撞。
什么是哈希表中的碰撞?哈希函数将应用一个巧妙的算法,将键的大小缩减到一个可管理的大小。有些方法比其他方法更复杂。那么,如果两次哈希的结果相同会发生什么?
为了扩展这个想法,值得思考冯·米塞斯的生日悖论。由于概率的原因,有时事件发生的可能性比我们想象的要大。在这种情况下,如果你调查一个只有23人的随机群体,实际上大约有50%的几率其中两人会有相同的生日。这被称为生日悖论。
假设一家公司有24名员工,并且应用了一个巧妙的哈希函数,该函数获取他们生日的日期和月份,并将其用作索引。只有24名员工和一个拥有365个索引槽的哈希表来存放对他们的引用,你可能认为任何两名员工共享生日的概率很低。事实上,研究表明,这种情况发生的可能性超过50%。下次你参加聚会时,一定要检查是否有任何两位与会者生日相同,亲自验证一下。

这说明,当哈希函数应用于键时,会产生重复的哈希值,必须为此做出安排。
针对这个问题有几种解决方案。
以下是解决碰撞的两种主要方法:
- 动态扩容:每次发生碰撞时扩展表,然后增加哈希方法的复杂性,将值重新分配到新的地址。通过这种方式,表会自然地增长以匹配所需数据的大小。
- 链表法:在碰撞点创建一个链表,简单地存储额外的值。因此,在发生碰撞时,不是存储一个值,而是存储一个值的链表。



总结
在本节课中,我们一起学习了哈希表是什么、它的结构和特性以及它是如何工作的。你还了解到,哈希是一种非常巧妙的方法,它使用哈希函数和索引来实现 O(1) 时间的搜索。我们探讨了碰撞以及如何利用它们来确定表的大小。你甚至还了解到,如果你参加的聚会客人超过24位,那么至少两人共享同一生日的可能性是很大的。
Python 142:堆数据结构详解 📚
在本节课中,我们将要学习一种名为“堆”的特殊数据结构。堆结合了树和队列的某些特性,是一种用于高效组织和处理优先级元素的重要工具。我们将探讨堆的结构、核心操作、工作原理及其实际应用场景。
堆的基本概念 🌳
堆是一种模仿树形结构的专用数据结构,但其行为方式与队列相似,关键区别在于堆为元素赋予了优先级。堆中的每个元素都有一个键值,优先级可以基于最小键值或最大键值来设定。
- 最小堆:优先级赋予键值最小的元素。
- 最大堆:优先级赋予键值最大的元素。
堆最初是为了高效存储和搜索数据而引入的,但后来人们发现它在许多操作中都非常有用。
堆的核心操作 ⚙️
堆支持一组精选的核心操作。这些方法是构成堆的基础元素,不同编程语言的实现可能会添加额外的方法。
以下是堆的核心方法:
- 插入:向堆中添加一个新元素。
- 查找最小值:在最小堆中,返回优先级最高的元素(即最小键值)。
- 删除最小值:在最小堆中,移除并返回优先级最高的元素。
注意:本节的讨论围绕最小堆展开,但所有内容反转后同样适用于最大堆。两者的唯一区别在于优先级设置的位置。
一个可能被添加的额外方法是 decrease_key,即更改某个键的值。这在现实场景中元素的优先级发生变化时非常有用。
堆的底层结构与实现 🏗️

在讨论树时,我们提到二叉树会根据值的大小顺序来查找:如果值小于节点,则沿左路径向下;如果值大于节点,则沿右路径向下。


基于这种底层架构,堆通常使用二叉树来构建。另一种方法是让数组模拟二叉树的行为。
在最小堆中,最小值被放置在根节点,后续值根据其键值大小被放置在层次结构中的相应位置。这意味着从堆中检索最小值的时间复杂度是 O(1),因为它始终存储在根节点。
与栈不同,检索一个值并不会将其从树中移出。如果需要移除元素,可以调用 delete_min 方法。

堆的设计哲学与限制 🚫
通常,堆不支持删除优先级元素之外的其他项目。这是因为堆是为特定目的而构建的:以最短时间识别并返回最重要的项目,然后让下一个重要项目进入队列。
在树中删除非优先级项目需要重组树结构,这会导致性能下降。如果你需要一种支持此类操作的数据结构,可能需要考虑堆之外的其他结构。

堆的插入过程 🔄
向最小堆中插入元素通过“上浮”过程完成。

以下是插入步骤:
- 新元素被插入到堆的末尾(即树的最底层最右边的位置)。
- 将该元素与其父节点进行比较。
- 如果新元素的值小于其父节点,则交换它们的位置。
- 重复步骤2和3,直到新元素的值不小于其父节点,或者它到达了根节点。
堆的插入操作可以在 O(log N) 的时间内完成。
堆的实际应用场景 💡
了解了堆的底层机制后,你现在可能对如何应用这种数据结构有了一些想法。考虑到其固有结构能从一组元素中优先处理特定值,其自然应用领域就是调度。
以下是堆的一些典型应用场景:
- CPU进程调度:根据优先级执行任务。
- 网络路由或数据包处理:优先处理高优先级的数据包。
- 面试日程安排:用于优先安排特定任务,例如使用候选人处于面试流程的阶段或职位在组织内的优先级作为键值。
拥有一个能基于重要性自动应用调度流程的系统,可以极大地节省时间。


总结 📝
本节课中,我们一起深入学习了堆数据结构。你了解了堆如何用于将元素从最不重要到最重要进行组织,也看到了通过限制功能,反而可以提高处理效率。
堆在需要快速访问最高或最低优先级元素的场景中表现出色。与选择任何数据结构一样,为正确的工作找到合适的工具至关重要。堆就是处理优先级队列和调度问题的利器。
Python 143:图数据结构入门 🗺️
在本节课中,我们将要学习一种强大的数据结构——图。图非常适合用来表示实体(如城市、网页、人)以及它们之间的复杂关系(如道路、链接、社交关系)。我们将了解图的基本概念、类型、遍历方法以及它在现实世界中的应用。
在计算机科学中考虑一个具体问题时,始终需要思考解决问题可能需要执行哪些操作。通过这种思考,可以选择一个合适的数据结构来存储数据。
假设你在一家大型互联网公司工作,需要存储一系列地点以及它们之间的连接关系。
在这个图示中,我们的城市按照彼此之间的关系被绘制出来。
请注意,并非所有可能的细节都需要被记录。例如,如果你想知道芝加哥到波士顿的距离,你可以很容易地从数据的组织方式中推导出这个信息。
同样的方法可以用来为互联网目的地、单词之间的关系或社交网络上的人与人之间的关系建模。


这种保存信息的方法是基于图的方法。在接下来的内容中,将概述这种方法的一些术语和优势。

图的基本构成 🧱
上一节我们介绍了图的概念,本节中我们来看看图的具体构成。
这个结构图示是一个图,它由表示目的地的节点和显示每个节点如何与另一个节点相关联的边组成。
节点之间存在数值,这意味着这是一个加权图。

图中没有箭头,这意味着这是一个无向图。
与有向图相反,无向图没有优先顺序。
思考有向图和无向图的一种方式,类似于双向街道和单向街道。

图的连接性与路径 🛣️
有时,在组织数据时,突出某种进展会有所帮助;而在其他情况下,边的存在只是为了显示关联关系。
一个路径是由一条边连接的两个或更多节点的序列。
在有向图中,如果边只是单向的,那么这种连接被认为是弱连接。


然而,如果两个节点之间有双向连接,那么它就被称为强连接。


此时,你可能会认为图类似于树。在某种程度上,你可以说树是一种简单的图。值得注意的是,树有一个起点,并模拟了具有父子关系的层次结构。而图是一种复杂得多的结构,没有起点或终点。
两个相邻的节点被称为邻居,通过一个邻居连接的节点被称为相邻。





图的遍历 🔍
和图一样,树也可以进行广度优先和深度优先遍历。回忆一下,广度优先搜索涉及访问同一层的每个节点,然后再向下进行;而深度优先搜索涉及在移动到下一个分支之前,深入探查每个分支的末端。

以下是实现广度优先搜索的步骤:
- 选择一个给定的起始位置。
- 遍历所有相邻节点。
- 每个邻居节点都有一组连接的节点,可以将它们添加到另一个数据结构——队列中。
通过这种方式,你可以系统地访问每个节点。


为了实现深度优先搜索,你可以使用栈。回忆一下,栈处理元素的方式与队列不同。

当队列遵循先进先出原则时,栈则遵循后进先出原则。


因此,通过系统地将所有邻居节点放入栈中,你将确保进行深度优先遍历。



图的应用实例 🚀
图是一种被广泛研究的数据结构,是许多用于确定节点间重要性的算法的基础。无论节点中存储的是什么元素,一个著名的算法是最短路径算法:从节点A到节点E的最快方式是什么?边的权重会告知选择每条路径的成本。
这种方法用于在互联网上路由数据包,或在谷歌地图上计算行程。


另一个常见的基于图的挑战是旅行商问题。



一个销售员需要访问几个特定的节点。规划一条在最短时间内覆盖所有节点的最佳路线是什么?这将用于包裹路由。
给定X个目的地和Y辆车,规划出最有效的路线,以便所有包裹都能以最少的资源消耗送达。



总结 📝
本节课中我们一起学习了图数据结构。
在本视频中,你学习了图如何为你提供一种灵活的数据建模方式,通过数据的存储方式来促进对数据的推断。


这种多功能的方法只保留了最少的信息。从芝加哥到波士顿的距离没有存储在任何地方,但可以被推导出来。很容易查询不同的问题,而无需改变数据的结构。计算步行时的最佳时间可以轻松地替代驾驶时间,而无需大费周章。
整个统计学领域都致力于从节点位置推断信息,这可以用来对存储在那里的任何数据进行推断。
Python 144:模块小结 📚
在本节课中,我们将回顾整个“数据结构介绍”模块的核心内容。我们将系统性地梳理从基础到高级的各种数据结构,理解它们的特性、分类及应用场景。
模块回顾
恭喜你完成了数据结构介绍模块的学习。现在,让我们花一些时间回顾在本模块中学到的知识。
你从一节关于基础数据结构的课程开始了本模块。内容涵盖了从字符串、布尔值或数组等基础结构,到集合、图和堆等更高级的数据结构。理解你正在处理的数据以及最适合使用的数据结构,是非常有益的。

你学习了简单的、创建后不可变的不可变结构,以及便于对其内容执行操作的可变结构。


数据结构分类
接着,你深入研究了所有类型的数据结构以巩固记忆。以下是数据结构的通用分类,它将不同类型的结构分为两个主要分支:线性和非线性。


线性结构的例子包括数组、队列、栈和列表。它意味着每个元素都与其前一个元素相连。
你详细学习了这些结构,现在应该能够描述它们中的每一个。


非线性数据结构
然后,你将重点转向非线性数据结构。与线性结构相反,非线性结构的实例包括树或图。这些结构不允许你以单一流畅的动作遍历数据。相反,你可以探索特定的路径。
接下来的一课介绍了列表和集合。


你了解到,与数组类似,在某些编程语言中,列表通常被声明为字符串、整数或浮点类型。而在另一些语言中,列表可以包含混合的元素类型。你还了解到,有些语言要求你最初确定一个结构的大小,而另一些语言则允许结构动态增长。


链表与集合
随后是关于链表及其工作原理的部分。请记住,一个链表包含两条信息:即数据和指向下一个列表项的指针。

然后你学习了集合及其工作原理。集合与列表非常相似。然而,集合会以无序的方式存储其元素。

在集合之后,你接触到了哈希函数及其在集合搜索中的作用。集合的搜索速度异常快。

栈与队列
接着,你在同一课中观看了关于栈和队列的下一个视频。复习一下,栈和队列是抽象数据结构,根据编程语言的不同,有许多不同的实现方式。两者共同的基本原则是元素的添加和移除方式。
你学习了栈和队列采用顺序访问,并使用 empty、push 和 pop 等方法来移动、添加或移除项。你还了解了 LIFO(后进先出) 和 FIFO(先进先出) 原则。

当你学习队列时,你了解到队列与栈非常相似,因为它往往具有相同的方法。它可以创建、插入、移除和检查队列的状态。与栈不同,队列基于 FIFO(先进先出) 原则工作。同样,其名称很好地指示了该结构的工作原理。
树结构
本课的最后一个视频重点介绍了树。树是一种强大的数据结构,为你在添加和搜索值方面提供了极大的灵活性。树的固有结构可以让你理解所存储数据之间的许多关系,这在从数据中提取信息时可以节省大量时间和代码。


你学习了树结构以及数据如何在树中移动。
高级数据结构

在下一课中,你被介绍了高级数据结构。首先,你学习了什么是哈希表,它的结构、固有特性以及工作原理。你还探讨了使用哈希表的一些优点,并发现了哈希中“冲突”的含义。
让我们快速回顾一下这涉及的内容。你接触了哈希函数,并了解到获取键值后,对其应用哈希函数,将其缩减为一个固定大小的值。


你通过我们经验领域的一个例子学习了压缩。当你想通过互联网发送信息时,可能会先将其大小压缩到可管理的字节数,通过互联网发送,然后在另一端解压缩。

随后解释了哈希表如何通过使用索引,为存储和搜索数据提供了一种替代方法。为了实现这一点,你必须实现一种算法,该算法接收一个键并将其映射到存储在索引中的值。

堆的结构与特性
本课的下一个视频重点介绍了堆的结构和特性。你还发现了堆如何用于将元素从最不重要到最重要进行组织,以及如何通过限制堆的功能来提高效率。
你了解到,堆可以优先处理值最小的键,这种堆称为最小堆;而优先处理最大值的堆称为最大堆。堆可以执行几个核心操作,即插入、查找和删除项。
此后,你了解到删除树中的项需要重新构建树,这会导致性能下降。总结关于堆的视频,你对堆以及如何使用它们将元素从最不重要到最重要进行组织有了更深入的理解。你已经看到,通过限制功能,可以提高效率。
与选择任何数据结构一样,重要的是为正确的工作找到合适的工具。
图结构
最后,你重点学习了图,并设定了如下场景。在考虑计算机科学中的给定问题时,始终重要的是考虑解决你的问题可能需要执行什么操作,并通过这种反思选择适当的数据结构来保存你的数据。
假设你可能为一家大型互联网公司工作,该公司希望存储一个位置目录及其相互之间的连接性。使用了一个城市相对位置图来说明所有权重图、无向图等概念,并且与有向图相反,无向图没有优先顺序。
之后,你了解到,如果边只是单向的,则有向图中的连接被认为是弱连接。然而,如果两个节点之间有双向连接,则称其为强连接。


总结
在本视频中,你学习了贯穿本模块的关键概念和主题。你已经对所有提到的主题进行了一些测验。你正为未来做好更充分的准备。祝你在下一个模块中好运。
Python 145:排序算法 📊
在本节课中,我们将学习排序算法。排序是数据处理中的一项基础且重要的任务。我们将探讨几种常见的排序方法,包括选择排序、插入排序和快速排序,并了解它们的基本原理、实现步骤以及各自的优缺点。
排序的必要性 🔍

对一组数据进行排序,听起来可能很简单。然而,深入细节后,你会发现它可能出人意料地具有挑战性。
为了解决这个挑战,人们开发了多种算法,也设计了一些数据结构,例如二叉树和堆。这些数据结构的设计目标之一,就是为了让数据能以一种有序的方式存储。
使用已排序的数据,或者具备对自有数据进行排序的能力,可以显著节省时间。因此,一个能够被排序的元素数据集是基本前提。
这种顺序可以是按字母顺序、数字顺序、时间顺序、形状大小或颜色色调。具体使用哪种度量标准并不重要,重要的是它们能够按照升序或降序进行排列。

另一个需要考虑的因素是,排序是通过置换(即重新排列原列表)完成的,还是通过创建副本(同时保留原列表)完成的。

选择排序 🤔
选择排序是一种早期的排序方法。它模仿了人类处理这个问题的方式,其基本原理非常直接。
以下是选择排序的步骤:
- 遍历列表,找出最小的元素。
- 将这个最小元素与列表的第一个元素交换位置,使最小元素位于顶部。
- 此时,原顶部位置的元素被交换到了列表中空出的位置。
- 对列表中的每一个元素重复此过程,直到列表按从小到大排序完毕。

让我们通过一个例子来探索这个过程。
在图中,索引位置0的元素是35。在选择排序中,会将索引0的元素与数组中的每个元素进行比较,直到找到最小值。
同样地,下一个位置的元素46会与每个元素比较,在这个例子中,它与6交换。接下来是索引2的元素36。你会发现索引3的元素9被认为更小,但必须搜索整个数组才能确认。
这个过程持续进行,直到每个元素都按大小排序,最小的在左边,最大的在右边。
插入排序 📥

另一种直接的排序方法是插入排序。与遍历所有元素不同,这种方法从检查列表中的前两个元素开始。
以下是插入排序的步骤:
- 比较列表中的前两个元素,将较小的那个移到前面。
- 对每一个后续元素,将其与它左边的元素进行比较。
- 如果发现它更小,就将其向左交换位置。
- 重复此过程,直到元素到达正确位置或到达列表开头。
让我们看一个例子。
在屏幕上,你会注意到一个数字数组。第一个元素35左边没有更大的元素,所以它保持原位。然后元素46被比较,也留在原地。

接下来是元素36,它与位置1的元素(46)比较,发现更小,于是它们交换。再与位置0的元素比较,显示不需要进一步交换。
在第3步,你会看到元素9。它与46比较并交换到位置2。它进一步与位置0和1的元素比较,并再次交换。
接下来,位置4的元素与位置3的元素比较并交换。它进一步与位置2和1的元素交换。它也与位置0比较,但由于更大,所以不再移动。
这个过程持续进行,从右向左移动,直到整个数组排序完毕。

快速排序 ⚡
上一节我们介绍了两种基于简单范式的直接排序方法。快速排序则是一种更复杂、实现难度更高,但效率也高得多的方法。
快速排序基于枢轴的原则运作。算法选择数组中的一个元素作为枢轴。

以下是快速排序的步骤:
- 选择数组中的一个元素作为枢轴。
- 将所有大于这个值的元素移到枢轴的右边。
- 将所有小于这个值的元素移到枢轴的左边。
- 对枢轴左右两边的子数组,递归地重复此过程,直到所有项都排序完毕。
让我们通过一个例子来探索这个过程。
这里,元素9被选为快速排序的枢轴点。所有小于9的项被交换到左边,所有大于9的项被交换到右边。因此,第一次分割后,较小的元素(6和3)被移到了左边。
对结果数组再次应用相同的过程,当发现3是唯一未被分割的元素时,递归终止。
现在,取大于原始选定枢轴的值,你选择一个新的枢轴。在这个例子中,选择了36,并执行进一步的元素交换。
最后,剩余的未排序索引位置根据新的枢轴进行交换。一旦所有元素排序完毕,算法终止。

算法选择与实践 🛠️

除了上述方法,还有许多其他的排序方法,有些甚至融合了现有方法的优点形成混合算法。

在实践中,你可能不需要自己编写实现,因为每种编程语言都有优秀的现成实现。本节的目标是展示它们底层的工作原理,以便你在面对特定问题时能选择最合适的一个。
与数据结构一样,没有一种排序算法能在所有场景下都提供最佳结果。每种方法都有其权衡,在某些环境下比在其他环境下更有效。你很快将在关于大O表示法的内容中,更深入地了解这些方法的效率。
总结 📝


本节课中,我们一起探索了排序算法以及可用的不同排序方法。你学习了实现选择排序、插入排序和快速排序所需的步骤,并发现了每种排序方法的优点和弱点。理解这些基础算法的工作原理,将帮助你在未来的数据库工程和数据建模任务中做出更明智的技术决策。
Python 146:搜索算法
在本节课中,我们将要学习计算机科学中的基础操作——搜索。我们将介绍两种主要的搜索方法:线性搜索和二分搜索,了解它们的实现步骤、优缺点,并学习如何使用大O表示法来评估它们的效率。
在上一节中,我们探讨了排序算法。本节中,我们来看看如何在已排序或未排序的数据集中查找特定元素。
搜索的基本考量
在计算机科学中,当面对一个数据集合时,经常需要识别其中的特定元素。然而,对“特定元素”的定义可能存在不同的解读。
以下是搜索时需要考虑的几个关键问题:
- 精确匹配:例如,给定一个哈希表,是否存在与给定键匹配的键值对?这是一个简单的“一对一”比较,结果要么是找到唯一的键,要么是未找到。
- 范围或极值搜索:例如,查找数组中的最大值、最小值或中位数。
- 处理未找到的情况:如果要查找的值不存在,应该返回什么?返回空值(Null)可能会影响应用程序的后续运行,需要设计相应的保护机制。
- 匹配实例:搜索是应该返回第一个匹配的值,还是最后一个?
(在本课末尾的补充阅读材料中,有一个链接,指向Null的发明者Tony Hoare的演讲,他称Null为“十亿美元的错误”。)
线性搜索
最简单的搜索实现是线性搜索。如果你有一个元素数组,线性搜索从索引起点开始,逐个检查数组中的元素,直到找到目标元素或检查完所有元素。
在这种方法中:
- 最佳情况时间复杂度是 O(1)(目标元素恰好在第一个位置)。
- 最坏情况时间复杂度是 O(n)(目标元素在最后一个位置或不存在,需要检查每个元素)。
从线性搜索到二分搜索
关于数据结构,我们已经知道有些结构(如堆或二叉树)本身具有排序特性。你也可以先对任何数据结构应用排序算法,然后再应用搜索方法。
使用二分搜索可以在每次迭代中将搜索空间减半。
二分搜索
二分搜索要求数据在搜索前必须是有序的。它的工作原理是不断将待搜索区间对半分割。
假设我们有一个已排序的列表 data_list 和目标值 target。以下是二分搜索的步骤:
- 检查列表中间位置的元素。
- 如果中间元素等于
target,则搜索成功。 - 如果中间元素小于
target,则丢弃左半部分,只在右半部分继续搜索。 - 如果中间元素大于
target,则丢弃右半部分,只在左半部分继续搜索。 - 重复此过程,每次迭代都将搜索区间减半,直到找到目标或区间为空。
# 二分搜索示例代码(迭代版本)
def binary_search(sorted_list, target):
low = 0
high = len(sorted_list) - 1
while low <= high:
mid = (low + high) // 2 # 找到中间索引
if sorted_list[mid] == target:
return mid # 找到目标,返回索引
elif sorted_list[mid] < target:
low = mid + 1 # 目标在右半部分
else:
high = mid - 1 # 目标在左半部分
return -1 # 未找到目标
与线性搜索类似,二分搜索的最佳情况也是 O(1)(目标恰好在中间)。其最坏情况的时间复杂度是 O(log n)。这是因为每次迭代后,剩余待搜索的元素数量 N 都减半,经过 k 次迭代后,剩余元素约为 N / 2^k。当 N / 2^k = 1 时,k = log₂N。
二分搜索的效率远高于线性搜索。然而,必须注意,任何感知到的时间增益都需要抵消掉排序列表所花费的时间。如果列表经常更新,排序过程可能会变得代价高昂。
总结
本节课中,我们一起学习了线性和二分搜索算法。我们了解了完成这些搜索的步骤及其工作原理,也学习了如何应用大O表示法来估算两者的效率。我们还认识到,通过对标准方法进行一些巧妙的调整(如先排序再二分查找),可以显著提升搜索性能。


在下一课中,你将开始学习如何设计和使用算法。
Python 147:分治法 🧩
在本节课中,我们将要学习分治法范式。分治法为解决特定问题提供了一个有用的思考框架。它包含了本模块中讨论的两个核心原则,即递归和将大问题分解为小问题。我们将了解分治法的运作步骤、其优势,并通过归并排序等实例来加深理解。
分治法范式简介
分治法范式为解决计算问题提供了一个清晰的框架。上一节我们介绍了递归思想,本节中我们来看看如何将分治法作为解决问题的系统性方法。
该范式主要包含两个必要步骤和一个可选步骤。
以下是分治法的三个核心步骤:
- 分解:将原始输入问题分割成若干个更小的、相互独立的子问题。
- 解决:递归地解决每一个子问题。如果子问题足够小,则直接求解。
- 合并:将各个子问题的解合并起来,形成原问题的解。此步骤在某些问题中可能不需要。
用伪代码可以描述为:
def divide_and_conquer(problem):
if problem is small enough: # 基线条件
return solve_directly(problem)
else:
subproblems = divide(problem) # 分解步骤
solutions = []
for sub in subproblems:
solutions.append(divide_and_conquer(sub)) # 递归解决
return combine(solutions) # 合并步骤
实例解析:归并排序
为了更好地理解分治法如何应用,让我们以排序问题为例。之前我们讨论过多种排序方法,现在介绍一种基于分治思想的排序算法——归并排序。
归并排序是一种对数组进行排序的复杂方法。它首先将数组一分为二,然后对这两个子数组再次进行分割,此过程不断递归进行,直到每个子数组只包含一个元素。随后,过程开始反向进行,将已排序的小数组合并回它们被分割前的部分,最终得到一个完全有序的数组。
这个解决方案基于一个核心思想:通过将大问题分解为小问题,可以更轻松地完成整体任务。
现实世界类比

为了更直观地理解分治法如何应用于归并排序,让我们探讨一个现实世界的例子。

假设你和三位室友决定一起去超市购物。在列出一个长长的购物清单后,你们一同前往超市。
- 低效方法:你们四个人一起在超市里走动,共同寻找清单上的每一项物品。
- 分治法(初级):将购物清单分解成四份,每人负责一份。这能减少整体购物时间,尽管可能导致不同人负责的区域有重叠。
- 分治法(优化):首先将清单排序,使所有同类物品(如饮料、水果、肉类)归类在一起。然后根据超市的区域划分,分配每位成员负责一个特定区域(如一人负责生鲜区,一人负责日用百货区)。最后,大家分别完成采购后,在收银台合并所有商品。这是一种更高效的完成任务的方法。
俗话说“问题分享,负担减半”。那么在计算机上这是如何运作的呢?
分治法的优势
分治法为计算机科学带来了两大直接优势:并行化和内存管理。
- 并行化:指的是让不同的线程或计算机同时处理同一问题的不同部分,以更快地完成任务。采用分治解决方案的一个好处是,在编码时可以利用并行处理。例如,在归并排序中,每个子数组可以被发送到不同的处理器核心或服务器上进行排序。
- 内存管理:有时需要处理的数据集过于庞大,无法一次性装入内存。分治法允许将数据分解成适合内存大小的“块”进行处理,然后再将结果合并。此外,在云计算架构下,可以将部分计算任务卸载到云端服务器,以管理本地可用内存。

总结
本节课中,我们一起学习了分治法范式。我们通过归并排序的例子,了解了分治法如何为解决复杂问题提供框架。我们学习了其包含的必要步骤(分解、解决)和可选步骤(合并),并探讨了这种范式为计算机带来的并行化和内存管理两大优势。掌握分治法,对于设计和理解高效算法至关重要。
Python 148:递归
概述
在本节课中,我们将要学习递归的概念及其实现方法。递归是编程中一种重要的技术,它允许函数调用自身来解决问题。我们将探讨递归的三个核心要求,并通过具体示例来理解其工作原理和应用场景。
从循环到递归

在之前的视频中,你学习了分治范式。本节中,我们来看看递归以及如何实现递归解决方案的要求。
任何编程语言的基本能力之一就是执行循环。循环使我们能够重复执行操作,直到获得期望的输出。与人类不同,计算机永远不会厌倦重复执行相同的单调任务。


除了循环之外,解决问题的另一种方法是递归。让函数调用自身的做法被称为递归,这也是本视频的重点。

递归是指一个函数反复调用自身来处理一个更小规模的问题实例,直到满足某个退出条件。
递归的三个要求
那么实现递归需要什么?实现递归解决方案有三个要求,即:基本情况、递减结构和递归调用。
让我们看一个与二进制相关的例子,以便更好地说明这三个要求。
考虑一个挑战,你的任务是计算一个数的指数。回想一下,计算一个数的指数是为了确定从它可以推导出多少种可能的排列。这在演示二进制如何表示一系列字符时讨论过。
以下是实现递归的三个核心组件:
- 基本情况:确保函数不会无限调用自身,并最终结束。
- 递减结构:每次递归调用时,问题规模都应减小。
- 递归调用:函数在其定义内部调用自身。
让我们通过一个计算指数的函数来具体看看:
def exponent(x, n):
if n == 0: # 基本情况
return 1
else: # 递归情况
return x * exponent(x, n-1) # 递归调用,n-1是递减结构
- 第1行定义了一个接受两个参数
x和n的函数。 - 基本情况是
if n == 0。在这种情况下,程序将终止并返回1(任何数的0次方都是1)。 - 第4行是条件语句的第二部分。如果尚未达到终止点,则使用一个缩减后的结构再次调用该函数。
- 在这个例子中,目标是将
x乘以n次,以找出二进制数可能存在的总状态数。
减少输入值与建立基本情况同样重要。这样,函数最终会达到基本情况并停止调用自身。
递归函数的第三个组成部分是包含对自身的调用。这发生在第5行,exponent 函数接受了递减后的结构(n-1)。
之所以说结构是递减的,是因为其规模在每次调用中都减小了。每次调用函数时,都会在调用栈上创建一个新的实例。
用 x=2 和 n=3 调用上述函数将导致创建三个实例并放置在调用栈上。
这会增加计算成本,因为调用函数需要资源。然而,每个结果的计算都将保留在调用栈上。这在计算层次性问题或可以从了解哪些步骤导致特定结果(如图遍历)中受益的问题时非常有用。


递归的应用示例

让我们探索一个递归的使用示例。考虑关于二分查找的视频。
一个二分查找函数将接受一个列表和一个目标值作为参数。

首先,检查列表的中点元素,以确定要检查列表的哪一半。重复此过程,直到找到目标元素或确定其不存在。
你可能会考虑通过循环或递归来解决这个问题。递归的输入将是一个列表和一个搜索元素,递归函数将调用自身直到达到目标端点。
为何使用递归?
那么,既然简单的循环就能做到,为什么还要使用递归呢?有些问题非常适合递归调用。
考虑计算给定数字的斐波那契数。斐波那契数列是一个数字序列,其中前两个数字是0和1,之后的每个数字都是集合中前两个数字的和。
计算过程涉及传入一个数字,计算结果,更改数字,然后用一个新的整数输入再次调用函数。
以这种方式编写代码意味着你可以简单地用不同的整数调用该函数,它将返回所需步骤的分解。可读性是递归的一大优点。有时,当一个问题需要多次检查时,循环可能很快变得笨拙。
递归解决方案减少了解决问题所需的代码量,并且可能更易于阅读和理解。
最后,人们会采用递归方法作为分治解决方案的一部分。在这里,问题被分解成更小的步骤并重复执行,以找到最优解。


总结
本节课中,我们一起学习了递归。你已经了解到,虽然递归可能会给问题增加一些计算开销,但它也能产生优雅、易于阅读的代码。此外,递归体现了分治解决方案的精髓,即将问题分解为其最小的组成部分并解决它们。
Python 149:动态规划 🧩
在本节课中,我们将要学习动态规划这一重要的编程范式。动态规划通过将复杂问题分解为更小的子问题,并存储这些子问题的解来避免重复计算,从而高效地解决组合与优化问题。
在介绍动态规划之前,你已经学习了分治范式和递归。

本节视频中,你将学习记忆化和动态规划的概念。动态规划是一种编程范式,它提倡通过将问题分解为更小的子问题并解决它们来解决问题。

这些解决方案随后被存储在合适的数据结构中,以备后续使用。
这样做的好处是,如果这些子问题需要再次计算,只需查找答案,而无需重新计算整个问题。

这种解决子问题并存储结果,以便在未来可能查找时节省时间的技术,被称为记忆化。
动态规划与前几个视频中已经遇到的两个概念相关。
让我们快速回顾一下这些概念。第一个是分治法,即将一个大问题分解为一组较小的子问题,然后解决它们。
第二个是分治法的一个子集,称为递归。递归是一种编码解决方案的实践,它避免运行循环,而是通过多次自我调用来得出解决方案。
动态规划是这些方法的延伸,它额外涉及记录每次新运行子问题时产生的结果。
在后续运行中,不再重新计算结果,而是查询上一次提出该问题时的查找记录。如前所述,这种方法被称为记忆化。为了强化这个概念,记忆化是指当编译器识别出某个计算已为先前任务运行过时,存储先前计算的结果并用其替代重新运行计算。
为了举例说明,请考虑视频中提出的关于二进制数的问题:一个六位二进制锁有多少种可能的组合?
在之前的视频中,已经展示可以通过指数运算或求幂来发现这一点。因此,同一个六位锁将有 2^6 或 64 种组合。
所以,2^6 = 2 × 2 × 2 × 2 × 2 × 2。
或者,你可以将其分成两组,先计算 2 × 2 × 2,再计算 2 × 2 × 2,结果是 8 × 8,同样得到相同的结果。应用分治法,并利用记忆化高效计算,将首先计算 2^3,然后再次使用 2^3,从而减少所需的计算总量。
通过应用记忆化,第一个 2^3 将被计算出来,然后为第二个括号重用,减少了整体所需的计算量。

那么,什么样的问题适合用动态规划解决呢?

动态规划方法通常适用于组合问题或优化问题。
一个已经提到的组合问题的例子是斐波那契数列。你在面试中可能遇到的另一个例子是背包问题。
这既是一个组合问题,也是一个优化问题。
假设为一次计划中的露营旅行做准备。你可以往背包里装所需的物品。每件物品都有其重量成本:手电筒重 1 公斤,水重 2 公斤,帐篷重 3 公斤。此外,每件物品都有其价值:手电筒价值为 1,水价值为 2,帐篷价值为 3。
简而言之,背包问题列出了一系列重量不同、价值不同的物品。你的背包只能携带一定数量的物品。问题是,如果你的背包能承受一定的重量,需要计算你能携带的最佳物品组合。目标是找到在背包重量容量限制下的最佳回报。
为了计算这个问题的解决方案,你必须选择所有加起来达到给定重量并包含给定价值的物品。可携带的重量会发生变化。这个问题可以应用于资源分配,例如你拥有一定的 CPU 算力和 X 个任务要运行,就像 CPU 完成任务的专用容量一样。有时重量可能是 7 公斤,其他时候可能是 10 公斤。
动态规划涉及保存用于得出给定解决方案的计算过程。
因此,如果你已经计算出了 7 公斤的最佳选择,当重量要求提高到 10 公斤时,你将不必再次重新运行初始计算。这可以成为一种节省时间的度量方法。
在计算动态规划解决方案时,你必须首先确定目标函数,即描述最优结果应该是什么。
接下来,你必须将问题分解为更小的步骤。实现这一点的一种已经讨论过的方法是使用递归函数,即那些会反复调用自身直到得出解决方案的函数。

它们应该以这样的方式编写:你可以在不更改已编写方法代码的情况下改变结果。
在本节课中,我们一起学习了动态规划是一种旨在优化给定问题解决方案的方法;它利用记忆化和重叠子问题的原理,来识别何时可以快速实现目标函数,从而优化所需的计算步骤。
Python 150:贪心算法 🧠
在本节课中,我们将学习如何运用贪心算法这一范式来解决复杂问题。贪心算法是一种简单直接的策略,它通过每一步选择当前看起来最优的选项来寻求问题的解决方案。
概述:贪心算法的哲学与原理

上一节我们介绍了动态规划等复杂的问题解决方法。本节中,我们来看看一种更简单直接的策略——贪心算法。
有一种哲学原理称为奥卡姆剃刀。它指出,最简单的解决方案几乎总是最好的。这个解决问题的原则主张,简单优于复杂。在我们的语境中,贪心算法就是那个简单的解决方案。


贪心算法是动态规划的一种替代方法。这种方法旨在为任务提供即时解决方案,并倾向于局部优化,而非更全面的全局方法。


贪心算法 vs. 动态规划
当处理一个被细分为多个部分的问题时,使用动态规划方法会寻找一个全局最优解,即解决每个子问题,选择并实施最佳的子集。
而贪心方法则会查看解决方案列表并实施局部优化。通常,它会选择当前回报最高的选项。

为了让这一点更清晰,我们举一个CPU需要完成一系列任务的例子。

应用动态规划方法需要选择一个能在给定时间内完成的活动子集来执行,这类似于背包问题。这涉及到确定打包哪些物品子集能在装满背包的过程中最大化总价值。
对此问题的贪心算法方法则总是选择最有价值的物品放入背包,而不考虑这会从过程中排除哪些其他物品。😊

因此,在我们的CPU示例中,贪心方法将首先选择运行时间最短的程序,然后是下一个最短的程序,依此类推。虽然这可能不会带来全局最优的解决方案,但它会减少计算最有效物品子集所需的任何开销。
实例分析:最短路径问题
为了更好地理解这两种方法的不同,让我们考虑最短路径问题。图像显示了一个包含9个不同节点(A, B, C, D, E, F, G, H, S)的地图。每个节点通过一条带权重的路径连接到另一个节点。这个权重反映了选择这条路径所产生的成本。
你现在面临从节点E到节点F的旅程,并希望规划最有效的路线。
动态规划方法将涉及创建一个表格,并从E开始计算每个潜在节点的成本。然后,它会引入下一组节点并计算累积成本。这种方法无疑会得出最有效的解决方案。


在初始计算完成后使用记忆化技术,结果会被保存下来,后续的旅程将受益于更快的计算时间。😊 这是一种自底向上的全局问题解决方法。
贪心算法在路径问题中的应用
贪心方法在其方法论上有所不同。它不是试图找到连接路线的最优子集,而是从节点E开始,查看每个可用的连接。
因此,它有一组权重值可选,即5、3、2、4和12,分别对应节点C、B、D、G和H。该数组中的最小值是2,对应节点D。遵循贪心原则,它会做出这个选择并前进到下一个节点。


假设数据结构是一个有向图,它将面临另外三个节点A、F和G,其值分别为7、5和6。由于F是最终目的地,它会选择F并愉快地到达终点,累计的旅行时间代价为7(从E到D的权重2加上从D到F的权重5)。😊
从视觉上看,你可以发现这是最有效的路径,并且是在没有创建详尽的组合表和计算所有路线的情况下得出的。
然而,如果节点G和F之间的路径权重是2,那么它可能会选择一个次优的解决方案。

贪心算法的权衡

这就是选择贪心方法而非动态方法时需要做的权衡。
虽然贪心算法的开销很低,并且编码解决方案相当简单,但它并不总是保证返回最佳选项。


总结
本节课中,我们一起学习了贪心算法的方法。此外,你也看到了它与动态解决方案的比较,从而加深了对这种替代方法优缺点理解。
下次你在谷歌地图上规划路线时,可以考虑一下所提供的路线选择,并思考这些路线可能是如何计算出来的。😊
Python 151:模块小结 - 算法介绍 🎯
在本节课中,我们将回顾算法模块的核心内容。我们将总结排序、搜索算法,以及分治、递归、动态规划和贪心算法等关键概念。

排序算法回顾 🔄

上一节我们介绍了排序算法的重要性。本节中我们来看看三种主要的排序方法。

以下是三种核心排序算法:
- 选择排序:遍历未排序部分,找到最小(或最大)元素,将其放到已排序序列的末尾。
- 插入排序:将未排序部分的元素逐个插入到已排序部分的正确位置。
- 快速排序:选择一个“基准”元素,将数组分为小于基准和大于基准的两部分,然后递归地对这两部分进行排序。

这些算法各有优劣。选择排序实现简单,但效率较低。插入排序对小规模或基本有序的数据效率高。快速排序在平均情况下性能优异。重要的是,没有一种排序算法在所有场景下都是最优的。
搜索算法回顾 🔍


接下来,我们学习了计算机科学中的基础概念——搜索算法。
以下是两种核心搜索方法:
- 线性搜索:顺序遍历数据结构中的每个元素,直到找到目标。
def linear_search(arr, target): for i in range(len(arr)): if arr[i] == target: return i return -1 - 二分搜索:要求数据已排序。每次迭代将搜索范围减半。
def binary_search(arr, target): low, high = 0, len(arr) - 1 while low <= high: mid = (low + high) // 2 if arr[mid] == target: return mid elif arr[mid] < target: low = mid + 1 else: high = mid - 1 return -1
我们还深入探讨了搜索和排序算法的时间与空间复杂度,这是评估算法效率的关键指标。
算法设计范式 🧩
掌握了基础算法后,我们进入了更高级的算法设计范式。

首先,我们探索了分治法。该方法包含三个步骤:
- 分:将大问题分解为更小的子问题。
- 治:递归地解决每个子问题。
- 合(可选):将子问题的解合并为原问题的解。

分治法为解决问题提供了一个有效的框架。
接下来,我们学习了递归。递归是指函数直接或间接调用自身来解决问题。
实现递归方案需要三个要素:
- 基准情形:递归终止的条件。
- 递减结构:问题规模随着递归调用而减小。
- 递归调用:函数调用自身。
然后,我们介绍了动态规划。这是一种通过将问题分解为重叠子问题来高效求解的范式。其核心思想是存储子问题的解(即记忆化),避免重复计算。

动态规划的求解过程通常可以概括为:
- 定义目标函数(描述最优解)。
- 将问题分解为子问题。
- 选择自顶向下(记忆化搜索)或自底向上(制表法)的动态规划方法来实现。

最后,我们了解了贪心算法。与动态规划考虑全局最优解不同,贪心算法在每一步都做出当前看来最优的局部选择。
选择贪心算法而非动态规划需要权衡。贪心算法开销低、实现简单,但它不能保证总是得到全局最优解。

本节课中我们一起学习了算法模块的核心知识。我们回顾了排序与搜索算法,并探讨了分治、递归、动态规划和贪心等高级算法设计思想。您已经掌握了评估和选择合适算法工具的基础。接下来请完成本模块的最终测验,然后进入最后一个模块完成毕业项目评估。您已经非常接近终点了。祝您好运,享受接下来的学习旅程!🚀
Python 152:课程回顾
在本节课中,我们将对课程所涵盖的一系列核心概念与技能进行回顾总结,为你准备编程面试提供清晰的脉络。
概述
本课程旨在帮助你为编程面试做好准备。我们学习了从面试技巧、计算机科学基础,到数据结构和算法的广泛内容。接下来,我们将分模块回顾这些关键知识点。
模块一:编程面试准备
上一节我们介绍了课程的整体目标,本节中我们来看看第一个模块,它专注于编程面试本身。

你首先了解了什么是编程面试、其可能包含的形式以及你可能遇到的不同面试类型。

第一课聚焦于技术性编程面试,其主要目的是确认你是否具备承担岗位职责的技术能力。
你学习了在这种面试进行时必须牢记的步骤。


课程强调,使用合适的工具始终很重要,并且你必须将时间限制牢记在心。

你还探索了如何为编程面试做准备,以及第一印象的重要性,包括关注沟通技巧,例如解释你的思维过程和处理错误。


你学习了STAR方法,以及如何在与面试官沟通时利用它来获益。
你也学习了如何使用伪代码来演示你如何得出解决方案。
以下是关于实际解决方案设计的一些重要技巧,以及如何测试你的解决方案。

模块二:计算机科学基础
在下一课中,你开始接触计算机科学,首先是对二进制系统的概述,你学习了十进制(B10)和二进制(B2)之间的区别。

接着你发现了位置记数法,即利用数字的位置来表示数值的递增。
然后你继续探索了计算机内存的关键组件及其工作原理。

你现在应该知道为了更好地理解内存的各个层次,并且应该能够描述它们之间的差异。

你学习了传输速率,即计算机将内存传输到缓存进行处理的速度。
接着你转向了时间复杂度,学习了如何通过完成任务所需的时间来评估时间效率或衡量性能。
你发现了大O表示法,这是一种用于确定算法效率的度量标准。
你探索了空间复杂度,这本质上是计算结果所需的空间。

并且关于空间复杂度的决策不仅基于算法的速度,还基于给定解决方案将使用多少内存容量。
在速度和紧凑性之间总是需要做出权衡选择。

模块三:数据结构
在第二个模块中,你学习了数据结构。这涵盖了从字符串、布尔值或数组等基本数据结构,到集合、图和堆等更高级的数据结构,以及每种数据结构带来的特定优势和限制。
你探索了所有类型的数据结构,以及它们如何被分类为两个主要分支:线性和非线性。

接下来,你被介绍了栈和队列,这两种抽象数据结构在元素的添加和移除方式上都有特定的特性。
当你学习队列时,你了解到队列与栈非常相似,它们往往具有相同的方法:创建、插入、移除和检查队列状态。与栈不同,队列基于先进先出(FIFO)的原则工作。
最后,你发现树是一种强大的数据结构,它在添加和搜索值方面提供了极大的灵活性。
在此之后,你继续研究了一些高级数据结构,即哈希表、堆和图。
接着,你探索了堆。你发现了堆如何用于将元素从最不重要到最重要进行组织,以及通过限制堆的功能,如何提高生产力。
最后,你研究了图。这种结构图示了一个由节点(表示目的地)和边(显示每个节点如何与另一个节点相关联)组成的图。节点之间存在值,意味着这是一个加权图。没有箭头存在,意味着这是一个无向图,与有向图形成对比。无向图没有优先顺序。
你了解到,在有向图中,如果边是单向的,则连接被认为是弱连接的。然而,如果两个节点之间存在双向连接,则称其为强连接。
模块四:算法
在第三个模块中,你初步了解了算法,包括可用的算法类型,以及如何最好地使用它们来排序和搜索你的数据。
你首先探索了排序算法,以及使用已排序数据或能够对自有数据进行排序如何能显著节省时间。
你发现了排序的重要性,并探索了三种主要的排序方法:选择排序、插入排序和快速排序。
接下来,你继续发现了搜索算法,以及每种类型如何为解决问题提供自己的框架。


你探索了两种核心的搜索方法:线性和二分。
- 线性搜索:遍历给定数据结构中的每一项,直到找到特定项。
- 二分搜索:在每次迭代中将搜索空间减半。



你还深入了解了搜索和排序算法中的时间和空间复杂度。

然后你进入最后一课,该课介绍了如何使用算法。
在这里,你学习了处理算法的不同方法。
首先,你探索了分治范式。你了解到,在“分”的步骤中,输入被分割成更小的段并单独处理。在“治”的步骤中,解决与给定段相关的每个任务。可选的最后一步“合”是组合所有已解决的段。
接下来,你探索了另一个重要的算法方法:递归。
递归是指一个函数用问题的较小实例反复调用自身,直到满足某个退出条件。
你了解到实现递归解决方案有三个要求:基本情况、递减结构和递归调用。


接着你被介绍了动态规划,这是一种通过将问题分解为更小问题来促进解决问题的编程范式。

你检查了计算动态规划解决方案所涉及的过程。

本质上,这可以概括为:首先,确定目标函数,即描述什么是最佳结果。接着,将问题分解为更小的步骤,然后决定你希望应用哪种方法来实现期望的结果。


最后,你学习了贪心算法,并与动态规划方法进行了比较。
贪心方法会查看解决方案列表并实施局部优化。通常,会选择当前回报最高的选项。


你看到了一个示例,说明如何实现贪心算法方法来达成解决方案。


虽然贪心算法的开销较低,并且编码解决方案相当直接,但它并不总是保证返回最佳选项。因此,在选择贪心方法而非动态方法时存在权衡。


总结
在本节课中,我们一起回顾了贯穿本课程的许多重要概念和方法。这是一个真正的成就,它也应该为你可能参加的任何潜在编程面试做好准备。
你剩下要做的就是在结束课程之前完成最终的课程测验。祝你好运。
Python 153:26_课程总结
在本节课中,我们将对编码面试准备课程进行总结,回顾所学知识,并展望未来的学习与发展路径。
你已经完成了这门编码面试准备课程。你付出了巨大的努力,并在此过程中积累了丰富的知识。你在开发者的旅程中取得了巨大的进步。
现在,你应该理解编码面试独特且具有挑战性的方面。具体来说,你应该为面试做好充分准备,掌握一些有助于你在面试中表现出色的软技能。你还掌握了计算机科学的基础知识,以及一些可以应用于任何面试挑战的问题解决方法。

🎯 课程核心收获
上一节我们回顾了学习历程,本节中我们来看看完成本课程后你应具备的核心能力。


完成本课程后,你现在应该能够:
- 为整个面试流程做好准备。
- 提供成功的面试策略与技巧。
- 坦然讨论面试过程中的情绪因素。

🔑 关键技能评估
以下是课程评估中衡量的关键技能,它们揭示了你的知识与理解水平:

- 数据结构:在编码面试情境下理解与应用数据结构。
- 算法:掌握算法的概念与使用方法。
- 算法可视化:学会将算法过程可视化以辅助理解。
- 模式组合:能够结合新学的和已掌握的编码模式来解决问题。
🚀 继续你的旅程
恭喜你,你已经成功完成了本专业的所有课程。在此阶段,你可以考虑注册其他课程、专业或证书路径。
证书是全球公认且受行业认可的、掌握技术技能的证明。无论你是刚起步的技术专业人士、学生还是商业用户,你所完成的课程以及作品集中的一系列实践项目,都将证明你作为开发者的知识与能力。这些证书可以向潜在雇主展示你的技能。它不仅向雇主表明你具有自我驱动力和创新精神,也充分体现了你个人的特质以及新获得的知识。
到目前为止,你做得非常出色,应该为自己的进步感到自豪。你迄今为止获得的经验将向潜在雇主证明,你积极主动、能力出众,并且不畏惧学习新事物。
再次祝贺你完成本课程,并祝你在接下来的学习旅程中一切顺利。

📝 总结
本节课中我们一起学习了课程的核心总结。我们回顾了你在编码面试准备方面取得的成就,明确了完成课程后应掌握的关键技能,并探讨了如何利用这些成果继续你的职业发展与学习之路。请带着这份知识与自信,迎接未来的挑战。

浙公网安备 33010602011771号