MySQL Неверное значение даты и времени: '0000-00-00 00:00:00'

155

Я недавно принял старый проект, который был создан 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

Нужно ли обновлять каждое значение?

lorm
источник

Ответы:

12

Мое предложение, если таблица пустая или не очень большая, - экспортировать операторы создания в виде файла .sql, переписать их по своему желанию. Также сделайте то же самое, если у вас есть какие-либо существующие данные, т.е. экспортируйте операторы вставки (я рекомендую делать это в отдельном файле как операторы создания). Наконец, удалите таблицу и выполните сначала оператор create, а затем вставьте.

Вы можете использовать для этой mysqldumpкоманды либо команду, включенную в установку MySQL, либо вы также можете установить MySQL Workbench, который является бесплатным графическим инструментом, который также включает эту опцию в очень настраиваемом виде без необходимости искать конкретные параметры команды.

Люсия Пасарин
источник
Люсия Пасарин, мне очень нравится твоя идея, но не будут ли усечены данные? Некоторые данные UTF8 занимают больше байтов, чем latin1? Если что-то вписывалось в varchar 255, возможно, сейчас это не будет? Должен ли я, возможно, изменить все varchars на «текстовые» поля?
Lorm
Да ты прав. Это может произойти, поскольку latin1 использует 1 байт на символ, тогда как utf8 использует максимум 4 байта на символ (в зависимости от версии MySQL и типа utf8 dev.mysql.com/doc/refman/5.5/en/charset-unicode -utf8.html ). Следовательно, вам не обязательно нужен тип TEXT. Я бы предположил, что х4 ваши ранее существующие размеры должны работать.
Люсия Пасарин
Это эквивалент базы данных для переформатирования вашего жесткого диска, когда вы хотите удалить файл. Можно с уверенностью сказать, что это решение неприемлемо в производственной среде.
Брэндон
198

Я не смог сделать это:

UPDATE users SET created = NULL WHERE created = '0000-00-00 00:00:00'

(на MySQL 5.7.13).

Я продолжал получать Incorrect datetime value: '0000-00-00 00:00:00'ошибку.

Странно, это сработало SELECT * FROM users WHERE created = '0000-00-00 00:00:00'. Я понятия не имею, почему первый отказывает, а второй работает ... может быть, ошибка MySQL?

В любом случае этот запрос UPDATE работал:

UPDATE users SET created = NULL WHERE CAST(created AS CHAR(20)) = '0000-00-00 00:00:00'
проектное землетрясение
источник
13
У меня была та же проблема, но установка последней части равной 0 исправила ее для меня так:UPDATE users SET created = NULL WHERE created = '0'
Брайан Лейшман
SELECT * FROM entityWHERE creationAt = "0000-00-00 00:00:00" работает нормально, но с обновленной ошибкой! У меня такая же проблема. Исправить это с помощью решения @obe CAST (созданного как CHAR (20)) ... Я думаю, что это ошибка.
Chrysweel
44
Для меня это работало как UPDATE users SET created = NULL WHERE created=0(без 'около нуля)
KIR
1
Для замены даты «0000-00-00» только без метки времени я использовал CHAR (11)
D.Tate
1
Это чистый гений. Почему это не принятый ответ? Только для даты без отметки времени минимальное значение 1000-01-01. Попробуйте использовать это как значение по умолчанию для каждого атрибута даты, который вы намереваетесь оставить пустым или со значением 0000-00-00.
Арванитис Христос
155

Изменение значения по умолчанию для столбца с ALTER TABLEоператором, например

 ALTER TABLE users MODIFY created datetime  NULL DEFAULT '1970-01-02'

... не изменяет значения, которые уже сохранены. Значение «по умолчанию» применяется к вставляемым строкам, для которых значение не указывается для столбца.


Что касается того, почему вы сталкиваетесь с ошибкой, вполне вероятно, что sql_modeнастройка для вашего сеанса включает NO_ZERO_DATE.

Ссылка: http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_zero_date

Когда вы выполняли «импорт», операторы SQL, которые выполняли INSERT в этой таблице, выполнялись в сеансе, в котором допускались нулевые даты.

Чтобы увидеть настройку sql_mode:

SHOW VARIABLES LIKE 'sql_mode' ;

-или-

SELECT @@sql_mode ;

Что касается того, как «исправить» текущую проблему, чтобы ошибка не возникала при запуске ALTER TABLE оператора.

Несколько вариантов:

1) измените, sql_modeчтобы разрешить нулевые даты, удалив NO_ZERO_DATEи NO_ZERO_IN_DATE. Изменение можно применить в файле my.cnf, поэтому после перезапуска MySQL Serversql_mode переменная будет инициализирована с настройкой в ​​my.cnf.

