为 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_TABLES
或STRICT_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
值(无论日期是否正确)都来自此日期之前。
【讨论】:
完美的快速解决方案。事实上,您也可以使用<'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()得到的是包含时分秒的时间。