|
|
<!--
|
|
|
CO_OP_TRANSLATOR_METADATA:
|
|
|
{
|
|
|
"original_hash": "870a0086adbc313a8eea5489bdcb2522",
|
|
|
"translation_date": "2025-08-25T16:14:21+00:00",
|
|
|
"source_file": "2-Working-With-Data/05-relational-databases/README.md",
|
|
|
"language_code": "hk"
|
|
|
}
|
|
|
-->
|
|
|
# 使用數據:關係型數據庫
|
|
|
|
|
|
| 繪製的手繪筆記 ](../../sketchnotes/05-RelationalData.png)|
|
|
|
|:---:|
|
|
|
| 使用數據:關係型數據庫 - _手繪筆記由 [@nitya](https://twitter.com/nitya) 繪製_ |
|
|
|
|
|
|
你可能曾經使用過電子表格來存儲信息。電子表格由一組行和列組成,行包含信息(或數據),列描述這些信息(有時稱為元數據)。關係型數據庫正是基於這種表格中行和列的核心原則構建的,允許你將信息分散到多個表中。這樣可以處理更複雜的數據,避免重複,並且在探索數據時更加靈活。讓我們一起探索關係型數據庫的概念。
|
|
|
|
|
|
## [課前測驗](https://purple-hill-04aebfb03.1.azurestaticapps.net/quiz/8)
|
|
|
|
|
|
## 一切從表開始
|
|
|
|
|
|
關係型數據庫的核心是表。就像電子表格一樣,表是由列和行組成的集合。行包含我們希望處理的數據或信息,例如城市名稱或降雨量。列則描述它們存儲的數據。
|
|
|
|
|
|
讓我們從創建一個存儲城市信息的表開始探索。我們可能會從城市名稱和國家開始。你可以將其存儲在如下表格中:
|
|
|
|
|
|
| 城市 | 國家 |
|
|
|
| -------- | ------------- |
|
|
|
| 東京 | 日本 |
|
|
|
| 亞特蘭大 | 美國 |
|
|
|
| 奧克蘭 | 新西蘭 |
|
|
|
|
|
|
注意,**城市**、**國家**和**人口**這些列名描述了存儲的數據,而每一行則包含一個城市的信息。
|
|
|
|
|
|
## 單表方法的局限性
|
|
|
|
|
|
上述表格可能對你來說很熟悉。現在讓我們為這個初具規模的數據庫添加一些額外的數據——年度降雨量(以毫米為單位)。我們將關注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
|
|
|
|
|
|
### cities
|
|
|
|
|
|
| city_id | 城市 | 國家 |
|
|
|
| ------- | -------- | ------------- |
|
|
|
| 1 | 東京 | 日本 |
|
|
|
| 2 | 亞特蘭大 | 美國 |
|
|
|
| 3 | 奧克蘭 | 新西蘭 |
|
|
|
|
|
|
> ✅ 在本課程中,你會注意到我們交替使用 "id" 和 "主鍵" 這兩個術語。這些概念同樣適用於你稍後會探索的 DataFrames。雖然 DataFrames 不使用 "主鍵" 這一術語,但你會發現它們的行為非常相似。
|
|
|
|
|
|
有了我們的城市表,現在讓我們存儲降雨量。與其重複城市的完整信息,我們可以使用 ID。我們還應確保新創建的表也有一個 *id* 列,因為所有表都應該有一個 ID 或主鍵。
|
|
|
|
|
|
### rainfall
|
|
|
|
|
|
| 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 |
|
|
|
|
|
|
注意新創建的 **rainfall** 表中的 **city_id** 列。這一列包含的值引用了 **cities** 表中的 ID。在技術的關係型數據術語中,這被稱為 **外鍵**;它是來自另一個表的主鍵。你可以將其視為一個引用或指針。**city_id** 1 指向東京。
|
|
|
|
|
|
> [!NOTE] 外鍵通常縮寫為 FK
|
|
|
|
|
|
## 檢索數據
|
|
|
|
|
|
將數據分成兩個表後,你可能會想知道如何檢索它。如果我們使用的是 MySQL、SQL Server 或 Oracle 等關係型數據庫,我們可以使用一種稱為結構化查詢語言(SQL)的語言。SQL(有時讀作 sequel)是一種用於檢索和修改關係型數據庫中數據的標準語言。
|
|
|
|
|
|
要檢索數據,你可以使用命令 `SELECT`。其核心是,你**選擇**想要查看的列,**從**它們所在的表中檢索。如果你只想顯示城市的名稱,可以使用以下語句:
|
|
|
|
|
|
```sql
|
|
|
SELECT city
|
|
|
FROM cities;
|
|
|
|
|
|
-- Output:
|
|
|
-- Tokyo
|
|
|
-- Atlanta
|
|
|
-- Auckland
|
|
|
```
|
|
|
|
|
|
`SELECT` 是用來列出列名的,而 `FROM` 是用來列出表名的。
|
|
|
|
|
|
> [NOTE] SQL 語法不區分大小寫,這意味著 `select` 和 `SELECT` 是一樣的。然而,根據你使用的數據庫類型,列名和表名可能區分大小寫。因此,最佳實踐是始終將編程中的所有內容視為區分大小寫。在撰寫 SQL 查詢時,常見的約定是將關鍵字全部用大寫字母表示。
|
|
|
|
|
|
上述查詢將顯示所有城市。假設我們只想顯示新西蘭的城市。我們需要某種形式的篩選器。SQL 中的關鍵字是 `WHERE`,即 "條件為真時"。
|
|
|
|
|
|
```sql
|
|
|
SELECT city
|
|
|
FROM cities
|
|
|
WHERE country = 'New Zealand';
|
|
|
|
|
|
-- Output:
|
|
|
-- Auckland
|
|
|
```
|
|
|
|
|
|
## 數據的連接
|
|
|
|
|
|
到目前為止,我們只從一個表中檢索數據。現在我們希望將 **cities** 和 **rainfall** 的數據結合起來。這可以通過*連接*它們來完成。你將在兩個表之間創建一個接縫,並匹配每個表中的某一列的值。
|
|
|
|
|
|
在我們的例子中,我們將匹配 **rainfall** 表中的 **city_id** 列與 **cities** 表中的 **city_id** 列。這將把降雨量與其對應的城市匹配起來。我們將執行的連接類型稱為*內連接*,這意味著如果某些行與另一個表中的任何內容不匹配,它們將不會顯示。在我們的例子中,每個城市都有降雨量,因此所有內容都會顯示。
|
|
|
|
|
|
讓我們檢索所有城市在2019年的降雨量。
|
|
|
|
|
|
我們將分步完成。第一步是通過指定接縫的列(即 **city_id**)來連接數據。
|
|
|
|
|
|
```sql
|
|
|
SELECT cities.city
|
|
|
rainfall.amount
|
|
|
FROM cities
|
|
|
INNER JOIN rainfall ON cities.city_id = rainfall.city_id
|
|
|
```
|
|
|
|
|
|
我們已經突出顯示了我們想要的兩列,以及我們希望通過 **city_id** 將表連接起來的事實。現在我們可以添加 `WHERE` 語句來篩選出僅2019年的數據。
|
|
|
|
|
|
```sql
|
|
|
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
|
|
|
```
|
|
|
|
|
|
## 總結
|
|
|
|
|
|
關係型數據庫的核心是將信息分割到多個表中,然後將其重新組合以進行顯示和分析。這提供了極高的靈活性來執行計算或以其他方式操作數據。你已經了解了關係型數據庫的核心概念,以及如何在兩個表之間執行連接。
|
|
|
|
|
|
## 🚀 挑戰
|
|
|
|
|
|
網絡上有許多關係型數據庫可供使用。你可以利用上面學到的技能來探索這些數據。
|
|
|
|
|
|
## 課後測驗
|
|
|
|
|
|
## [課後測驗](https://purple-hill-04aebfb03.1.azurestaticapps.net/quiz/9)
|
|
|
|
|
|
## 回顧與自學
|
|
|
|
|
|
[Microsoft Learn](https://docs.microsoft.com/learn?WT.mc_id=academic-77958-bethanycheum) 上有多種資源可供你繼續探索 SQL 和關係型數據庫的概念:
|
|
|
|
|
|
- [描述關係型數據的概念](https://docs.microsoft.com//learn/modules/describe-concepts-of-relational-data?WT.mc_id=academic-77958-bethanycheum)
|
|
|
- [開始使用 Transact-SQL 查詢](https://docs.microsoft.com//learn/paths/get-started-querying-with-transact-sql?WT.mc_id=academic-77958-bethanycheum)(Transact-SQL 是 SQL 的一個版本)
|
|
|
- [Microsoft Learn 上的 SQL 內容](https://docs.microsoft.com/learn/browse/?products=azure-sql-database%2Csql-server&expanded=azure&WT.mc_id=academic-77958-bethanycheum)
|
|
|
|
|
|
## 作業
|
|
|
|
|
|
[作業標題](assignment.md)
|
|
|
|
|
|
**免責聲明**:
|
|
|
本文件已使用人工智能翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。原始語言的文件應被視為權威來源。對於重要信息,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋概不負責。 |