Для временного изменения мы можем изменить настройку за один сеанс, не требуя глобального изменения.

-- save current setting of sql_mode
SET @old_sql_mode := @@sql_mode ;

-- derive a new value by removing NO_ZERO_DATE and NO_ZERO_IN_DATE
SET @new_sql_mode := @old_sql_mode ;
SET @new_sql_mode := TRIM(BOTH ',' FROM REPLACE(CONCAT(',',@new_sql_mode,','),',NO_ZERO_DATE,'  ,','));
SET @new_sql_mode := TRIM(BOTH ',' FROM REPLACE(CONCAT(',',@new_sql_mode,','),',NO_ZERO_IN_DATE,',','));
SET @@sql_mode := @new_sql_mode ;

-- perform the operation that errors due to "zero dates"

-- when we are done with required operations, we can revert back
-- to the original sql_mode setting, from the value we saved
SET @@sql_mode := @old_sql_mode ;

2) изменить created столбец, чтобы разрешить значения NULL, и обновить существующие строки, чтобы изменить нулевые даты на нулевые значения

3) обновить существующие строки, чтобы изменить нулевые даты на действительные даты


Нам не нужно запускать отдельные операторы для обновления каждой строки. Мы можем обновить все строки одним махом (при условии, что это таблица разумного размера. Для таблицы большего размера, чтобы избежать огромного отката / отмены генерации, мы можем выполнить операцию в кусках разумного размера.)

В этом вопросе AUTO_INCREMENTзначение, показанное для определения таблицы, гарантирует, что количество строк не является чрезмерным.

Если мы уже изменили createdстолбец для учета NULLзначений, мы можем сделать что-то вроде этого:

UPDATE  `users` SET `created` = NULL WHERE `created` = '0000-00-00 00:00:00'

Или мы можем установить их на действительную дату, например, 2 января 1970 г.

UPDATE  `users` SET `created` = '1970-01-02' WHERE `created` = '0000-00-00 00:00:00'

