为 DATE 或 DATETIME 设置默认值时 MySQL 出错

Posted

技术标签:

【中文标题】为 DATE 或 DATETIME 设置默认值时 MySQL 出错【英文标题】:Error in MySQL when setting default value for DATE or DATETIME 【发布时间】:2016-07-22 07:45:16 【问题描述】:

我运行的是mysql Server 5.7.11和这句话:

updated datetime NOT NULL DEFAULT '0000-00-00 00:00:00'

没有工作。给出错误:

ERROR 1067 (42000): Invalid default value for 'updated'

但是如下:

updated datetime NOT NULL DEFAULT '1000-01-01 00:00:00'

正常工作

DATE 的情况相同。

作为一个旁注,在MySQL docs中提到:

DATE 类型用于具有日期部分但没有时间部分的值。 MySQL 以 'YYYY-MM-DD' 格式检索和显示 DATE 值。支持的范围是“1000-01-01”到“9999-12-31”。

即使他们也说:

无效的 DATE、DATETIME 或 TIMESTAMP 值将转换为相应类型的“零”值('0000-00-00' 或 '0000-00-00 00:00:00')。

还考虑到 MySQL 文档的第二个引用,谁能告诉我为什么它会给出这个错误?

【问题讨论】:

你为什么想要一个明显没有意义的默认值?如果日期未知,那么这正是NULL 的用途。 注意:这适用于 SQL Fiddle 的 5.6 版——sqlfiddle.com/#!9/02c98。 @Karlos 检查更新的答案。 @TomH 约会中的零在您看来毫无意义,这已经超出了许多读者的兴趣。显然,NULL 始终存在,因为它是0000-00-00 00:00:00。他们两个,在我看来是非常不同的。回答您的评论,也超出了这篇文章的范围,并确保完整的网站本身。 【参考方案1】:

这个错误是因为sql模式,根据最新的MYSQL 5.7文档可以是严格模式

MySQL Documentation 5.7 says:

严格模式影响服务器是否允许 '0000-00-00' 作为有效日期: 如果未启用严格模式,则允许“0000-00-00”并且插入不会产生警告。 如果启用了严格模式,则不允许使用“0000-00-00”,并且插入会产生错误,除非也给出了 IGNORE。对于 INSERT IGNORE 和 UPDATE IGNORE,允许使用 '0000-00-00' 并且插入会产生警告。

检查 MYSQL 模式

SELECT @@GLOBAL.sql_mode global, @@SESSION.sql_mode session

禁用 STRICT_TRANS_TABLES 模式

但是要允许0000-00-00 00:00:00格式,你必须在 mysql 配置文件中或通过命令禁用 STRICT_TRANS_TABLES 模式

通过命令

SET sql_mode = '';

SET GLOBAL sql_mode = '';

使用关键字GLOBAL 需要超级权限,它会影响从那时起所有客户端连接的操作

如果上述方法不起作用,请转到 /etc/mysql/my.cnf(根据 ubuntu)并注释掉 STRICT_TRANS_TABLES

另外,如果您想在服务器启动时永久设置 sql 模式,请在 Linux 或 MacOS 上将 SET sql_mode='' 包含在 my.cnf 中。对于 Windows,这必须在 my.ini 文件中完成。

注意

然而,MYSQL 5.6 默认不启用严格模式。因此,它不会按照MYSQL 6 documentation 的说法产生错误

MySQL 允许您将“0000-00-00”的“零”值存储为“虚拟日期”。在某些情况下,这比使用 NULL 值更方便,并且使用更少的数据和索引空间。要禁止“0000-00-00”,请启用 NO_ZERO_DATE SQL 模式。

更新

关于@Dylan-Su 所说的错误问题:

我不认为这是 MYSQL 随着时间的推移而演变的错误,因为随着产品的进一步改进,一些事情发生了变化。

但是我有另一个关于 NOW() 函数的相关错误报告

Datetime field does not accept default NOW()

另一个有用的说明 [参见Automatic Initialization and Updating for TIMESTAMP and DATETIME]

从 MySQL 5.6.5 开始,TIMESTAMP 和 DATETIME 列可以自动初始化并更新为当前日期和时间(即当前时间戳)。在 5.6.5 之前,这仅适用于 TIMESTAMP,并且每个表最多有一个 TIMESTAMP 列。以下说明首先描述 MySQL 5.6.5 及更高版本的自动初始化和更新,然后描述 5.6.5 之前版本的差异。

