A3.3 資料庫程式設計 SQL
SQL(Structured Query Language,結構化查詢語言)是查詢與操作關聯式資料庫的標準語言。本頁用一個學校資料庫範例,依序說明查詢、篩選、排序、聚合、多表 JOIN,以及新增、修改、刪除資料與建立資料表的指令。
範例資料庫
Student(studentID, name, grade, house)
Course(courseID, title, level) -- level 為 'SL' 或 'HL'
Enrollment(studentID, courseID, score)
如何查詢資料?
SELECT 指定欄位,FROM 指定資料表,WHERE 篩選列,ORDER BY 排序:
常用篩選條件:
| 語法 | 意義 | 例子 |
|---|---|---|
=, <>, >, <= |
比較 | score >= 6 |
AND, OR, NOT |
邏輯組合 | grade = 11 OR grade = 12 |
BETWEEN a AND b |
範圍(含兩端) | score BETWEEN 4 AND 6 |
IN (...) |
屬於清單之一 | house IN ('Red', 'Blue') |
LIKE |
模式比對,% 代表任意字串、_ 代表一個字元 |
name LIKE 'A%' |
IS NULL |
欄位為空 | score IS NULL |
如何做統計?
聚合函式(aggregate function)把多列計算成一個值:COUNT、SUM、AVG、MIN、MAX。GROUP BY 分組計算,HAVING 篩選分組後的結果:
-- 每門課的平均分數,只列出平均大於 5 的課
SELECT courseID, AVG(score) AS avgScore, COUNT(*) AS students
FROM Enrollment
GROUP BY courseID
HAVING AVG(score) > 5
ORDER BY avgScore DESC;
WHERE 與 HAVING 的差別
WHERE 在分組 之前 篩選個別列;HAVING 在分組 之後 篩選群組,所以聚合函式條件只能寫在 HAVING。
如何查詢多張資料表?
JOIN 依外鍵把多張表合併。INNER JOIN 只保留兩邊都有對應的列:
-- 列出所有修 HL 課程學生的姓名、課名與分數
SELECT s.name, c.title, e.score
FROM Student s
INNER JOIN Enrollment e ON s.studentID = e.studentID
INNER JOIN Course c ON e.courseID = c.courseID
WHERE c.level = 'HL'
ORDER BY e.score DESC;
LEFT JOIN 保留左表所有列,右表沒有對應時填 NULL,可用來找「沒有修任何課的學生」:
SELECT s.name
FROM Student s
LEFT JOIN Enrollment e ON s.studentID = e.studentID
WHERE e.courseID IS NULL;
如何新增、修改與刪除資料?
INSERT INTO Student (studentID, name, grade, house)
VALUES (101, 'Chris', 11, 'Blue');
UPDATE Enrollment
SET score = 7
WHERE studentID = 101 AND courseID = 'CS-HL';
DELETE FROM Enrollment
WHERE studentID = 101;
UPDATE 與 DELETE 一定要寫 WHERE
少了 WHERE,UPDATE 會修改整張表的每一列,DELETE 會刪除整張表的所有資料。
如何建立資料表?
資料定義語言(Data Definition Language, DDL)用來建立與修改結構;上面的查詢與修改屬於資料操作語言(Data Manipulation Language, DML)。
CREATE TABLE Enrollment (
studentID INTEGER NOT NULL,
courseID VARCHAR(10) NOT NULL,
score INTEGER CHECK (score BETWEEN 1 AND 7),
PRIMARY KEY (studentID, courseID),
FOREIGN KEY (studentID) REFERENCES Student(studentID),
FOREIGN KEY (courseID) REFERENCES Course(courseID)
);
什麼是檢視表?
檢視表(view)是存起來的查詢,使用起來像一張虛擬資料表,可以簡化常用查詢,並只讓使用者看到部分欄位(例如不讓助教看到學生電話)。
CREATE VIEW HLStudents AS
SELECT s.studentID, s.name, c.title
FROM Student s
JOIN Enrollment e ON s.studentID = e.studentID
JOIN Course c ON e.courseID = c.courseID
WHERE c.level = 'HL';
如何在程式中執行 SQL?
IA 與實際應用中,常用程式語言連接資料庫。以 Python 內建的 sqlite3 為例,一定要用參數化查詢(? 佔位符),避免 SQL 注入:
import sqlite3
conn = sqlite3.connect("school.db")
cur = conn.cursor()
name = input("學生姓名:")
cur.execute("SELECT studentID, grade FROM Student WHERE name = ?", (name,))
for student_id, grade in cur.fetchall():
print(student_id, grade)
conn.close()
推薦影音
SQL 入門完整課程(Programming with Mosh)
簡述:Mosh 以實際資料庫示範 SELECT、WHERE、JOIN、GROUP BY、子查詢等指令,節奏清楚,可以邊看邊在 SQLite 或 MySQL 上練習。
SQL 完整資料庫課程(freeCodeCamp)
簡述:freeCodeCamp 的長篇課程,從資料庫概念、建表、查詢一路講到 ER 圖設計,適合想系統化學習或準備 IA 的學生。
練習題
以下題目都使用本頁的範例資料庫。
練習 2:聚合
計算每個 house 的學生人數,只顯示人數超過 20 人的 house。
練習 3:JOIN
列出修讀課名為 Computer Science 的所有學生姓名與分數,分數高的排前面。
練習 4:修改資料
學生 205 從 Green house 換到 Yellow house,寫出 SQL。
練習 5:找出錯誤
下列查詢有什麼問題?SELECT courseID, AVG(score) FROM Enrollment WHERE AVG(score) > 5 GROUP BY courseID;
參考答案
聚合函式不能用在 WHERE,因為 WHERE 在分組前執行。應改為 GROUP BY courseID HAVING AVG(score) > 5。