被 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_DATENO_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

    严格模式下,在 INSERTUPDATE 过程中,如果除零(或 MOD(X,0) ),则产生错误(否则为警告)

    如果未给出该模式,除零时MySQL返回 NULL

    如果设置了 INSERT IGNOREUPDATE IGNORE 中,MySQL 则生成除零警告,但操作结果为 NULL

  6. NO_AUTO_CREATE_USER

    防止 GRANT 自动创建新用户

    但如果通知指定了密码,则有可能会创建新用户

  7. NO_ENGINE_SUBSTITUTION

    如果需要的存储引擎被禁用或未编译,那么抛出错误

    不设置此值时,会默认的存储引擎替代,并抛出一个异常

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.