division mysql_三、被 MySQL sql_mode 深深伤害( 上 )
常在海邊走,哪有不濕鞋,用 MySQL 多了,就常常會遇見各種錯誤,尤其是不同版本帶來的錯誤。
而經常刺痛我們的,應該數 MySQL 的 sql_mode 了,比如在 記不住的 MySQL DISTINCT 的用法 ( 上 ) 的示例數據下執行下面的語句會報錯
mysql> SELECT DISTINCT(user),fruit FROM fruits GROUP BY user,fruit;
ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.fruits.fruit' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
這個錯誤的意思是說,在 sql_mode=only_full_group_by 模式下,所選取的字段,必須出現在 GROUP BY 子句中。
這種要求其實也很好理解,如果選取的列不在 GROUP BY 子句中,那么它的值就是隨機的,沒啥大意義。
還有另一種情況的 sql_mode 錯誤,就是在 5.7 以上的版本中,timestamp 類型的默認值不能全為 0 ,及 0000-00-00 00:00:00
比如,執行下面的語句會報錯
mysql> CREATE TABLE `test`.`user` (
`id` int AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
);
ERROR 1067 (42000): Invalid default value for 'created_at'
出現這個問題的原因,是因為 sql_mode 包含了 NO_ZERO_IN_DATE 和 NO_ZERO_DATE,而在這兩個模式下,timestamp 的年份只能是 1970-2038,對了,上限在某些機子上已經不是 2038 了
字符這個錯誤的辦法很簡單,就是把 timestamp 類型的默認值改成 1970-01-01 00:00:00
mysql> CREATE TABLE `test`.`user` (
-> `id` int AUTO_INCREMENT,
-> `created_at` datetime NOT NULL DEFAULT '1970-01-01 00:00:00',
-> PRIMARY KEY (`id`)
-> );
Query OK, 0 rows affected (0.10 sec)
這很反直覺,但很有效,只不過在判斷 timestamp 是否為空的時候,可能就要判斷是否等于 `1970-01-01 00:00:00
還有很多很多 sql_mode 引起的錯誤,小編一時就想不起來了
sql_mode 是什么 ?
屢屢受 sql_mode 欺負,那么它到底是什么 ?
官網對此的解釋是 「 Modes affect the SQL syntax MySQL supports and the data validation checks it performs 」
翻譯成中文就是 「 模式會影響 MySQL 支持的 SQL 語法以及它執行的數據驗證檢查 」
白話一點就是 sql_mode 決定了哪些 SQL 語句可以被執行,哪些不能被執行
MySQL 查看 sql_mode
其實,官方還有一段話
The MySQL server can operate in different SQL modes, and can apply these modes differently for different clients, depending on the value of the sql_mode system variable. DBAs can set the global SQL mode to match site server operating requirements, and each application can set its session SQL mode to its own requirements
這句話的意思是說
「 MySQL 服務器可以在不同的 SQL 模式下運行,并且可以針對不同的客戶端以不同的方式應用這些模式,具體取決于 sql_mode 系統變量的值 」。
那你肯定和我一樣好奇,就是當前連接的 sql_mode 到底是什么 ?
好在 MySQL 提供了一些命令用于查詢和設置 sql_mode,我們可以使用下面的命令查看當前 MySQL 連接的 sql_mode
mysql> select @@sql_mode;
+-----------------------------------------------------------------+
| @@sql_mode |
+-----------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,
|STRICT_TRANS_TABLES,
|NO_ZERO_IN_DATE,
|NO_ZERO_DATE,
|ERROR_FOR_DIVISION_BY_ZERO,
|NO_AUTO_CREATE_USER,
|NO_ENGINE_SUBSTITUTION |
+------------------------------------------------------------------+
1 row in set (0.00 sec)
(我對結果進行了換行)
是不是看到了熟悉的身影,其實 sql_mode 遠遠不止這些值。我們暫時只對常見的幾個值做下解釋吧
1、 ONLY_FULL_GROUP_BY
對于 `GROUP BY` 聚合操作,如果 `SELECT中` 的列,沒有在 `GROUP BY` 中出現,那么將認為這個 SQL 是不合法的
2、 STRICT_TRANS_TABLES
在該模式下,如果一個值不能插入到一個事務表中,則中斷當前的操作,對非事務表不做任何限制
3、 NO_ZERO_IN_DATE
在嚴格模式,不接受月或日部分為0的日期。
如果使用 `IGNORE` 選項或非嚴格模式,則可以插入類似的日期 '0000-00-00',但會生成警告
4、 NO_ZERO_DATE
在嚴格模式,不要將 '0000-00-00' 做為合法日期
如果使用 `IGNORE` 選項或非嚴格模式,則可以插入類似的日期 '0000-00-00',但會生成警告
5、 ERROR_FOR_DIVISION_BY_ZERO
嚴格模式下,在 `INSERT` 或 `UPDATE` 過程中,如果除零(或 `MOD(X,0)` ),則產生錯誤(否則為警告)
如果未給出該模式,除零時MySQL返回 `NULL`
如果設置了 `INSERT IGNORE` 或 `UPDATE IGNORE` 中,MySQL 則生成除零警告,但操作結果為 `NULL`
6、 NO_AUTO_CREATE_USER
防止 `GRANT` 自動創建新用戶
但如果通知指定了密碼,則有可能會創建新用戶
7、 NO_ENGINE_SUBSTITUTION:
如果需要的存儲引擎被禁用或未編譯,那么拋出錯誤
不設置此值時,會默認的存儲引擎替代,并拋出一個異常
干貨推薦
附錄:MySQL 拾遺:系列文章
總結
以上是生活随笔為你收集整理的division mysql_三、被 MySQL sql_mode 深深伤害( 上 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【读书笔记】《数据产品经理修炼手册》——
- 下一篇: 深度学习对抗生成网络--GAN