MySQL 允許在 SQL 陳述式中撰寫包含常數、函數呼叫、欄位參考的複雜表達式,廣泛用於 SELECT 選取清單、WHERE 過濾條件、INSERT ... VALUES()、UPDATE ... SET 等場合。理解表達式求值順序、隱含型別轉換規則、NULL 特殊語意,是撰寫正確、高效查詢的基石。本文系統整理運算子分類與優先序、型別轉換矩陣、日期時間解讀邏輯、常見陷阱與測試驗證技巧。
42)、字串('abc')、十六進位(0x4142)、布林(TRUE/FALSE)NOW()、STRCMP('a','b')、CONCAT(col1, col2) — 函數名與左括號間不可有空格col_name、tbl_name.col_name、db_name.tbl_name.col_name(expr) 改變求值順序優先序由高到低(同行同優先序,左結合):
| 優先序 | 運算子 | 類別 |
|---|---|---|
| 1 (最高) | INTERVAL | 特殊 |
| 2 | BINARY、COLLATE | 型別轉換/排序規則 |
| 3 | !、-(一元負號)、~(位元反轉) | 一元運算子 |
| 4 | ^ | 位元 XOR |
| 5 | *、/、%、DIV | 算術 |
| 6 | +、- | 算術 |
| 7 | <<、>> | 位元位移 |
| 8 | & | 位元 AND |
| 9 | | | 位元 OR |
| 10 | =、<=>、>、>=、<、<=、<>、!=、IS、LIKE、REGEXP、IN | 比較 |
| 11 | BETWEEN、CASE、WHEN、THEN、ELSE | 流程控制 |
| 12 | NOT | 邏輯非 |
| 13 | &&、AND | 邏輯與 |
| 14 | ||、OR | 邏輯或 |
| 15 | := | 指派 |
關鍵差異:|| 在 MySQL 為邏輯或(非字串串接),字串串接必須用 CONCAT()。ANSI 模式下 || 為串接,可用 SET sql_mode='PIPES_AS_CONCAT' 切換。
MySQL 依運算子需求自動轉換運算元型別,核心原則:「以運算子預期型別為準」。
'42' → 數值 42'abc' → 0(伴隨警告)NULL 參與任何算術/位元運算 → 結果 NULLNULL 為假(0),非零數值為真CONCAT(1,2,3) → '123'(數值轉字串)REPEAT('X', CONCAT(1,2,3)/10) → REPEAT('X', 12.3) → 整除得 12 → 12 個 X| 運算元組合 | 比較模式 | 範例結果 |
|---|---|---|
| 兩數值 | 數值比較 | 2 < 11 → 1 |
| 兩字串 | 字典序比較 | '2' < '11' → 0('2' > '1') |
| 數值 + 字串 | 數值比較(字串轉數值) | '2' < 11 → 1 |
| 含 NULL | 結果 NULL(除 <=>、IS NULL) | NULL = 1 → NULL |
| TIMESTAMP/DATETIME + 常數 | 時間值比較 | dt_col < '2025-01-01' |
| 十六進位 + 非數值 | 二進位字串比較 | 0x61 = 'a' → 1 |
20250101 → 日期 '2025-01-01''2025-01-01'、'20250101'、'250101' 皆可解析TO_DAYS('2025-01-01') = TO_DAYS(20250101) = TO_DAYS(20250101.0)'0000-00-00'(零日期)| 操作類別 | 規則 | 範例 |
|---|---|---|
| 算術/位元運算 | 任何運算元為 NULL → 結果 NULL | 5 + NULL = NULL |
| 邏輯運算 | NULL 視為假(0) | NULL AND TRUE = 0 |
| 比較運算 | 除 <=>、IS NULL、IS NOT NULL 外皆回傳 NULL | NULL = NULL → NULL;NULL <=> NULL → 1 |
| 函數參數 | 多數函數遇 NULL 回傳 NULL;IFNULL()、COALESCE() 專門處理 | IFNULL(NULL, 'def') → 'def' |
| 排序 | ASC 時 NULL 排最前;DESC 時排最後 | ORDER BY col ASC → NULL 在最上方 |
-- char_col 為 CHAR 型別,含 '00', '01', 'abc'
DELETE FROM t WHERE char_col = 00; -- 00 視為數值 0
-- 所有非數值字串轉為 0,條件全真,全表被刪!
修正:WHERE char_col = '00' 或 WHERE char_col = '00' + 0 強制字串比較。
-- 錯誤:YEAR(date_col) 需逐列計算
SELECT * FROM t WHERE YEAR(date_col) < 1990;
-- 正確:字面日期常數,可用索引
SELECT * FROM t WHERE date_col < '1990-01-01';
IF(0.3, 'true', 'false') -- 0.3 轉整數為 0 → 'false'
-- 正確寫法
IF(0.3 > 0, 'true', 'false') -- 明確比較
SELECT 'abc' + 0, '123' + 0, 'abc' = 0, '123' = 0;
SELECT IFNULL(NULL, 'x'), COALESCE(NULL, NULL, 'y');
SELECT 0.3, 0.3 + 0, 0.3 > 0;
col + 0 或 col * 1 或 CAST(col AS UNSIGNED)CONCAT(col) 或 CAST(col AS CHAR)STR_TO_DATE(col, '%Y%m%d') 或 CAST(col AS DATE)BINARY col = 'ABC' 或 col = BINARY 'ABC'ENUM/SET 非法值轉為空串/移除非法子項0000-00-00、00:00:00)ALTER TABLE、LOAD DATA、UPDATE、多列 INSERT 產生的轉換會回傳警告計數,可用 SHOW WARNINGS 或 API mysql_info() 取得MySQL 的型別系統以「寬容自動轉換」著稱,但這正是 Bug 溫床。掌握運算子優先序、比較模式判定邏輯、NULL 三值邏輯、日期時間解讀規則,並養成關鍵查詢先用 SELECT 驗證表達式結果的習慣,才能寫出穩健、可預測的 SQL。建議在開發規範中明確要求:WHERE 條件運算元型別一致、禁止隱含轉換、日期常數統一用 'YYYY-MM-DD' 格式。