SQL Mode 決定 MySQL 「多嚴格地執行 SQL 標準」。本文系統梳理模式分類、常用組合、異構遷移預設組合、數據驗證功能、版本演進差異,給出生產環境配置建議與避坑指南。
| 模式值 | 分類 | 核心行為 |
|---|---|---|
ANSI | 標準相容 | 語法/行為向標準 SQL 靠攏(|| 為字符串連接、"" 為標識符引號等) |
STRICT_TRANS_TABLES | 嚴格模式 | 事務表:非法值報錯回滾;非事務表:首行非法值報錯停止 |
STRICT_ALL_TABLES | 嚴格模式 | 所有表(含非事務)非法值均報錯回滾/停止 |
TRADITIONAL | 嚴格組合 | STRICT_TRANS_TABLES + NO_ZERO_IN_DATE + NO_ZERO_DATE + ERROR_FOR_DIVISION_BY_ZERO + NO_ENGINE_SUBSTITUTION,「傳統」數據庫行為:錯誤即停止,不再警告 |
NO_ZERO_IN_DATE | 日期驗證 | 禁止月/日為 0 的日期(如 '2024-00-01') |
NO_ZERO_DATE | 日期驗證 | 禁止 '0000-00-00' 作為合法日期 |
ERROR_FOR_DIVISION_BY_ZERO | 數學驗證 | 除零報錯而非返回 NULL |
NO_ENGINE_SUBSTITUTION | 引擎保護 | 指定引擎不可用時報錯,不自動降級為 InnoDB/MyISAM |
ONLY_FULL_GROUP_BY | 聚合規範 | SELECT 列必須出現在 GROUP BY 或聚合函數中(5.7+ 默認開啟) |
PIPES_AS_CONCAT | 語法兼容 | || 作為字符串連接(同 CONCAT),而非 OR |
ANSI_QUOTES | 語法兼容 | " 作為標識符引號,字符串必須用 ' |
IGNORE_SPACE | 語法兼容 | 允許函數名與括號間有空格 COUNT (*) |
NO_ENGINE_SUBSTITUTIONONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_ENGINE_SUBSTITUTION, NO_AUTO_CREATE_USERNO_AUTO_CREATE_USER(已內建)。| 目標數據庫 | SQL Mode 組合 |
|---|---|
| DB2 | PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, NO_KEY_OPTIONS, NO_TABLE_OPTIONS, NO_FIELD_OPTIONS |
| MaxDB | DB2 組合 + NO_AUTO_CREATE_USER |
| MSSQL | DB2 組合 |
| Oracle | DB2 組合 + NO_AUTO_CREATE_USER |
| PostgreSQL | DB2 組合 |
核心作用:屏蔽 MySQL 特有的 KEY/ENGINE/AUTO_INCREMENT 等語法,使導出的 DDL 更易被目標數據庫識別。
NO_ZERO_IN_DATE + NO_ZERO_DATE 拒絕 '0000-00-00'、'2024-00-15'。ERROR_FOR_DIVISION_BY_ZERO 使 SELECT 1/0 報錯而非返回 NULL。ANSI_QUOTES 開啟後 "col" 視為列名,字符串必須用單引號。NO_BACKSLASH_ESCAPES 使 \ 變為普通字符,防止注入繞過。PIPES_AS_CONCAT 使 'a' || 'b' 等價 CONCAT('a','b')。# /etc/my.cnf [mysqld] # 5.7/8.0 推薦:嚴格 + 日期驗證 + 除零報錯 + 引擎保護 + 聚合規範 sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY" # 兼容舊應用(不建議長期):暫時移除 STRICT_TRANS_TABLES # sql_mode = "NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY"
-- 全局動態修改(即時生效,重啟失效) SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY'; -- 會話級覆蓋(僅當前連接) SET SESSION sql_mode = 'ANSI,STRICT_TRANS_TABLES'; -- 查看當前 SELECT @@GLOBAL.sql_mode, @@SESSION.sql_mode;
| 坑點 | 現象 | 解決 |
|---|---|---|
| 舊應用插入 '0000-00-00' | 報錯 Incorrect date value | 應用層修正為 NULL 或有效日期;或暫時移除 NO_ZERO_DATE |
| GROUP BY 報錯 | Expression #1 of SELECT list is not in GROUP BY clause | 補全 GROUP BY 列,或關閉 ONLY_FULL_GROUP_BY(不推薦) |
| 字符串截斷不報錯 | VARCHAR(10) 插入 20 字符靜默截斷 | 開啟 STRICT_TRANS_TABLES 強制報錯 |
| 主從 SQL Mode 不一致 | 同步報錯/數據不一致 | 主從**強制保持相同** sql_mode,納入巡檢 |
SQL Mode 是 MySQL 「嚴格程度」的總開關,**生產環境強制開啟嚴格模式**,在開發/測試階段暴露數據質量問題,避免髒數據入庫。