你有沒有想過,SELECT 這個關鍵字到底在做什麼?
很多人會說「查詢資料」,但這個說法不夠精確。
SELECT 真正在做的事情是「輸出」——把資料呈現出來。
理解這個觀念之後,你會發現 SELECT 其實可以單獨執行,不一定要搭配 FROM 和 WHERE。
SELECT 的基本用法
大部分教學一開始就教你 SELECT、FROM、WHERE 三個關鍵字一起用。
所以很多人會以為:SELECT 一定要搭配 FROM 才能執行。
其實不是。
回顧一下上一篇講的執行計畫:
| 順序 | 子句 | 做的事情 |
|---|---|---|
| 1 | FROM | 決定從哪張表單拿資料(輸入) |
| 2 | WHERE | 篩選出符合條件的資料(轉換) |
| 3 | SELECT | 挑出要呈現的欄位、做計算(輸出) |
FROM 負責「輸入」,WHERE 負責「轉換」,SELECT 負責「輸出」。
那如果今天你不需要從表單拿資料,只是想輸出一個值呢?
這時候就不需要 FROM 和 WHERE,只要 SELECT 就夠了。
舉個例子:
SELECT 'Hello World'這行指令執行後,資料庫會輸出 Hello World 這個字串。
沒有 FROM,沒有 WHERE,只有 SELECT,一樣可以執行。
這裡用單引號包住字串,是因為在很多資料庫系統中,雙引號是保留給表單或欄位名稱用的。
所以字串要用單引號。
SELECT 可以做運算
SELECT 不只能輸出固定的字串,還可以做各種運算。
數學運算
SELECT 2 + 3結果是 5。
資料庫會先計算 2 + 3,然後把結果輸出。
你可以用 +、-、*、/ 做加減乘除:
SELECT 10 * 5結果是 50。
字串合併
你也可以把多個字串連接在一起:
SELECT CONCAT('Hello', ' ', 'World')結果是 Hello World。
CONCAT 是一個函式,它會把括號裡面的字串按順序連接起來。
型別轉換
有時候你需要把一種資料型別轉換成另一種,可以用 CAST:
SELECT CAST('2024-01-01' AS DATE)這會把字串 '2024-01-01' 轉換成日期型別。
轉換之後,你就可以對它做日期運算:
SELECT CAST('2024-01-01' AS DATE) - INTERVAL 7 DAY結果是 2023-12-25,也就是往前推 7 天。
SELECT 的運算結果也是輸出
不管是數學運算、字串合併、還是型別轉換,SELECT 做的事情都一樣:把運算結果輸出。
這些運算結果可以直接呈現給使用者,也可以放進 WHERE 條件中使用,或是當成子查詢的一部分。
SELECT 輸出的是「表格」,不是純文字
SELECT 的本質是輸出,但要注意:它輸出的是一張表格,不是純文字。
SELECT 輸出的表格結構
舉個例子:
SELECT 2 + 3你可能以為結果是這樣:
5但其實不是。
資料庫輸出的是一張表格:
| 2 + 3 |
|---|
| 5 |
第一列 2 + 3 是欄位名稱,第二列 5 是欄位值。
有沒有發現?欄位名稱就是你寫的運算式 2 + 3。
這樣的欄位名稱非常醜,而且之後很難引用。
用 AS 幫 SELECT 結果取別名
既然 SELECT 輸出的是表格,那表格的欄位就應該有一個好懂的名稱。
用 AS 可以幫欄位取別名:
SELECT 2 + 3 AS 計算結果輸出的表格變成:
| 計算結果 |
|---|
| 5 |
這樣清楚多了。
取別名有幾個好處:
- 自己看得懂:三個月後回來看程式碼,你還知道這是什麼
- 別人看得懂:寫程式是團隊合作,別人也要能理解你的程式碼
- 後續引用方便:如果要把這個結果放進子查詢,有名字才能指定它
第三點特別重要。
因為 SELECT 輸出的是表格,這張表格可以當成另一個 SELECT 的輸入。
如果欄位沒有名字,後面的 SELECT 要怎麼指定它?
這就是為什麼我們強烈建議:給輸出結果一個好懂的別名。
子查詢實戰:找出名字有「志」又有「明」的人
假設老闆說:「請你找出名字裡面有『志』又有『明』的人。」
你會怎麼做?
先找出名字有「志」的人
SELECT *
FROM 會員
WHERE CONTAINS(名字, '志')這個 SELECT 會從會員表單中,篩選出名字包含「志」的人。
從這群人中,再找出名字有「明」的人
現在我們要從「含志會員」這群人中,再篩選出「名字有明的人」。
怎麼做呢?
把第一步的結果當成一張臨時表單,放進 FROM 裡面:
SELECT *
FROM (
SELECT *
FROM 會員
WHERE CONTAINS(名字, '志')
) AS 含志會員
WHERE CONTAINS(含志會員.名字, '明')這裡有幾個重點:
1. 用圓括號包住子查詢
為什麼要用圓括號?
因為 FROM 後面通常是接一張表單的名稱,像是 FROM 會員。
但這裡我們要放的不是表單名稱,而是另一個 SELECT 的結果。
用圓括號把 SELECT 包起來,告訴資料庫:「這整段是一個查詢,它的結果要當成一張表單來用」。
2. 一定要給子查詢取別名
把子查詢放進 FROM 的時候,必須給它一個別名。
為什麼?
因為如果不取別名,資料庫搞不清楚你指的是哪張表單的欄位。
這裡取名叫 含志會員,後面就可以用 含志會員.名字 來指定欄位。
這裡的 . 是「的」的意思,含志會員.名字 就是「含志會員這張表單的名字欄位」。
怎麼閱讀複雜的子查詢?
當子查詢變多、結構變複雜時,你可能會看不懂整個查詢在做什麼。
這時候有個技巧:先看外層,再看內層。
拿剛才的例子來說:
SELECT *
FROM (
SELECT *
FROM 會員
WHERE CONTAINS(名字, '志')
) AS 含志會員
WHERE CONTAINS(含志會員.名字, '明')先把子查詢遮起來,看外層結構
SELECT *
FROM (...) AS 含志會員
WHERE CONTAINS(含志會員.名字, '明')外層在做什麼?從「某張表單」中,篩選出名字有「明」的人。
再看子查詢在做什麼
SELECT *
FROM 會員
WHERE CONTAINS(名字, '志')子查詢在做什麼?從會員表單中,篩選出名字有「志」的人。
這樣分層來看,結構就清楚了。
子查詢裡面還可以有子查詢,形成多層結構。
當查詢變複雜時,記住這個閱讀技巧:
- 先把子查詢遮起來,當成一張表單
- 看懂外層結構後,再進去看子查詢在做什麼
- 一層一層拆解,就不會迷失在複雜的結構中
之後我們還會教一個更進階的技巧:用 CTE(Common Table Expression)把子查詢提出去,讓整個結構更清楚。
小結
這篇文章介紹了 SELECT 的基本用法與子查詢:
- SELECT 可以輸出字串、做運算:這是學 SQL 的第一步
- 輸出結果要取別名:讓自己和別人都看得懂
- 子查詢是把 SELECT 結果當成臨時表單:放進 FROM 裡面再次使用
- 子查詢一定要取別名:放進 FROM 時,資料庫強制要求
- 閱讀複雜查詢的技巧:先看外層,再看內層,一層一層拆解
掌握子查詢的概念後,你就能把複雜的問題拆成多個步驟,一步一步處理。