SELECT 是 SQL 中使用頻率最高、功能最豐富的語句。本文系統梳理 完整語法結構、別名與表達式、DISTINCT 去重、WHERE 條件構建、多表連接、子查詢、排序分頁、分組聚合,並針對易混淆點給出對比示例。
SELECT [ALL | DISTINCT]
{* | table.* | [table.]col1 [AS alias1] [, [table.]col2 [AS alias2]] ...}
FROM table_name
[WHERE condition]
[GROUP BY col_list [HAVING condition]]
[ORDER BY col_list [ASC | DESC]]
[LIMIT [offset,] row_count]
SELECT name, price FROM products; — 顯式列出列,避免 SELECT * 造成網絡/IO 浪費。SELECT name AS book_name, price AS book_price FROM products; — 別名建議加 AS 提升可讀性;別名含空格需單引號 'book name'。SELECT 1+2*3, 8%5; — 純量表達式可直接計算,不依賴表。SELECT name, price, price*0.7 AS 'discount price' FROM products WHERE id <= 15; — 列表達式可混用算術運算。SELECT DISTINCT price FROM products; -- 單列去重
SELECT DISTINCT price, name FROM products; -- 整行去重(price+name 組合唯一)
誤區:DISTINCT col1, col2 作用於 整行組合,而非單獨對 col1 去重。
| 分類 | 操作符/語法 | 示例 |
|---|---|---|
| 邏輯運算 | AND / && | WHERE id>10 AND status=1 |
OR / || | WHERE cat='A' OR cat='B' | |
NOT / ! | WHERE NOT (id>100) | |
| 比較運算 | = | WHERE id=10 |
<=>(NULL 安全等值) | WHERE col <=> NULL 等同 col IS NULL | |
!= / <> | WHERE status!=0 | |
< <= > >= | WHERE price BETWEEN 10 AND 20 | |
| NULL 判斷 | IS NULL / IS NOT NULL | WHERE mobile IS NULL |
ISNULL(expr) | 函數形式,返回 1/0 | |
| 範圍 | BETWEEN ... AND ... | WHERE id BETWEEN 10 AND 20 含邊界 |
NOT BETWEEN ... AND ... | WHERE id NOT BETWEEN 10 AND 20 | |
| 集合 | IN (val1, val2...) | WHERE id IN (5,10,15) |
NOT IN (...) | WHERE id NOT IN (5,10) | |
| 模糊匹配 | LIKE _(單字符) %(任意長度) | WHERE name LIKE '%java%' |
NOT LIKE | WHERE name NOT LIKE '%java%' | |
REGEXP / RLIKE | WHERE name REGEXP '^java'(以 java 開頭) |
SELECT c.name, p.name FROM cats c, products p; -- 無條件:c.rows * p.rows 行,無業務意義
SELECT c.name, p.name, p.price
FROM cats c
JOIN products p ON c.id = p.cid; -- 推薦 ANSI SQL-92 語法
SELECT a.id, a.name, b.id, b.name
FROM cats a
JOIN cats b ON a.pid = b.id; -- 同表不同別名
-- 標量子查詢(返回單值)
SELECT * FROM products WHERE price > (SELECT AVG(price) FROM products);
-- 列子查詢(返回單列多行)
SELECT * FROM products WHERE cid IN (SELECT id FROM cats WHERE name LIKE 'j%');
-- 行子查詢(返回單行多列)
SELECT * FROM t1 WHERE (col1, col2) = (SELECT col1, col2 FROM t2 LIMIT 1);
ORDER BY price DESC; -- 降序
ORDER BY price ASC, id DESC; -- 多鍵排序
LIMIT 10; -- 前 10 行
LIMIT 0, 10; -- 同義
LIMIT 10 OFFSET 20; -- 第 3 頁(每頁 10 行)
SELECT cid,
COUNT(*) AS cnt,
SUM(price) AS total,
AVG(price) AS avg_p,
MAX(price) AS max_p,
MIN(price) AS min_p
FROM products
GROUP BY cid
HAVING AVG(price) > 50; -- HAVING 過濾分組結果,只能用聚合函數/分組列
關鍵差異:WHERE 過濾原始行(聚合前),HAVING 過濾分組後結果(聚合後)。
最佳實踐清單:
SELECT *,顯式列出所需列。LIMIT 1000000, 20,改用「游標/Seek 分頁」(見本專欄「MySQL LIMIT 深度優化」一文)。GROUP BY 列必須出現在 SELECT 列表或聚合函數中(ONLY_FULL_GROUP_BY 模式下強制)。JOIN 或 EXISTS,尤其 IN (SELECT...) 在大數據量下性能隱患大。