关于 NO_ZERO_DATE 的更新

从 MySQL 5.7.4 开始,此模式已弃用。对于以前的版本,您必须注释掉配置文件中的相应行。参考MySQL 5.7 documentation on NO_ZERO_DATE

【讨论】:

UPDATE IGNORE 是我要找的东西?? 错了。我的两个 MySQL 实例(本地和服务器)都有 STRICT_TRANS_TABLES。但是,我可以在本地实例中轻松插入 0000-00-00,但不能在我的服务器实例中插入 - 会引发错误。为什么?因为我的服务器 MySQL 配置启用了NO_ZERO_DATE。而我的本地没有。 ok @Green 如果适用,我会找出并更新答案 在我的情况下,'SET sql_mode = ""' 不起作用。 'SET GLOBAL sql_mode = "";'为我完成了这项工作。 还应该删除NO_ZERO_DATE【参考方案2】:

我在 WAMP 3.0.6 和 MySql 5.7.14 中遇到了这个错误。

解决方案

c:\wamp\bin\mysql\mysql5.7.14\my.ini 文件中的第 70 行(如果您的 ini 文件未更改)从

sql-mode= "STRICT_ALL_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ZERO_DATE,NO_ZERO_IN_DATE,NO_AUTO_CREATE_USER"

sql-mode="ERROR_FOR_DIVISION_BY_ZERO,NO_ZERO_DATE,NO_ZERO_IN_DATE,NO_AUTO_CREATE_USER"

并重新启动所有服务。

这将禁用严格模式。根据文档,“严格模式”是指启用STRICT_TRANS_TABLESSTRICT_ALL_TABLES 中的一个或两个的模式。 documentation 说:

"MySQL 5.7 中默认的 SQL 模式包括以下模式: 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。”

【讨论】:

【参考方案3】:

我遇到了一种情况,日期字段的数据在 NULL 和 0000-00-00 之间混合。但我不知道如何将 '0000-00-00' 更新为 NULL,因为

 update my_table set my_date_field=NULL where my_date_field='0000-00-00'

不再允许。 我的解决方法很简单:

update my_table set my_date_field=NULL where my_date_field<'0000-01-01'

因为所有不正确的my_date_field 值(无论日期是否正确)都来自此日期之前。

【讨论】:

完美的快速解决方案。事实上,您也可以使用&lt;'0000-01-01',因为它当然是一个有效日期。【参考方案4】:

首先选择当前会话sql_mode

SELECT @@SESSION.sql_mode;

然后你会得到类似default value:

'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'

然后设置sql_mode 不带'NO_ZERO_DATE'

SET SESSION sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

如果你有授权,你也可以为GLOBAL

SELECT @@GLOBAL.sql_mode;
SET GLOBAL sql_mode = '...';

【讨论】:

【参考方案5】:

配置语法问题

在 *nix 系统下的某些 MYSQL 版本(测试 5.7.*)上,您应该使用以下语法:

[mysqld]

sql-mode="NO_BACKSLASH_ESCAPES,STRICT_TRANS_TABLE,NO_ENGINE_SUBSTITUTION"

这些不起作用:

没有引号

sql-mode=NO_ENGINE_SUBSTITUTION

下划线不加引号

sql_mode=NO_ENGINE_SUBSTITUTION

下划线和引号

sql_mode="NO_ENGINE_SUBSTITUTION"

更完整的配置值和 sql-mode 回顾:

How to setup permanent Sql Mode flags

【讨论】:

【参考方案6】:

只需添加一行:sql_mode = "NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

内部文件:/etc/mysql/mysql.conf.d/mysqld.cnf

然后sudo service mysql restart

【讨论】:

适用于 5.7.23。 我可能首先建议SELECT @@SESSION.sql_mode;,然后他们从它给你的内容中删除 NO_ZERO_IN_DATE、NO_ZERO_DATE 和 STRICT_TRANS_TABLES。这样您就可以保留您启用的任何其他设置。我为我的 sql 模式设置的不仅仅是这两个项目。不知道它们都做了什么,但我不想冒险移除它们。【参考方案7】:

适用于 5.7.8:

mysql> create table t1(updated datetime NOT NULL DEFAULT '0000-00-00 00:00:00');
Query OK, 0 rows affected (0.01 sec)