(Обратите внимание, что значение datetime полуночи 1 января 1970 года ( '1970-01-01 00:00:00') является «нулевой датой». Это будет оценено как'0000-00-00 00:00:00'

spencer7593
источник
3
да, это сработало для меня. Я искал sql-mode в файле my.ini и удалил NO_ZERO_IN_DATE и NO_ZERO_DATE. затем перезапустил сервис. спасибо spencer7593!
Мили
Установить NO_ZERO_DATE: stackoverflow.com/questions/3891896/…
пользователь 1007017
Когда я делаю # 2 «изменить созданный столбец, чтобы разрешить значения NULL», он не позволит мне, потому что значения столбца по-прежнему выдают ошибку. Довольно застрял.
Майк Вейр
1
@MikeWeir: предположительно, « не дай мне » означает, что при выполнении оператора SQL возвращается ошибка. Это, вероятно, из-за настройки sql_mode. Более поздние версии MySQL имеют настройки по умолчанию, sql_modeкоторые являются более строгими, чем предыдущие версии. Ссылка на 8,0 здесь: dev.mysql.com/doc/refman/8.0/en/sql-mode.html см NO_ZERO_DATE, ALLOW_INVALID_DATEи др. обратите внимание, что некоторые из них включены в режим STRICT, например STRICT_TRANS_TABLES, STRICT_ALL_TABLESи другие комбинированные режимы. Чтобы обойти ограничения, временно измените sql_mode для сеанса
spencer7593
@ spencer7593 точно. Я не чувствовал, что этот вариант тоже был лучшим. Я воспользовался вашим советом по установке очень старого значения даты (1970), и моя система просто проигнорирует его. Спасибо за все ваши детали.
Майк Вейр
67

Я получил это исправить, выполнив это до запроса

SET SQL_MODE='ALLOW_INVALID_DATES';
Тарик Хан
источник
Это единственный ответ. Используется как: --init-команды = 'SET SESSION FOREIGN_KEY_CHECKS = 0; SET sql_mode =' ALLOW_INVALID_DATES»
Кёнчог
Огромное спасибо. Не могу объяснить, какая боль эта проблема для меня.
Дитер Грибниц
42

Согласно справочному руководству по MySQL 5.7 :

Режим SQL по умолчанию в MySQL 5.7 включает следующие режимы: ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER и NO_ENGEN

Поскольку 0000-00-00 00:00:00недопустимое DATETIMEзначение, ваша база данных повреждена. Вот почему MySQL 5.7 - который поставляется с NO_ZERO_DATEвключенным режимом по умолчанию - выдает ошибку при попытке выполнить операцию записи.

Вы можете исправить свою таблицу, обновив все недопустимые значения до любого другого допустимого значения, например NULL:

UPDATE users SET created = NULL WHERE created < '0000-01-01 00:00:00'

Также, чтобы избежать этой проблемы, я рекомендую вам всегда устанавливать текущее время в качестве значения по умолчанию для ваших createdпохожих полей, чтобы они автоматически заполнялись INSERT. Просто сделать:

ALTER TABLE users
ALTER created SET DEFAULT CURRENT_TIMESTAMP
Иван Фильо
источник
8
SET sql_mode = 'NO_ZERO_DATE';
UPDATE `news` SET `d_stop`='2038-01-01 00:00:00' WHERE `d_stop`='0000-00-00 00:00:00'
Эндрю Марч
источник
4
Этот ответ будет улучшен с обсуждением того, почему это решает проблему.
KevinO
это влияет на дату и время хранения. или вызвать какие-либо проблемы
Спросите байтов
8

Вот какое у меня решение PhpMyAdmin / Fedora 29 / MySQL 8.0 (например):

set sql_mode='SOMETHING'; не работает , вызов команды выполнен успешно, но ничего не изменилось.

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: SHOW VARIABLES LIKE '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, если у вас есть контроль над сервером, вы можете изменить sql_mode(и все остальные параметры) непосредственно вPlus > Variables > sql_mode

Shim-Сан
источник
5

Вы можете изменить тип создаваемого поля с datetimeна varchar(255), затем вы можете установить (обновить) все записи, которые имеют значение "0000-00-00 00:00:00"для NULL.

Теперь вы можете делать ваши запросы без ошибок. После того, как вы закончите, вы можете изменить тип поля, созданного для datetime.

Абдалла Аджлуни
источник
4

У меня эта ошибка также после обновления MySQL с 5.6 до 5.7

Я понял, что лучшим решением для меня было объединить некоторые решения здесь и сделать что-то такое, что работало бы с минимальными затратами.

Я использую MyPHPAdmin для простоты отправки запросов через интерфейс, потому что тогда я могу легко проверить структуру и все такое. Вы можете использовать ssh напрямую или другой интерфейс. Метод должен быть похожим или одинаковым в любом случае.

...

1.

Сначала проверьте фактическую ошибку при попытке восстановить базу данных:

joomla.jos_menu Примечание: столбцы TIME / TIMESTAMP / DATETIME старого формата были обновлены до нового формата.

Предупреждение: неверное значение даты и времени: «0000-00-00 00:00:00» для столбца «checked_out_time» в строке 1

Ошибка: недопустимое значение по умолчанию для 'checked_out_time'

статус: операция не удалась

Это говорит мне о том, что столбцу check_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 ОК

...

Работает просто отлично :)

Дон кинг
источник
4

Проверьте

SELECT @@sql_mode;

если вы видите там материал 'ZERO_DATE', попробуйте

SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'NO_ZERO_DATE',''));   
SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'NO_ZERO_IN_DATE',''));   

