9.9 KiB
使用数据:关系型数据库
![]() |
|---|
| 使用数据:关系型数据库 - 速记图由 @nitya 绘制 |
你可能曾经用过电子表格来存储信息。电子表格由一组行和列组成,行中包含信息(或数据),列则描述这些信息(有时称为元数据)。关系型数据库正是基于表格中行和列的核心原理构建的,它允许你将信息分布在多个表中。这使得你可以处理更复杂的数据,避免数据重复,并在探索数据时拥有更大的灵活性。让我们一起来探索关系型数据库的概念。
课前测验
一切从表格开始
关系型数据库的核心是表格。就像电子表格一样,表格是由行和列组成的集合。行包含我们希望处理的数据或信息,例如城市名称或降雨量。列则描述了它们存储的数据。
让我们从创建一个存储城市信息的表格开始。我们可以从城市名称和国家开始。你可以将其存储在如下表格中:
| 城市 | 国家 |
|---|---|
| 东京 | 日本 |
| 亚特兰大 | 美国 |
| 奥克兰 | 新西兰 |
注意,城市、国家和人口这些列名描述了存储的数据,每一行都包含一个城市的信息。
单一表格方法的局限性
上面的表格看起来可能对你来说很熟悉。现在我们尝试向这个新兴的数据库中添加一些额外的数据——年降雨量(以毫米为单位)。我们将关注2018年、2019年和2020年的数据。如果我们为东京添加这些数据,可能会是这样的:
| 城市 | 国家 | 年份 | 降雨量 |
|---|---|---|---|
| 东京 | 日本 | 2020 | 1690 |
| 东京 | 日本 | 2019 | 1874 |
| 东京 | 日本 | 2018 | 1445 |
你注意到我们的表格有什么问题了吗?你可能会注意到我们重复了城市的名称和国家多次。这会占用相当多的存储空间,而且大部分情况下是不必要的。毕竟,东京只有一个我们感兴趣的名称。
好吧,我们试试别的方法。我们为每一年添加新的列:
| 城市 | 国家 | 2018 | 2019 | 2020 |
|---|---|---|---|---|
| 东京 | 日本 | 1445 | 1874 | 1690 |
| 亚特兰大 | 美国 | 1779 | 1111 | 1683 |
| 奥克兰 | 新西兰 | 1386 | 942 | 1176 |
虽然这样避免了行的重复,但也带来了其他问题。每次有新的一年时,我们都需要修改表格的结构。此外,随着数据的增长,将年份作为列会使得检索和计算值变得更加困难。
这就是为什么我们需要多个表格和关系。通过将数据分解开来,我们可以避免重复,并在处理数据时拥有更大的灵活性。
关系的概念
让我们回到数据,确定如何分解它们。我们知道需要存储城市的名称和国家,因此这部分数据最好存储在一个表中。
| 城市 | 国家 |
|---|---|
| 东京 | 日本 |
| 亚特兰大 | 美国 |
| 奥克兰 | 新西兰 |
但在创建下一个表之前,我们需要弄清楚如何引用每个城市。我们需要某种形式的标识符、ID 或(在数据库术语中)主键。主键是用于标识表中某一特定行的值。虽然这可以基于某个值本身(例如,我们可以使用城市的名称),但它几乎总是一个数字或其他标识符。我们不希望 ID 发生变化,因为这会破坏关系。大多数情况下,主键或 ID 是自动生成的数字。
✅ 主键通常缩写为 PK
城市表
| city_id | 城市 | 国家 |
|---|---|---|
| 1 | 东京 | 日本 |
| 2 | 亚特兰大 | 美国 |
| 3 | 奥克兰 | 新西兰 |
✅ 在本课程中,你会注意到我们交替使用“id”和“主键”这两个术语。这里的概念同样适用于你稍后会探索的 DataFrame。虽然 DataFrame 不使用“主键”这个术语,但你会注意到它们的行为非常相似。
创建了城市表后,让我们存储降雨量。与其重复存储城市的完整信息,我们可以使用 ID。我们还应该确保新创建的表也有一个 id 列,因为所有表都应该有一个 id 或主键。
降雨量表
| rainfall_id | city_id | 年份 | 降雨量 |
|---|---|---|---|
| 1 | 1 | 2018 | 1445 |
| 2 | 1 | 2019 | 1874 |
| 3 | 1 | 2020 | 1690 |
| 4 | 2 | 2018 | 1779 |
| 5 | 2 | 2019 | 1111 |
| 6 | 2 | 2020 | 1683 |
| 7 | 3 | 2018 | 1386 |
| 8 | 3 | 2019 | 942 |
| 9 | 3 | 2020 | 1176 |
注意新创建的 降雨量 表中的 city_id 列。此列包含引用 城市 表中 ID 的值。在关系型数据的技术术语中,这称为 外键;它是另一个表中的主键。你可以简单地将其视为一个引用或指针。city_id 为 1 的值指向东京。
[!NOTE] 外键通常缩写为 FK
检索数据
将数据分成两个表后,你可能会想如何检索它们。如果我们使用 MySQL、SQL Server 或 Oracle 等关系型数据库,可以使用一种称为结构化查询语言(SQL)的语言。SQL(有时读作 sequel)是一种用于在关系型数据库中检索和修改数据的标准语言。
要检索数据,你可以使用命令 SELECT。其核心是,你选择想要查看的列,并从它们所在的表中提取。如果你只想显示城市的名称,可以使用以下命令:
SELECT city
FROM cities;
-- Output:
-- Tokyo
-- Atlanta
-- Auckland
SELECT 是列出列名的地方,而 FROM 是列出表名的地方。
[!NOTE] SQL 语法不区分大小写,这意味着
select和SELECT是一样的。然而,根据你使用的数据库类型,列名和表名可能区分大小写。因此,作为最佳实践,建议在编写 SQL 查询时始终将所有内容视为区分大小写。编写 SQL 查询时,通常的惯例是将关键字全部用大写字母表示。
上面的查询将显示所有城市。假设我们只想显示新西兰的城市。我们需要某种形式的过滤器。SQL 中的关键字是 WHERE,表示“某条件为真时”。
SELECT city
FROM cities
WHERE country = 'New Zealand';
-- Output:
-- Auckland
数据联接
到目前为止,我们只从一个表中检索数据。现在我们想将 城市 和 降雨量 中的数据结合起来。这可以通过联接它们来实现。你实际上是在两个表之间创建一个连接,并将每个表中的列值匹配起来。
在我们的示例中,我们将匹配 降雨量 表中的 city_id 列和 城市 表中的 city_id 列。这将把降雨量值与其对应的城市匹配起来。我们将执行一种称为内联接的联接,这意味着如果某些行与另一个表中的任何内容不匹配,它们将不会显示。在我们的例子中,每个城市都有降雨量数据,因此所有内容都会显示。
让我们检索所有城市在2019年的降雨量。
我们将分步骤进行。第一步是通过指定连接的列(即 city_id)将数据联接在一起。
SELECT cities.city
rainfall.amount
FROM cities
INNER JOIN rainfall ON cities.city_id = rainfall.city_id
我们已经标出了我们需要的两列,并指出我们希望通过 city_id 将表格联接在一起。现在我们可以添加 WHERE 语句来过滤出仅2019年的数据。
SELECT cities.city
rainfall.amount
FROM cities
INNER JOIN rainfall ON cities.city_id = rainfall.city_id
WHERE rainfall.year = 2019
-- Output
-- city | amount
-- -------- | ------
-- Tokyo | 1874
-- Atlanta | 1111
-- Auckland | 942
总结
关系型数据库的核心是将信息分成多个表格,然后将其重新组合以进行显示和分析。这提供了高度的灵活性,可以执行计算或以其他方式操作数据。你已经了解了关系型数据库的核心概念,以及如何在两个表之间进行联接。
🚀 挑战
互联网上有许多关系型数据库。你可以使用上面学到的技能来探索这些数据。
课后测验
课后测验
复习与自学
Microsoft Learn 上有许多资源可以帮助你继续探索 SQL 和关系型数据库的概念。
- 描述关系型数据的概念
- 开始使用 Transact-SQL 进行查询(Transact-SQL 是 SQL 的一个版本)
- Microsoft Learn 上的 SQL 内容
作业
免责声明:
本文档使用AI翻译服务Co-op Translator进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用此翻译而产生的任何误解或误读承担责任。
