我最近接手了一个10年前创建的老项目。它使用MySQL 5.1。

除此之外,我需要将默认字符集从latin1更改为utf8。

举个例子,我有这样的表格:

  CREATE TABLE `users` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `first_name` varchar(45) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL,
    `last_name` varchar(45) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL,
    `username` varchar(127) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
    `email` varchar(127) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
    `pass` varchar(20) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL,
    `active` char(1) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL DEFAULT 'Y',
    `created` datetime NOT NULL,
    `last_login` datetime DEFAULT NULL,
    `author` varchar(1) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT 'N',
    `locked_at` datetime DEFAULT NULL,
    `created_at` datetime DEFAULT NULL,
    `updated_at` datetime DEFAULT NULL,
    `ripple_token` varchar(36) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL,
    `ripple_token_expires` datetime DEFAULT '2014-10-31 08:03:55',
    `authentication_token` varchar(255) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `index_users_on_reset_password_token` (`reset_password_token`),
    UNIQUE KEY `index_users_on_confirmation_token` (`confirmation_token`),
    UNIQUE KEY `index_users_on_unlock_token` (`unlock_token`),
    KEY `users_active` (`active`),
    KEY `users_username` (`username`),
    KEY `index_users_on_email` (`email`)
  ) ENGINE=InnoDB AUTO_INCREMENT=1677 DEFAULT CHARSET=utf8 CHECKSUM=1 DELAY_KEY_WRITE=1 ROW_FORMAT=DYNAMIC

我设置了自己的Mac来处理这个。没有考虑太多,我运行“brew install mysql”安装mysql 5.7。所以我有一些版本冲突。

我下载了这个数据库的副本并导入了它。

如果我试着像这样运行查询:

  ALTER TABLE users MODIFY first_name varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci    NOT NULL  

我得到这个错误:

  ERROR 1292 (22007): Incorrect datetime value: '0000-00-00 00:00:00' for column 'created' at row 1

我想我可以用:

  ALTER TABLE users MODIFY created datetime  NULL DEFAULT '1970-01-01 00:00:00';
  Query OK, 0 rows affected (0.06 sec)
  Records: 0  Duplicates: 0  Warnings: 0

但我明白:

  ALTER TABLE users MODIFY first_name varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci    NOT NULL ;
  ERROR 1292 (22007): Incorrect datetime value: '0000-00-00 00:00:00' for column 'created' at row 1

我必须更新每个值吗?


当前回答

而不是

UPDATE your_table SET your_column = new_valid_value where your_column = '0000-00-00 00:00:00';

Use

UPDATE your_table SET your_column = new_valid_value where your_column = 0;

其他回答

我还得到

SQLSTATE[22007]: Invalid datetime format: 1292错误的datetime 列值:'0000-00-00 00:00:00'

错误信息

通过将0000-00-00 00:00:00更改为1970-01-01 08:00:00来修复此问题

1970-01-01 08:00:00 Unix时间戳为0

这是非常丑陋的,但它也很快为我解决了问题。您的表需要一个唯一的键,您将使用它来修复受污染的列。在这个例子中,主键被称为“id”,损坏的时间戳列被称为“BadColumn”。

选择受污染列的id。 select id from BadColumn='0000-00-00 00:00:00' 将id收集到一个以逗号分隔的字符串中。例如:1,22,33。为此,我使用了一个外部包装器(Perl脚本)来快速地将它们全部输出。 使用id列表使用有效日期(1971年到2038年)更新旧列。 更新表BadColumn='2000-01-01 00:00:00' where id in (1,22,33)

我在https://support.plesk.com/hc/en-us/articles/115000666509-How-to-change-the-SQL-mode-in-MySQL上找到了解决方案。我有这个:

mysql> show variables like 'sql_mode';
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value                                                                                                                                     |
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| 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, 1 warning (0.01 sec)

注意上面结果中的NO_ZERO_IN_DATE,NO_ZERO_DATE。我通过这样做去掉了它:

mysql> SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
Query OK, 0 rows affected, 1 warning (0.00 sec)

然后我有了这个:

mysql> show variables like 'sql_mode';
+---------------+--------------------------------------------------------------------------------------------------------------+
| Variable_name | Value                                                                                                        |
+---------------+--------------------------------------------------------------------------------------------------------------+
| sql_mode      | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+---------------+--------------------------------------------------------------------------------------------------------------+
1 row in set, 1 warning (0.01 sec)

在此之后,我可以成功地使用ALTER TABLE并更改我的表。

下面是我的解决方案PhpMyAdmin / Fedora 29 / MySQL 8.0(以)为例:

设置sql_mode = '东西';不工作,命令调用成功,但什么都没有改变。

set GLOBAL sql_mode='SOMETHING';更改全局配置永久更改。

set SESSION sql_mode='SOMETHING';session变量只影响当前客户端。

https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html

所以我这样做:

显示类似SQL_MODE的变量; 结果: ONLY_FULL_GROUP_BY、STRICT_TRANS_TABLES NO_ZERO_IN_DATE、NO_ZERO_DATE ERROR_FOR_DIVISION_BY_ZERO NO_ENGINE_SUBSTITUTION 删除结果:NO_ZERO_IN_DATE,NO_ZERO_DATE 设置新的配置:Set GLOBAL SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'

您可以以同样的方式删除或添加其他模式。

这有助于更改使用和测试框架的全局或sql_mode必须在每个文件或一组查询中指定。

改编自这里的一个问题:how-can-i-disable-mysql-strict-mode

示例:安装最新的Joomla 4.0 alpha内容。

编辑: 在PhpMyadmin中,如果您拥有服务器的控制权,您可以直接在Plus > Variables > sql_mode中更改sql_mode(以及所有其他参数)

在MySQL从5.6升级到5.7后,我也有这个错误

我发现,对我来说,最好的解决方案是把这里的一些解决方案结合起来,用最少的输入来实现它。

我使用MyPHPAdmin是为了通过接口发送查询的简单性,因为这样我就可以轻松地检查结构和所有这些。您可以直接使用ssh或其他接口。无论如何,方法应该相似或相同。

...

1.

首先检查实际错误时,试图修复db:

joomla。jos_menu注意:旧格式的TIME/TIMESTAMP/DATETIME列已升级为新格式。 警告:错误的日期时间值:'0000-00-00 00:00:00'列checked_out_time在第1行 错误:'checked_out_time'的默认值无效 状态:操作失败

这告诉我列checked_out_time在表jos_menu需要有所有坏的日期固定以及“默认”改变。

...

2.

我根据错误消息中的信息运行SQL查询:

UPDATE jos_menu SET checked_out_time = '1970-01-01 08:00:00' WHERE checked_out_time = 0

如果你得到一个错误,你可以使用下面的查询,似乎总是工作:

UPDATE jos_menu SET checked_out_time = '1970-01-01 08:00:00' WHERE CAST(checked_out_time AS CHAR(20)) = '0000-00-00 00:00:00'

...

3.

然后,一旦完成,我运行第二个SQL查询:

ALTER TABLE `jos_menu` CHANGE `checked_out_time` `checked_out_time` DATETIME NULL DEFAULT CURRENT_TIMESTAMP;

或者在这种情况下,它是一个必须为NULL的日期

ALTER TABLE `jos_menu` CHANGE `checked_out_time` `checked_out_time` DATETIME NULL DEFAULT NULL;

...

如果我现在运行修复数据库,我得到:

joomla。jos_menu 好吧

...

工作得很好:)