Неправильне значення дати 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 для роботи над цим. Не надто замислюючись про це, я запустив "варити встановити 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

Чи потрібно оновлювати кожне значення?

Відповіді:


12

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

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


Люсія Пасарін, мені дуже подобається ваша ідея, але чи не будуть усічені дані? Чи деякі дані UTF8 займають більше байтів, ніж latin1? Якщо раніше щось вміщувалось у varchar 255, можливо, тепер це не буде? Чи повинен я, можливо, змінити всі вархари на "текстові" поля?
лорм

Так, ти маєш рацію. Це може статися, оскільки latin1 використовує 1 байт на char, тоді як utf8 використовує максимум 4 байти на char (залежно від версії MySQL та типу utf8 dev.mysql.com/doc/refman/5.5/uk/charset-unicode -utf8.html ). Тому вам не обов'язково потрібен тип TEXT. Я б припустив, що x4 ваші раніше існуючі розміри повинні працювати.
Луція Пасарін

Це еквівалент бази даних переформатування вашого жорсткого диска, коли ви хочете видалити файл. Можна впевнено сказати, що це рішення неприйнятне у виробничих умовах.
Брендон

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'
Брайан Лейшман

ВИБІР * ВІД entityЧОГО createAt = "0000-00-00 00:00:00" працює нормально, але з оновленою помилкою! У мене була така ж проблема. Виправте це за допомогою рішення @obe CAST (створено AS CHAR (20)) ... Я думаю, що це помилка.
Chrysweel

44
Для мене це спрацювало так UPDATE users SET created = NULL WHERE created=0(без 'близько нуля)
КІР

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/uk/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 Server sql_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'

(Зверніть увагу, що значення часу в півночі 1 січня 1970 року '1970-01-01 00:00:00') є "нульовою датою". Це буде оцінено як'0000-00-00 00:00:00'


3
так, це працювало для мене. Я шукав режим sql у файлі my.ini та видалив NO_ZERO_IN_DATE та NO_ZERO_DATE. потім перезапустили службу. дякую spencer7593!
мілі


Коли я роблю №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-command = 'НАСТРОЙКА СЕССІЇ 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 і NOUS.

Оскільки 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 повинні бути вказані у кожному файлі чи купі запитів.

Адаптований із запитання запитайте тут: як-можна-i-відключити-mysql-строгий режим

Приклад: встановити останній вміст Joomla 4.0-альфа.

Редагувати: У PhpMyadmin, якщо ви контролюєте сервер, ви можете змінити sql_mode(та всі інші параметри) безпосередньо вPlus > Variables > sql_mode


5

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

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


4

У мене є ця помилка і після оновлення MySQL з 5.6 до 5.7

Я зрозумів, що найкращим рішенням для мене є поєднання деяких тут рішень і зробити щось із цього, що працюватиме з мінімальним вкладом.

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

...

1.

Спочатку перевірте фактичну помилку при спробі відновити db:

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

Попередження: Неправильне значення дати: "0000-00-00 00:00:00" для стовпця "check_out_time" у рядку 1

Помилка: недійсне значення за замовчуванням для "check_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',''));   

Вийдіть і знову ввійдіть до свого клієнта (це дивно) та повторіть спробу


3

Зробіть режим sql не суворим

якщо за допомогою laravel перейдіть до конфігурації> бази даних, перейдіть до налаштувань mysql і зробіть суворий режим помилковим


Чи можу я це зробити в myphpadmin?
Дон Кінг

phpMyAdmin - це просто інтерфейс для використання фактичного сервера mysql, неважливо, який інтерфейс, який ви використовуєте команди mysql, не зміниться з інтерфейсом. Спробуйте цю команду (встановити sql_mode = '';) або цю (встановити глобальний sql_mode = '';), щоб вимкнути її.
Milind Chaudhary

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


1
проблема полягає в тому, що ОП не може змінити дату через помилку. Я думаю, що це помилка з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";Будь-які ідеї?
Smamatti

У моєму випадку рішенням було видалити NO_ZERO_IN_DATE,NO_ZERO_DATEу вашій версії рядка my.ini, що визначає sql_mode.
Smamatti

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)


1

Моє рішення

SET sql_mode='';
UPDATE tnx_k2_items
SET created_by = 790
, modified = '0000-00-00 00:00:00'
, modified_by = 0

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. Це добре працювало зі мною.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.