SQL 練習工具

在瀏覽器中運作的資料庫(SQLite)已備有員工、部門、銷售的練習用資料表。寫好 SQL 並執行,結果會立即以表格顯示。可透過 10 道會自動對答案的練習題,練習 SELECT 與 WHERE、ORDER BY、GROUP BY 與 HAVING、內部合併與外部合併、子查詢等。

練習題

結果

練習用資料表

資料庫只在本頁中運作,輸入的 SQL 與資料不會傳送到任何地方。即使用 INSERT 或 UPDATE 改寫了資料表,按「還原資料表」或重新整理頁面即可恢復初始狀態。對答案時,沒有 ORDER BY 的題目不考慮資料列的順序。

練習用資料表

員工表有員工編號、姓名、部門編號、薪資、到職年,部門表有部門編號、部門名稱、所在地,銷售表有銷售編號、員工編號、月份、金額。員工表的部門編號是參照部門表部門編號的外鍵。資料中刻意放入沒有所屬部門的員工(部門編號為 NULL)、薪資為 NULL 的員工,以及沒有員工的部門,可以確認合併與彙總時 NULL 如何處理。隨時可在畫面下方的「練習用資料表」查看各表的內容。

SELECT 的基本:選擇欄位、篩選、排序

在 SELECT 後寫要取出的欄位、FROM 後寫資料表、WHERE 後寫資料列的條件。SELECT 姓名, 薪資 FROM 員工 WHERE 薪資 >= 300000 ORDER BY 薪資 DESC; 會依薪資由高到低列出薪資在 300000 以上的員工。NULL 表示「沒有值」,要用 IS NULL 或 IS NOT NULL 而非 = NULL 判斷。請注意,薪資為 NULL 的員工既不符合 薪資 >= 300000,也不符合 薪資 < 300000。

彙總:GROUP BY 與 HAVING

COUNT、SUM、AVG、MAX、MIN 等彙總函數,會對 GROUP BY 分出的每個群組傳回一個值。WHERE 在分組前篩選資料列,HAVING 則在分組後篩選彙總結果。COUNT(*) 計算資料列數,COUNT(欄位) 計算非 NULL 值的個數,AVG(薪資) 會排除薪資為 NULL 的資料列再求平均。請確認練習題 5 的答案是 7 人而非 8 人的平均。

合併:內部合併與外部合併

INNER JOIN(內部合併)只傳回符合 ON 條件的組合,因此沒有所屬部門的員工與沒有員工的部門不會出現在結果中。LEFT OUTER JOIN(左外部合併)會保留左表的所有資料列,右表沒有對應資料列時,右表的欄位為 NULL。以部門表為左表外部合併員工表,並用 COUNT(員工.員工編號) 計數,就能把沒有員工的部門顯示為 0 人。若用 COUNT(*),會把填入 NULL 的資料列也算成 1 列,因此不會是 0。

子查詢:IN 與 EXISTS

在 WHERE 中寫入另一個 SELECT(子查詢),就能把其結果當作條件使用。IN 檢查值是否包含在子查詢傳回的清單中,EXISTS 檢查子查詢是否至少傳回 1 列。使用 NOT EXISTS 可以找出像「完全沒有銷售紀錄的員工」這種沒有對應資料列的資料。在子查詢中使用外部資料列之值的稱為相關子查詢,可以想成對外部的每一列各評估一次子查詢。

練習資料庫題目

商品表格中有(商品名稱, 價格)為(筆, 120)、(筆記本, 250)、(橡皮擦, 80)、(資料夾, 300)、(尺, 150)的5筆資料列。依序列出 SELECT 商品名稱 FROM 商品 WHERE 價格 >= 150 ORDER BY 價格 DESC 所傳回之資料列的是下列何者?

  1. A尺、筆記本、資料夾
  2. B資料夾、筆記本
  3. C資料夾、筆記本、尺
查看答案與解析

正確答案:C. 資料夾、筆記本、尺