mysql> show create table t1;
+-------+-------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                            |
+-------+-------------------------------------------------------------------------------------------------------------------------+
| t1    | CREATE TABLE `t1` (
  `updated` datetime NOT NULL DEFAULT '0000-00-00 00:00:00'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+-------+-------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.8-rc  |
+-----------+
1 row in set (0.00 sec)

您可以创建一个 SQLFiddle 来重新创建您的问题。

http://sqlfiddle.com/

如果它适用于 MySQL 5.6 和 5.7.8,但在 5.7.11 上失败。那么它可能是 5.7.11 的回归错误。

【讨论】:

这其实是一个非常准确的答案【参考方案8】:

使用 MySQL Workbench 解决问题(在服务器端应用解决方案后):

在首选项面板中将 SQL_MODE 删除为 TRADITIONAL。

【讨论】:

【参考方案9】:

这个答案只适用于 MySQL 5.7:

最好并没有真正将sql_mode设置为空白,而是在php中使用会话变量:

SET SESSION sql_mode= 'ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'

所以至少你保留其他默认值。

疯狂的是mysql文档不清楚,需要在sql_mode中删除这些默认值:

NO_ZERO_IN_DATE,NO_ZERO_DATE,我明白,但在未来的版本中,这将被停用。

STRICT_ALL_TABLES,有了这个,before参数会被忽略,所以你也需要删除它。

最后也是传统的,但是文档谈到了这个参数:“在将不正确的值插入列时给出错误而不是警告”,使用此参数,不会插入零值的日期,但没有插入。

MySQL 并没有真正使用这些参数和组合进行组织。

【讨论】:

【参考方案10】:

mysql Ver 14.14 Distrib 5.7.18, for Linux (x86_64) 的选项组合。

不扔:

STRICT_TRANS_TABLES + NO_ZERO_DATE

投掷:

STRICT_TRANS_TABLES + NO_ZERO_IN_DATE

我在 Ubuntu 上 /etc/mysql/my.cnf 的设置:

[mysqld]
sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

【讨论】:

【参考方案11】:
set global sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

【讨论】:

【参考方案12】:

我已经测试了如下修复:

1). On the file "system/library/db/mysqli.php" search and comment the line: 
"$this->connection->query("SET SESSION sql_mode = 'NO_ZERO_IN_DATE,NO_ZERO_DATE,NO_ENGINE_SUBSTITUTION'");"

2) Add the following line above the one you just commented:
// Correction by Added by A.benkorich
$this->connection->query("SET SESSION sql_mode = 'ONLY_FULL_GROUP_BY'");

【讨论】:

【参考方案13】:

选择数据库并运行 SQL 查询:

SELECT @@GLOBAL.sql_mode global, @@SESSION.sql_mode session

【讨论】:

【参考方案14】:

在目录 xampp/mysql/bin 打开“my.ini”并更改行:sql_mode for ->

"sql_mode=NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE"

REMOVE "NO_ZERO_IN_DATE"

【讨论】:

欢迎使用***,请使用正确的代码格式以提高答案的易读性。【参考方案15】:

1.使用以下命令将默认日期更改为 current_timestamp:-

  ALTER TABLE `wp_posts` CHANGE `post_date` `post_date`  DATETIME NOT
  NULL DEFAULT CURRENT_TIMESTAMP

2。使用以下命令将默认日期更改为 NULL:-

 ALTER TABLE `wp_posts` CHANGE `post_date` `post_date`  DATETIME NOT
 NULL DEFAULT NULL

3.使用以下命令更改超过 1 列的默认日期 使用单个 SQL 查询:-

ALTER TABLE `wp_posts`  CHANGE `post_date` `post_date` DATETIME NOT NULL 
DEFAULT CURRENT_TIMESTAMP, CHANGE `post_date_gmt` `post_date_gmt` 
DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CHANGE `post_modified` 
`post_modified` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CHANGE 
`post_modified_gmt` `post_modified_gmt` DATETIME NOT NULL DEFAULT 
 CURRENT_TIMESTAMP;

【讨论】:

以上是关于为 DATE 或 DATETIME 设置默认值时 MySQL 出错的主要内容,如果未能解决你的问题,请参考以下文章

在为 Date SQL Server 字段添加 DateTime C# 值时,我应该使用 Date 还是 DateTime SqlDbType?

sql server中datetime字段只取年月日如2006-04-21,默认值如何设置?getdate()得到的是包含时分秒的时间。

向列 'datetime' 添加值时导致溢出

如何在 Rails 中为 datetime_field_tag 设置默认值

使用相同的函数设置多个类属性

如何将 Timestamp 转换为 Date 或 DateTime 对象?