Выйдите и снова войдите в свой клиент (это странно) и попробуйте снова

commonpike
источник
3

Сделайте режим sql не строгим

при использовании laravel перейдите в config-> database, перейдите в настройки mysql и установите строгий режим в false

Милинд Чаудхари
источник
Могу ли я сделать это в myphpadmin?
Дон Кинг
phpMyAdmin - это просто интерфейс для использования фактического сервера MySQL, не имеет значения, какой интерфейс вы используете команды MySQL, не будет меняться с интерфейсом. Попробуйте эту команду (set sql_mode = '';) или this (set global sql_mode = '';) отключить.
Милинд Чаудхари
1
да, я нашел все, что нужно, чтобы отключить строгий режим, добавив sql_mode = (и ничего после него), в нижней части my.cnf
Дон Кинг,
3

У меня была похожая проблема, но в моем случае в какой-то строке было значение NULL.

Итак, сначала я обновляю таблицу:

update `my_table`set modified = '1000-01-01 00:00:00' WHERE modified is null

проблема решена, по крайней мере, в моем случае.

Ленон Толфо
источник
2

Я тоже получил

SQLSTATE [22007]: неверный формат даты и времени: 1292 Неверное значение даты и времени: «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

tekintian
источник
1
проблема в том, что OP не может изменить дату из-за ошибки. Я предполагаю, что это ошибка изNO_ZERO_DATE
GusDeCooL
2

Я нашел решение по адресу 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успешно использовать и изменять свои таблицы.

Хайме Монтойя
источник
1

Это то, что я сделал, чтобы решить мою проблему. Я тестировал в локальном MySQL 5.7 Ubuntu 18.04.

set global sql_mode="NO_ENGINE_SUBSTITUTION";

Перед глобальным выполнением этого запроса я добавил файл cnf в каталог /etc/mysql/conf.d . Имя файла cnf : mysql.cnf и коды

[mysqld]
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ALLOW_INVALID_DATES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

Затем я перезапустить MySQL

sudo service mysql restart

Надеюсь, это может кому-то помочь.

Калян Халдер Рааз
источник
Это решение работает, пока я не перезапущу сервер MySQL. Даже после перезапуска значение NO_ENGINE_SUBSTITUTIONнаходится во всех столбцах, SELECT @@global.sql_mode, @@session.sql_mode, @@sql_mode;но все равно я получаю сообщение об ошибке для недопустимой даты и времени, 0000-00-00 00:00:00пока не выполню первый запрос еще раз. set global sql_mode="NO_ENGINE_SUBSTITUTION";Есть идеи?
Смаматти
Решением в моем случае было удалить NO_ZERO_IN_DATE,NO_ZERO_DATEв вашей версии строку my.ini, определяющую sql_mode.
Смаматти
1

Это невероятно некрасиво, но и быстро решило проблему для меня. Ваша таблица нуждается в уникальном ключе, который вы будете использовать для исправления испорченных столбцов. В этом примере первичный ключ называется «id», а поврежденный столбец меток времени - «BadColumn».

  1. Выберите идентификаторы испорченных столбцов.

    select id from table where BadColumn='0000-00-00 00:00:00'

  2. Соберите идентификаторы в строку через запятую. Пример:1, 22, 33 . Я использовал для этого внешнюю оболочку (скрипт Perl), чтобы быстро выплюнуть их все.

  3. Используйте свой список идентификаторов, чтобы обновить старые столбцы с правильной датой (с 1971 по 2038 год).

    update table set BadColumn='2000-01-01 00:00:00' where id in (1, 22, 33)

felwithe
источник
1

Мое решение

SET sql_mode='';
UPDATE tnx_k2_items
SET created_by = 790
, modified = '0000-00-00 00:00:00'
, modified_by = 0
VietPublic
источник
1

Вместо того

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

использование

UPDATE your_table SET your_column = new_valid_value where your_column = 0;
Ренье
источник
0

Если вы вводите данные вручную, вы можете удалить значения и нули на TIMESTAMP (6) .000000, чтобы он стал TIMESTAMP. Это работало хорошо со мной.

Исаак
источник