iT邦幫忙

2026 iThome 鐵人賽

DAY 18
0

上一篇知道了資料要保存下來就需要資料庫,也決定這次先使用 SQLite。

今天就來認識關聯式資料庫最基本的東西:

Table、Row、Column、id,還有 SQL 的 SELECT 和 INSERT。

Table、Row、Column 是什麼?

關聯式資料庫把資料存在「表格」裡,可以先想成 Excel。

Table(資料表)
一張表格,用來存同一種資料。
例如 tasks 這張表就專門存作業。

Column(欄位)
表格的「直的」那一排,代表這種資料有哪些屬性。
例如 id、name、completed。

Row(資料列)
表格的「橫的」那一列,代表一筆資料。
例如「洗碗,未完成」就是一筆 Row。

畫成表格大概是這樣:

tasks

id name completed
1 洗碗 0
2 寫 Day 18 0

其實這跟我們前面寫的程式很像:

Day 14 我們用

tasks = [
    {"id": 1, "name": "洗碗", "completed": False},
]

List → 對應 Table(整張表)
Dict → 對應 Row(一筆資料)
Dict 的 key → 對應 Column(欄位)

所以概念上沒有變,只是換成存在資料庫裡。

id(主鍵)是什麼?

Day 14 我們自己幫每一筆資料加了一個 id,用來指定要操作哪一筆。

資料庫也有同樣的概念,叫做 Primary Key(主鍵)。

主鍵的規則是:

不能重複
不能是空的

有了主鍵,就可以精準地指到某一筆資料,像是:

「把 id = 1 的那一筆的 completed 改成 1」

在 SQLite 中,如果把 id 設成:

id INTEGER PRIMARY KEY AUTOINCREMENT

資料庫就會幫我們自動編號,不用像 Day 14 那樣自己維護 next_id。

SQL 是什麼?

SQL = Structured Query Language(結構化查詢語言)。

它是拿來跟關聯式資料庫溝通的語言。

我們想對資料做的事情,其實就是 Day 14 的 CRUD:

新增 → INSERT
查詢 → SELECT
修改 → UPDATE
刪除 → DELETE

對照起來會發現,其實跟 HTTP Method 是同一組概念,只是一邊是對 API 說,一邊是對資料庫說:

POST → INSERT
GET → SELECT
PUT → UPDATE
DELETE → DELETE

先建立一張表:CREATE TABLE

CREATE TABLE tasks (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    completed INTEGER NOT NULL DEFAULT 0
);

一行一行看:

id INTEGER PRIMARY KEY AUTOINCREMENT
→ id 是整數、是主鍵、自動編號

name TEXT NOT NULL
→ name 是文字,而且不可以是空的(NOT NULL)

completed INTEGER NOT NULL DEFAULT 0
→ completed 是整數,不可以空白,沒給值的話預設是 0

這裡有一個要注意的地方:

SQLite 沒有真正的布林(Boolean)型別,習慣上會用 0 代表 false、1 代表 true。

所以我們 API 裡的 completed: false,存進 SQLite 會變成 0。

(之後使用 ORM 的時候,這個轉換會由套件幫我們處理,不用自己換。)

另外像 NOT NULL 這種規定,就是上一篇說的「資料庫可以幫忙把關資料規則」,資料不符合規定時它會直接拒絕。

新增資料:INSERT

INSERT INTO tasks (name, completed) VALUES ('洗碗', 0);

意思是:在 tasks 這張表新增一筆,name 是「洗碗」,completed 是 0。

因為 id 設定了 AUTOINCREMENT,所以不用自己填,資料庫會給。

查詢資料:SELECT

查全部:

SELECT * FROM tasks;
  • 代表「所有欄位」。

也可以只查需要的欄位:

SELECT id, name FROM tasks;

加上條件:

SELECT * FROM tasks WHERE completed = 0;

WHERE 就是條件,這句的意思是「查出所有還沒完成的作業」。

查某一筆:

SELECT * FROM tasks WHERE id = 1;

這裡可以回頭對照 Day 14:

GET /tasks → SELECT * FROM tasks;
GET /tasks/1 → SELECT * FROM tasks WHERE id = 1;

前面我們是自己寫 for 迴圈一筆一筆找,資料庫則是用 WHERE 幫我們找。

