** 提醒自己要練習 SQL,本篇為作者自學筆記,圖與資源來自各大神和ChatGPT
SQL(結構化查詢語言)可以按照功能分成四種主要的語言類別,每一類別負責不同的資料庫操作。
功能: 用來定義資料庫的結構,例如建立、修改或刪除資料表和其他結構。
常見操作:
CREATE
:建立新的資料表或資料庫。ALTER
:修改現有的資料表結構。DROP
:刪除資料表或資料庫。TRUNCATE
:清空資料表內容,但保留結構。例子:(參考 ChatGPT)
建立名為 users 的表格
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100)
);
-- 新增欄位 age 到 users 表格
ALTER TABLE users ADD age INT;
-- 刪除 users 表格
DROP TABLE users;
功能: 用來處理資料庫中的資料,主要是查詢、插入、更新和刪除資料。
常見操作:
SELECT
:查詢資料。INSERT
:插入新資料。UPDATE
:更新已存在的資料。DELETE
:刪除資料。例子:
-- 插入一筆新資料到 users 表格
INSERT INTO users (id, name, email, age)
VALUES (1, 'Alice', 'alice@example.com', 25);
-- 更新 users 表格中 id 為 1 的資料
UPDATE users
SET age = 26
WHERE id = 1;
-- 刪除 users 表格中 age 小於 18 的資料
DELETE FROM users
WHERE age < 18;
功能: 用來管理交易(transaction),確保資料的一致性與完整性,常用於多步驟的操作中。
常見操作:
COMMIT
:提交交易,使修改永久生效。ROLLBACK
:回復上一個交易,取消之前的修改。SAVEPOINT
:設定交易的保存點,允許回復到某一特定階段。例子:
-- 開始交易
BEGIN;
-- 插入資料
INSERT INTO users (id, name, email, age)
VALUES (2, 'Bob', 'bob@example.com', 30);
-- 由於發現錯誤,回復交易
ROLLBACK;
-- 重新插入正確的資料
INSERT INTO users (id, name, email, age)
VALUES (2, 'Bob', 'bob.correct@example.com', 30);
-- 提交交易
COMMIT;
功能: 用來控制資料庫的存取權限,保障資料的安全性。
常見操作:
GRANT
:授權給使用者特定的操作權限。REVOKE
:收回使用者的操作權限。例子:
-- 給某使用者讀取和插入資料的權限
GRANT SELECT, INSERT ON users TO 'username';
-- 收回該使用者的插入權限
REVOKE INSERT ON users FROM 'username';
在 SQL 中,交易是一組邏輯操作單位,通常包含多個步驟(如插入、更新、刪除)。交易的目標是確保這些操作要麼全部成功,要麼全部失敗,保證資料的一致性和正確性。
假設 A 要轉帳 200 元給 B,這筆交易包含以下兩個步驟:
為了保證這筆交易的完整性,這兩個步驟必須:
為了設計可靠的交易系統,關聯交易必須具備以下四個特性,稱為 ACID:
定義:
交易中的所有操作必須視為一個整體(原子單位)。交易是一個大動作,要嘛成功要嘛失敗,沒有成功一半。
例子:
定義:
交易開始前和結束後,資料必須保持一致。換句話說,交易完成後,資料庫的狀態必須符合業務規則和約束條件。
例子:
定義:
多個交易同時進行時,彼此之間的操作不應互相影響。交易在提交前,它的中間狀態對其他交易是不可見的。這會衍伸出
例子:
假設現在有兩個交易正在進行,如果沒有設計好關聯式資料庫的隔離性就會出現以下問題:
在同一個 transaction 裡面連續使用相同的 Query 讀取了多次資料,但是相同的 Query 卻回傳了不同的結果,這就是 Non-repeatable reads。Dirty read 也是 non-repeatable read 的一種。
連續搜尋兩次範圍內的筆數,結果不一樣。如 SELECT ... WHERE
時,因為其他交易插入或刪除了符合範圍條件的數據,導致相同範圍查詢在同一交易中執行兩次時,結果不同。
SELECT * FROM orders WHERE amount > 100;
amount > 100
,例如:INSERT INTO orders (id, amount) VALUES (6, 150);
SELECT * FROM orders WHERE amount > 100;
定義:
交易提交後,其結果必須永久保存在資料庫中,即使系統發生故障(如斷電、崩潰),提交的數據也不會不見。
例子:
在 SQL 中,交易可以使用以下指令進行控制:
BEGIN
或 START TRANSACTION
:開始交易。COMMIT
:提交交易,將變更永久保存。ROLLBACK
:回復交易,取消所有操作。SAVEPOINT
:設定保存點,允許回復到特定階段。為了避免關聯式資料庫出現資料不對稱等問題,在資料庫設計結構時出現「正規化」的要求,拆分資料、消除冗餘、避免異常(例如插入、刪除、更新異常),來確保數據的一致性和完整性。
正規化過程遵循一系列規則(1NF、2NF、3NF 等),每個階段都對表結構有不同的要求。
正規化是分階段進行的,必須先滿足前一階段的要求才能進入下一階段。以下介紹最常用的 1NF、2NF、3NF:
目標:確保「每個欄位都只能存放一個值」,即消除「重複組」或「多值欄位」。
要求:
我們先來看以下的舉例,這份表格哪裡不符合第一正規化(1NF)?
目標:消除「部分依賴」,即所有 key 要完全依賴整個 Primary Key。
要求:
下圖是違反 2NF 的案例Student ID 跟 Course ID 是複合鍵,兩個一組是 Primary Key。但學費(Course Fee)跟 Student ID 沒有關係,所以只有依賴 Course ID。
解決方是一樣是分成兩個表格:
目標:消除「Transitvie Dependency」,即非主鍵欄位不應依賴於其他非主鍵欄位,每個欄位都要跟主鍵有「直接」關係。
要求:
下圖中,班級名稱和學生ID完全沒有關係,班級名稱是依賴在班級ID上,這就出現Transitvie Dependency 傳遞依賴,我的理解是「間接相關」。
解法:
正規化的壞處是找資料需要連結多個表格,查找效率低弱。於是誕生
例如:訂單表和商品價格表以正規化分開如下
如果我們需要查詢訂單的總金額(數量 × 商品價格)需要用JOIN
把兩個表合起來,如果是上千萬筆的電商資料可能就會使查詢效率變慢。
SELECT
o.訂單ID,
o.客戶ID,
o.購買數量 * p.商品價格 AS 總金額
FROM
Orders o
JOIN
Products p
ON
o.商品ID = p.商品ID;
所以這時候使用反正規化的作法,可以將程式碼節省成
SELECT 訂單ID, 客戶ID, 總金額 FROM Orders WHERE 訂單日期 = '2024-11-25';
正規化的優點:
反正規化適用於: