SELECT 是使用頻率最高、功能最豐富的 SQL 指令。本文按標準子句順序(SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY → LIMIT)系統講解核心用法,並以經典 pet、event 表為例,演示條件過濾、排序、分組聚合、多表聯查、自聯查等實戰技巧。
SELECT select_list -- 選擇列/運算式
FROM table_list -- 來源表(可多表)
WHERE primary_constraint -- 行級過濾條件
GROUP BY grouping_columns -- 分組依據
HAVING secondary_constraint -- 組級過濾條件
ORDER BY sorting_columns -- 結果排序
LIMIT count [OFFSET offset] -- 結果限制
順序固定不可亂;除 SELECT、select_list 外皆可選。MySQL 允許無 FROM 純運算:SELECT (2+3*4.5)/2.5;
-- 全表全欄
SELECT * FROM pet;
-- 條件過濾特定行
SELECT * FROM pet WHERE name = 'Bowser';
-- 投影特定列
SELECT name, birth FROM pet WHERE owner = 'Gwen';
-- 算術運算
SELECT death - birth AS days_lived FROM pet WHERE name='Bowser';
-- 字串/日期函數
SELECT CONCAT(name, '(', species, ')') AS desc FROM pet;
SELECT DATEDIFF(death, birth) FROM pet WHERE death IS NOT NULL;
| 類別 | 運算符 | 範例 |
|---|---|---|
| 算術 | + - * / % | price * 1.05 |
| 比較 | = != <> < <= > >= | birth >= '1998-01-01' |
| 範圍/集合 | BETWEEN ... AND ... / IN (...) / NOT IN | id BETWEEN 1 AND 100 |
| 模糊匹配 | LIKE / NOT LIKE | name LIKE 'B%' |
| 空值判斷 | IS NULL / IS NOT NULL | death IS NULL |
| 邏輯 | AND / OR / NOT | species='dog' AND sex='f' |
| 正則 | REGEXP / RLIKE | name REGEXP '^[A-C]' |
(species = 'cat' AND sex = 'm') OR (species = 'dog' AND sex = 'f')
字串比較預設不區分大小寫(依排序規則),加 BINARY 強制區分。
-- 單欄升序(預設)
SELECT name, birth FROM pet ORDER BY birth;
-- 降序
SELECT name, birth FROM pet ORDER BY birth DESC;
-- 多欄:先按種類升序,同種類內按出生降序
SELECT name, species, birth FROM pet ORDER BY species, birth DESC;
注意:DESC 僅作用於緊前欄位;TEXT/BLOB 不可排序。
COUNT(*) / COUNT(col) — 行數 / 非 NULL 值數SUM(col), AVG(col), MIN(col), MAX(col)GROUP_CONCAT(col SEPARATOR ',') — 組內值串聯 (MySQL 特有)-- 每位主人寵物數
SELECT owner, COUNT(*) FROM pet GROUP BY owner;
-- 每種寵物數量
SELECT species, COUNT(*) FROM pet GROUP BY species;
SELECT species, sex, COUNT(*) FROM pet GROUP BY species, sex;
-- 只顯示擁有 2 隻以上寵物的主人
SELECT owner, COUNT(*) AS cnt FROM pet GROUP BY owner HAVING cnt > 2;
WHERE vs HAVING:WHERE 過濾原始行(聚合前),HAVING 過濾分組結果(聚合後);WHERE 不可用聚合函數,HAVING 可用。
SELECT pet.name, (TO_DAYS(event.date)-TO_DAYS(pet.birth))/365 AS age, event.remark
FROM pet INNER JOIN event ON pet.name = event.name
WHERE event.type = 'litter';
-- 寵物配對:同種類、雌雄配對
SELECT p1.name, p1.sex, p2.name, p2.sex, p1.species
FROM pet AS p1 INNER JOIN pet AS p2
ON p1.species = p2.species AND p1.sex = 'f' AND p2.sex = 'm';
別名 (AS) 消除欄位歧義,提升可讀性。
SELECT owner, pet.name FROM owner LEFT JOIN pet ON owner.id = pet.owner_id;
-- 無寵物主人也會列出,pet.name 為 NULL
-- 前 10 筆
SELECT * FROM pet LIMIT 10;
-- 分頁:第 3 頁,每頁 10 筆
SELECT * FROM pet LIMIT 10 OFFSET 20;
-- 或
SELECT * FROM pet LIMIT 20, 10;
深分頁效能陷阱:LIMIT 1000000, 10 需掃描 100 萬行再丟棄。優化:WHERE id > last_max_id ORDER BY id LIMIT 10 (游標式分頁)。
SELECT * 禁止生產環境用:增加網傳、防覆蓋索引、Schema 變更衝擊。WHERE 盡量用索引欄位,避免函數包裹(WHERE DATE(created_at)=... → WHERE created_at >= ... AND created_at < ...)。OR 連接不同索引欄位常導致全表掃描,改 UNION ALL 或重構。GROUP BY 隱含排序 (MySQL 5.7 前),5.7+ 需顯式 ORDER BY 保證順序。COUNT(*) 極慢,用近似值 EXPLAIN Rows、觸發器維護計數表、或 SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_NAME='t' (MyISAM 精確/InnoDB 估算)。