WHERE 價格 >= 150 只選出價格在150以上的資料列。恰好150的尺也包含在內,因此選出的是筆記本(250)、資料夾(300)、尺(150)這3筆。接著 ORDER BY 價格 DESC 依價格由高到低(遞減)排序,結果依序為資料夾(300)、筆記本(250)、尺(150)。ORDER BY 指定ASC或不指定時,會由低到高(遞增)排序。若不加ORDER BY,結果資料列的順序不受保證。SELECT之後寫要取出的欄位(此處為商品名稱),FROM之後寫表格,WHERE之後寫選取資料列的條件。

員工表格的部門欄位中,由上而下依序為 業務、研發、業務、總務、研發、業務(共6筆)。SELECT DISTINCT 部門 FROM 員工 的結果有幾筆資料列?

  1. A2筆
  2. B3筆
  3. C6筆
查看答案與解析

正確答案:B. 3筆

DISTINCT會從結果中去除重複的資料列,把相同的值合併成一筆。部門的值有業務、研發、總務3種,因此結果為3筆。若不加DISTINCT而執行 SELECT 部門 FROM 員工,會連同重複的值原樣傳回6筆。2筆是只計算出現2次以上之部門(業務與研發)時的數目,相當於 SELECT 部門 FROM 員工 GROUP BY 部門 HAVING COUNT(*) >= 2 這類查詢的結果。

成績表格的分數欄位中有 50、NULL、70、NULL、90、30 共6個值。依序列出 SELECT COUNT(*), COUNT(分數), AVG(分數) FROM 成績 之結果的是下列何者?

  1. A6, 6, 40
  2. B6, 4, 40
  3. C6, 4, 60
查看答案與解析

正確答案:C. 6, 4, 60

COUNT(*)不論是否含NULL都會計算資料列數,因此為6。像COUNT(分數)這樣指定欄位時,只計算該欄位不是NULL的資料列,因此為4。AVG(分數)是把4個非NULL值的總和 50 + 70 + 90 + 30 = 240,除以非NULL值的個數4,得到 240 ÷ 4 = 60。要注意這與總和除以全部資料列數的 SUM(分數) / COUNT(*) = 240 ÷ 6 = 40 不同。若想把NULL當作0分,要先以 COALESCE(分數, 0) 替換再彙總。

銷售表格(門市, 金額)中有(A, 500)、(A, 700)、(B, 300)、(B, 400)、(C, 1200)、(D, 200)、(D, 900)共7筆資料列。SELECT 門市, SUM(金額) FROM 銷售 GROUP BY 門市 HAVING SUM(金額) >= 1000 的結果有幾筆資料列?

  1. A1筆
  2. B3筆
  3. C4筆
查看答案與解析

正確答案:B. 3筆

以 GROUP BY 門市 依門市分組後,合計分別為A:500 + 700 = 1200、B:300 + 400 = 700、C:1200、D:200 + 900 = 1100,共4個群組。HAVING SUM(金額) >= 1000 只保留合計在1000以上的群組,因此結果為A、C、D共3筆。1筆是像 WHERE 金額 >= 1000 這樣,在分組前以每筆資料列的金額篩選時的結果(只有C)。4筆是不加HAVING時的群組數。

員工表格(員工編號, 姓名, 部門編號)有4筆資料列,部門編號依序為10、20、10、NULL。部門表格(部門編號, 部門名稱)有部門編號為10、20、30的3筆資料列。SELECT 員工.姓名, 部門.部門名稱 FROM 員工 INNER JOIN 部門 ON 員工.部門編號 = 部門.部門編號 的結果有幾筆資料列?

  1. A3筆
  2. B4筆
  3. C12筆
查看答案與解析

正確答案:A. 3筆

INNER JOIN(內部連結)只把滿足ON條件的資料列組合作為結果。部門編號為10的2位員工與部門10的資料列組合,部門編號為20的1位員工與部門20的資料列組合,因此結果為3筆。部門編號為NULL的員工,因為與NULL的比較不會為真,不會與任何部門連結而從結果中消失。沒有員工的部門30也不會出現在結果中。4筆是保留員工表格所有資料列的左外部連結(員工 LEFT OUTER JOIN 部門)時的筆數。12筆是不加條件、產生所有組合的CROSS JOIN(笛卡兒積),即 4 × 3 = 12 筆。

