經典的「學生-課程-成績」三表結構是 SQL 入門與面試的標準練習場景。本文提供完整建表腳本、測試資料,並針對 10 題涵蓋聚合、子查詢、條件邏輯、日期處理、字串格式化、DML 操作的經典題目,給出標準解法與進階優化寫法。
-- 建立資料表
CREATE TABLE Student (
Sno CHAR(10) PRIMARY KEY, -- 學號
Sname NVARCHAR(20) NOT NULL, -- 姓名
Bdate DATE, -- 出生日期
Grade INT -- 年級/班級
);
CREATE TABLE Course (
Cno CHAR(4) PRIMARY KEY, -- 課程號
Cname NVARCHAR(20) NOT NULL -- 課程名稱
);
CREATE TABLE Score (
Sno CHAR(10) NOT NULL,
Cno CHAR(4) NOT NULL,
Score DECIMAL(5,2), -- 成績,NULL 表未修/缺考
PRIMARY KEY (Sno, Cno),
FOREIGN KEY (Sno) REFERENCES Student(Sno),
FOREIGN KEY (Cno) REFERENCES Course(Cno)
);
-- 測試資料
INSERT INTO Student VALUES
('S001', N'張三', '2000-01-15', 2007),
('S002', N'李四', '2000-05-22', 2007),
('S003', N'王五', '2001-03-10', 2008),
('S004', N'趙六', '2000-11-30', 2007);
INSERT INTO Course VALUES
('C001', N'數學'), ('C002', N'英文'), ('C003', N'大學語文');
INSERT INTO Score VALUES
('S001', 'C001', 85), ('S001', 'C002', 92), ('S001', 'C003', 78),
('S002', 'C001', 70), ('S002', 'C002', 65), ('S002', 'C003', 55),
('S003', 'C001', 95), ('S003', 'C002', 88), -- 缺考 C003
('S004', 'C001', 60), ('S004', 'C002', NULL), ('S004', 'C003', 70);
SELECT Grade, COUNT(*) AS StudentCount
FROM Student
GROUP BY Grade
ORDER BY Grade;
-- 解法 1: 相關子查詢
SELECT S.Sname,
ISNULL((SELECT AVG(ISNULL(Score, 0)) FROM Score WHERE Sno = S.Sno), 0) AS AvgScore
FROM Student S
WHERE S.Grade = 2007;
-- 解法 2: LEFT JOIN + 聚合 (效能較佳)
SELECT S.Sname, AVG(ISNULL(SC.Score, 0)) AS AvgScore
FROM Student S
LEFT JOIN Score SC ON S.Sno = SC.Sno
WHERE S.Grade = 2007
GROUP BY S.Sname;
SELECT
C.Cno, C.Cname,
ROUND(AVG(ISNULL(SC.Score, 0)), 2) AS AvgScore,
MAX(ISNULL(SC.Score, 0)) AS MaxScore,
MIN(ISNULL(SC.Score, 0)) AS MinScore
FROM Student S
JOIN Score SC ON S.Sno = SC.Sno
JOIN Course C ON SC.Cno = C.Cno
WHERE S.Grade = 2007
GROUP BY C.Cno, C.Cname;
UPDATE SC
SET Score = ISNULL(Score, 0) + 5
FROM Score SC
JOIN Student S ON SC.Sno = S.Sno
JOIN Course C ON SC.Cno = C.Cno
WHERE S.Grade = 2007 AND C.Cname = N'數學';
SELECT
S.Sno, S.Sname,
AVG(ISNULL(SC.Score, 0)) AS AvgScore,
CASE
WHEN AVG(ISNULL(SC.Score, 0)) >= 90 THEN N'優秀'
WHEN AVG(ISNULL(SC.Score, 0)) >= 60 THEN N'及格'
ELSE N'不及格'
END AS GradeLevel
FROM Student S
LEFT JOIN Score SC ON S.Sno = SC.Sno
GROUP BY S.Sno, S.Sname
ORDER BY AvgScore DESC;
SELECT
MONTH(Bdate) AS BirthMonth,
COUNT(*) AS StudentCount
FROM Student
WHERE Bdate IS NOT NULL
GROUP BY MONTH(Bdate)
ORDER BY BirthMonth;
SELECT
C.Cno, C.Cname,
ROUND(AVG(ISNULL(SC.Score, 0)), 2) AS AvgScore,
COUNT(SC.Score) AS ExamCount, -- 實際參考人數
ROUND(
SUM(CASE WHEN ISNULL(SC.Score, 0) >= 60 THEN 1.0 ELSE 0 END)
* 100.0 / COUNT(SC.Score), 2
) AS PassRatePercent
FROM Course C
LEFT JOIN Score SC ON C.Cno = SC.Cno
GROUP BY C.Cno, C.Cname;
DELETE FROM Score
WHERE Sno = (SELECT Sno FROM Student WHERE Sname = N'張三')
AND Cno = (SELECT Cno FROM Course WHERE Cname = N'大學語文');
UPDATE Course
SET Cname = N'高等數學'
WHERE Cname LIKE N'%數學%';
-- 查詢格式化
SELECT
N'S' + RIGHT(REPLICATE('0', 11) + Sno, 11) AS FormattedSno
FROM Student;
-- 更新資料 (謹慎!需確認無外鍵或已級聯)
UPDATE Student SET Sno = N'S' + RIGHT(REPLICATE('0', 11) + Sno, 11);
UPDATE Score SET Sno = N'S' + RIGHT(REPLICATE('0', 11) + Sno, 11);
SELECT A.TeamName AS Home, B.TeamName AS Away
FROM Team A
JOIN Team B ON A.TeamName < B.TeamName; -- 避免重複與自我對戰
BEGIN TRANSACTION;
UPDATE Score SET Score = 100 WHERE Sno = 'S001' AND Cno = 'C001';
-- 驗證
SELECT * FROM Score WHERE Sno = 'S001';
-- COMMIT TRANSACTION; -- 確認無誤提交
-- ROLLBACK TRANSACTION; -- 有誤回滾
| 主題 | 核心函數/語法 | 注意事項 |
|---|---|---|
| 空值處理 | ISNULL, COALESCE, NULLIF | 聚合函數自動忽略 NULL,需 ISNULL(Score,0) 參與運算 |
| 條件邏輯 | CASE WHEN ... THEN ... ELSE ... END | 可嵌套,搜尋型 vs 簡單型 |
| 日期處理 | MONTH, YEAR, DAY, DATEPART, FORMAT | SQL Server 無 TO_CHAR,用 CONVERT/FORMAT |
| 字串格式化 | REPLICATE, RIGHT, CONCAT, FORMAT | 補零常用 RIGHT('000'+col, len) |
| 相關子查詢 vs JOIN | 子查詢直觀,JOIN 效能通常更好 | 大量資料優先 JOIN + 聚合 |
| DML 操作 | UPDATE ... FROM JOIN, DELETE ... FROM JOIN | SQL Server 支援 JOIN 語法,比子查詢高效 |
| 功能 | SQL Server | MySQL | PostgreSQL | Oracle |
|---|---|---|---|---|
| 空值轉零 | ISNULL(col,0) | IFNULL(col,0) | COALESCE(col,0) | NVL(col,0) |
| 字串連接 | + 或 CONCAT | CONCAT 或 || | || | || |
| 日期格式化 | CONVERT/FORMAT | DATE_FORMAT | TO_CHAR | TO_CHAR |
| 取月份 | MONTH(date) | MONTH(date) | EXTRACT(MONTH FROM date) | EXTRACT(MONTH FROM date) |
| 四捨五入 | ROUND(val,2) | ROUND(val,2) | ROUND(val,2) | ROUND(val,2) |
掌握此 Schema 的核心查詢模式 (多表 JOIN、聚合分組、條件邏輯、空值處理、子查詢、DML),即能應對 80% 以上的業務報表與面試題目。建議在實際資料庫建立此結構親自執行驗證,體會執行計畫與結果差異。