Table of Contents

今天我們就來動手寫點 SQL,好嗎?

過去帶課時,我發現學生在學完 SQL 的概念後,如果能夠立刻練習對理解的效果是最佳的。於是我選了幾種生活中常用的、會利用到資料庫的一些情境來做為練習的主題,像是查詢員工工時、計算薪水、追專案進度等等都是在辦公室裡很容易出現的日常情境。

題目分為三個難度等級,不勉強一定要全部一口氣做完,如果遇到不會的,可以分成好幾天甚至好幾個禮拜慢慢想、慢慢寫出來,才能真正內化成自己的能力喔,準備好了嗎?打開編輯器,從第一題開始,試著讓資料庫乖乖回應你的每一道指令吧!

建立好練習環境

將下面練習用的資料表,貼進自己習慣的環境裡練習。或是如果只是想要簡單在線上練習,也可以直接用我在 SQL Fiddle 建立好的練習範例 (這裡我使用的是 SQLite):https://sqlfiddle.com/sqlite/online-compiler?id=109bad62-11f6-4ba0-8332-26c2c56fbe56

建立資料表

首先我們需要先虛構一組簡單的辦公室員工資料表,包含部門、員工、專案、每個員工在專案上的工時、以及酬勞等等

/* 部門 */
CREATE TABLE department (
dept_id  TEXT PRIMARY KEY,
dname    TEXT
);


/* 員工 */
CREATE TABLE employee (
eno       TEXT PRIMARY KEY,
ename     TEXT,
gender    TEXT,
age       INTEGER,
dept_id   TEXT,
hire_date TEXT,         -- yyyy-mm-dd
FOREIGN KEY (dept_id) REFERENCES department(dept_id)
);


/* 專案 */
CREATE TABLE project (
pno     TEXT PRIMARY KEY,
pname   TEXT,
dept_id TEXT,
budget  REAL,
FOREIGN KEY (dept_id) REFERENCES department(dept_id)
);


/* 員工專案工時 */
CREATE TABLE assignment (
eno   TEXT,
pno   TEXT,
hours INTEGER,
PRIMARY KEY (eno, pno),
FOREIGN KEY (eno) REFERENCES employee(eno),
FOREIGN KEY (pno) REFERENCES project(pno)
);


/* 薪資(月薪) */
CREATE TABLE salary (
eno   TEXT,
month TEXT,       -- yyyy-mm
amount REAL,
PRIMARY KEY (eno, month),
FOREIGN KEY (eno) REFERENCES employee(eno)
);

插入範例資料

接著,在每張表裡面填入一些虛構的練習用資料

/* department */
INSERT INTO department VALUES
('d001','Research'),('d002','Marketing'),
('d003','HR'),('d004','Finance');


/* employee */
INSERT INTO employee VALUES
('e001','Alice'  ,'F',29,'d001','2019-03-15'),
('e002','Bob'    ,'M',35,'d002','2017-07-20'),
('e003','Charlie','M',28,'d002','2021-01-05'),
('e004','Diana'  ,'F',42,'d001','2010-11-11'),
('e005','Evan'   ,'M',31,'d003','2018-04-23'),
('e006','Fiona'  ,'F',26,'d004','2022-06-01'),
('e007','George' ,'M',39,'d004','2015-09-09'),
('e008','Helen'  ,'F',45,'d003','2008-12-30'),
('e009','Ivan'   ,'M',27,'d001','2020-08-18'),
('e010','Julia'  ,'F',33,'d002','2016-02-14'),
('e011','Kevin'  ,'M',30,'d003','2019-10-10'),
('e012','Laura'  ,'F',24,'d001','2023-01-10');


/* project */
INSERT INTO project VALUES
('p001','AI Engine'      ,'d001',200000),
('p002','Ad Campaign'    ,'d002',150000),
('p003','Benefit Overhaul','d003', 80000),
('p004','ERP Migration'  ,'d004',120000),
('p005','Mobile App'     ,'d001',180000),
('p006','Market Research','d002', 60000);


/* assignment */
INSERT INTO assignment VALUES
('e001','p001',320),('e001','p005',120),
('e002','p002',400),('e002','p006', 80),
('e003','p002',200),('e003','p006',150),
('e004','p001',250),('e004','p004', 60),
('e005','p003',180),
('e006','p004',210),('e007','p004',130),
('e008','p003',200),
('e009','p001',150),
('e010','p002',300),
('e011','p003',120),
('e012','p005', 60);


/* salary (2025-01) */
INSERT INTO salary VALUES
('e001','2025-01',7000), ('e002','2025-01',7500),
('e003','2025-01',5200), ('e004','2025-01',9000),
('e005','2025-01',6200), ('e006','2025-01',4800),
('e007','2025-01',8800), ('e008','2025-01',9500),
('e009','2025-01',5100), ('e010','2025-01',7000),
('e011','2025-01',6000), ('e012','2025-01',4500);

練習題 (共30題)

這裡我分成三種難度,每種難度都有 10 小題

基礎難度

  1. 列出 employee 表當中的前 5 筆資料
  2. 查詢 department 的所有部門名稱
  3. 查詢年齡 > 30 的員工姓名有哪些、以及他們的年齡
  4. 查詢 assignment 中,p001 專案的員工編號以及花費的工時
  5. 統計性別為 'F' 的員工人數
  6. 使用 LIKE 找出員工姓名以 'A' 開頭的員工編號與姓名
  7. 查詢 2025-01 月的平均薪資
  8. 列出屬於 Marketing (d002) 部門的全部員工姓名與聘用日期,並且依日期由舊到新排序
  9. 查詢 budget > 100000 的專案編號與名稱
  10. 列出 assignment 中 hours > 300 的紀錄,並依照工時由高至低排序

中等難度

  1. 計算各個部門所屬員工的平均年齡
  2. 查詢每個專案的總花費工時
  3. 查出員工 e002 參與的專案數量有幾個
  4. 找出 budget 最高的專案名稱及其部門名稱
  5. 列出還沒有被指派任何員工的專案編號、以及專案名稱
  6. 找出參與兩個以上專案的員工編號、姓名,以及負責專案數量
  7. 查詢薪資高於公司平均的員工編號、姓名與薪資
  8. 列出每個部門的員工總數,並依人數由多到少排序
  9. 將每位員工參與的專案名稱用逗號串聯之後顯示出來 (可用 GROUP_CONCAT)
  10. 找出最早聘用的三位員工姓名及聘用日期

進階難度

  1. 找出同時參與 p001 與 p005 這兩個專案的員工編號與姓名
  2. 找出沒有參與任何 Research 部門專案的員工姓名
  3. 使用視窗函數 (Window function) 找出各部門當中薪資最高的員工,以及他的薪資
  4. 列出工時高於部門平均工時的員工編號、姓名與工時
  5. 以 2025-01-01 為基準,計算每位員工距離入職滿 5 年還差多少天
  6. 使用 CTE 計算各專案中員工工時的百分比,列出員工編號、專案編號、百分比,並依百分比降序來排序
  7. 查詢所有部門平均薪資與公司平均薪資的差額 (可以是負值)
  8. 找出與員工 e001 一起參與過至少 1 個專案的其他員工姓名,並顯示共同專案數量
  9. 查詢 assignment 中,每位員工最新一次參與的專案 (依插入順序視為最新),並只顯示出員工編號、專案編號、工時
  10. 建立一個名為 high_budget_project 的View,包含所有 budget > 公司專案平均的專案,再查詢這個view當中的專案總數