員工表格(員工編號, 姓名, 部門編號)有5筆資料列,部門編號依序為10、20、10、NULL、NULL。部門表格(部門編號, 部門名稱)有部門編號為10、20、30的3筆資料列。SELECT 部門.部門名稱, 員工.姓名 FROM 部門 LEFT OUTER JOIN 員工 ON 部門.部門編號 = 員工.部門編號 的結果有幾筆資料列?

  1. A3筆
  2. B4筆
  3. C5筆
查看答案與解析

正確答案:B. 4筆

LEFT OUTER JOIN(左外部連結)會保留左側表格(此處為部門表格)的所有資料列,若右側表格沒有相符的資料列,就以NULL填入右側欄位,成為一筆資料列。部門10有2位員工而成為2筆,部門20為1筆,沒有員工的部門30成為姓名為NULL的1筆,合計4筆。部門編號為NULL的2位員工不與任何部門相符,而且是不會全部保留的右側表格的資料列,因此不會出現在結果中。若是內部連結,部門30的資料列也會消失而成為3筆。若左右對調成 員工 LEFT OUTER JOIN 部門,5位員工會全部保留而成為5筆。使用外部連結時,確認要保留哪個表格的所有資料列很重要。

想從客戶表格(客戶編號, 姓名)與訂單表格(訂單編號, 客戶編號, 金額)中,求出從未下過訂單之客戶的姓名。正確的SQL敘述是下列何者?

  1. ASELECT 姓名 FROM 客戶 WHERE EXISTS (SELECT * FROM 訂單 WHERE 訂單.客戶編號 = 客戶.客戶編號)
  2. BSELECT 姓名 FROM 客戶 WHERE NOT EXISTS (SELECT * FROM 訂單)
  3. CSELECT 姓名 FROM 客戶 WHERE NOT EXISTS (SELECT * FROM 訂單 WHERE 訂單.客戶編號 = 客戶.客戶編號)
查看答案與解析

正確答案:C. SELECT 姓名 FROM 客戶 WHERE NOT EXISTS (SELECT * FROM 訂單 WHERE 訂單.客戶編號 = 客戶.客戶編號)

EXISTS是一種述詞:括號中的子查詢只要傳回一筆以上結果就為真,一筆都沒有就為假;NOT EXISTS則相反。在子查詢中像 訂單.客戶編號 = 客戶.客戶編號 這樣使用外層表格的欄位,就成為相關子查詢,會對外層客戶表格的每筆資料列,檢查該客戶是否有訂單。與NOT EXISTS組合後,只會留下一筆訂單都沒有的客戶。若改用EXISTS,求出的反而是下過訂單的客戶。若子查詢中沒有與客戶對應的條件,只要訂單表格有一筆資料列,子查詢就一定會傳回資料列,NOT EXISTS永遠為假,結果為0筆。以LEFT OUTER JOIN連結後,選出訂單端欄位為NULL的資料列,也能得到相同的結果。

常見問題

需要安裝或註冊嗎?

不需要。本工具使用在瀏覽器中執行 SQLite 的函式庫 sql.js,開啟頁面就能使用。輸入的 SQL 與資料不會傳送到任何地方。

把資料表弄壞了怎麼辦?

按「還原資料表」或重新整理頁面即可恢復初始狀態。對答案每次都會用新的資料庫進行,因此即使改寫了資料表也能正確判定。

對答案是怎麼判定的?

將輸入的 SQL 與參考答案分別在初始狀態的資料庫中執行,比較結果的列數、欄數與值。沒有 ORDER BY 的題目不考慮資料列的順序。欄位名稱與別名不列入判定,因此寫法與參考答案不同,只要結果相同就算正確。

可以使用哪種 SQL 語法?

SQLite 的語法。可以使用 SELECT、INSERT、UPDATE、DELETE、CREATE TABLE、合併、子查詢、彙總函數、CASE 運算式等。不同的資料庫產品在函數名稱與細部語法上可能不同,用於考試或其他產品時請確認其語法。

能用來準備考試嗎?

可以實際執行來確認考試常考的觀念,例如 SELECT、合併、GROUP BY 與 HAVING、子查詢、NULL 的處理。資料表與題目形式與實際考試不同,請搭配歷屆試題一起使用。

相關術語

SQL 關聯式資料庫 主鍵 外鍵 檢視表

相關計算工具

半導體、電子電路與資訊計算工具 →