修改和刪除:UPDATE、DELETE

UPDATE tasks SET completed = 1 WHERE id = 1;

DELETE FROM tasks WHERE id = 1;

這兩個一定要記得寫 WHERE。

如果寫成:

DELETE FROM tasks;

那就是把整張表的資料全部刪掉,而且不會跳出「確定嗎?」。

(這是很有名的慘案來源,練習的時候就養成先寫 WHERE 的習慣比較好。)

實際跑一次

光看 SQL 沒什麼感覺,我們直接用 Python 內建的 sqlite3 跑一次。

在專案資料夾建立一個新檔案:

db_demo.py

import sqlite3

# 連線到 demo.db(檔案不存在就會自動建立)
conn = sqlite3.connect('demo.db')
cursor = conn.cursor()

# 建立資料表
cursor.execute("""
CREATE TABLE IF NOT EXISTS tasks (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    completed INTEGER NOT NULL DEFAULT 0
)""")
# 新增兩筆資料
cursor.execute("INSERT INTO tasks (name, completed) VALUES (?, ?)", ("洗碗", 0))
cursor.execute("INSERT INTO tasks (name, completed) VALUES (?, ?)", ("寫 Day 18", 0))

# 存檔(很重要)
conn.commit()

# 查詢全部
print("=== 全部作業 ===")
rows = cursor.execute("SELECT id, name, completed FROM tasks").fetchall()
# 把 id = 1 改成已完成
for row in rows:
    print(row)

cursor.execute("UPDATE tasks SET completed = 1 WHERE id = ?", (1,))
conn.commit()

print("=== 還沒完成的作業 ===")
for row in rows:
    print(row)

conn.close()

執行:

python db_demo.py

終端機會看到類似:

=== 全部作業 ===
(1, ‘洗碗’, 0)
(2, ‘寫 Day 18’, 0)
=== 還沒完成的作業 ===
(2, ‘寫 Day 18’)
https://ithelp.ithome.com.tw/upload/images/20261002/20183865oK4KmCu4OB.png
終端機執行 db_demo.py 的輸出結果

而且資料夾裡會多出一個檔案:

demo.db

這就是 SQLite 的資料庫檔案,整個資料庫就是這一個檔案。
資料夾裡出現 demo.db 這個檔案
https://ithelp.ithome.com.tw/upload/images/20261002/201838656Ld8kLix9m.png
最重要的是:

再執行一次 python db_demo.py

會發現資料變成四筆了(原本兩筆 + 新增的兩筆)。
https://ithelp.ithome.com.tw/upload/images/20261002/20183865AGKxHosHNu.png
這就代表資料真的存到硬碟上了,不像前面存在記憶體那樣一關就沒。

(如果想重新開始,把 demo.db 刪掉再執行一次就可以了。)

兩個小地方先提一下

第一,conn.commit()

SQLite 在做新增、修改、刪除之後,要 commit 才會真的寫進資料庫。
如果忘記寫,程式結束後會發現資料沒有存進去。

第二,為什麼是問號?

cursor.execute("INSERT INTO tasks (name, completed) VALUES (?, ?)", ("洗碗", 0))

這裡沒有把資料直接接在 SQL 字串裡面,而是先寫問號,再把值另外傳進去。

這叫做參數化查詢,跟資安有關,是防止 SQL Injection 的關鍵。

Day 27、Day 28 會專門講這件事,現在先記得:

不要用字串把使用者的輸入直接拼進 SQL。

今天認識了關聯式資料庫的基本結構和 SQL:

Table → 一張表,存同一種資料
Column → 欄位,例如 id、name
Row → 一筆資料
Primary Key → 每筆資料的唯一編號
INSERT / SELECT / UPDATE / DELETE → 對應 CRUD

也實際用 Python 操作了一次 SQLite,看到資料真的被保存下來。

不過今天的程式全部都是自己寫 SQL 字串,看起來跟我們的 Flask API 還是兩回事。

如果每次要操作資料庫都要自己寫 SQL、自己轉成字典,好像有點麻煩。

下一篇就來看看 ORM 是什麼,以及 Flask 要怎麼連資料庫。


上一篇
Day 17|為什麼需要資料庫?
系列文
從零開始的後端開發:用 Flask 實作 REST API,搞懂 API 與資料庫之間如何協作 共 18 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言