MySQL Valor de fecha y hora incorrecto: '0000-00-00 00:00:00'

155

Recientemente me hice cargo de un antiguo proyecto creado hace 10 años. Utiliza MySQL 5.1.

Entre otras cosas, necesito cambiar el conjunto de caracteres predeterminado de latin1 a utf8.

Como ejemplo, tengo tablas como esta:

  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

Configuré mi propia Mac para trabajar en esto. Sin pensarlo demasiado, ejecuté "brew install mysql" que instaló MySQL 5.7. Entonces tengo algunos conflictos de versión.

Descargué una copia de esta base de datos y la importé.

Si intento ejecutar una consulta como esta:

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

Me sale este error:

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

Pensé que podría solucionar esto con:

  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

pero me sale:

  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

¿Tengo que actualizar cada valor?

lorm
fuente

Respuestas:

12

Mi sugerencia si es que la tabla está vacía o no es muy grande es exportar las declaraciones de creación como un archivo .sql, reescribirlas como desee. También haga lo mismo si tiene datos existentes, es decir, exportar instrucciones de inserción (recomiendo hacer esto en un archivo separado como las instrucciones de creación). Finalmente, suelte la tabla y ejecute primero la instrucción create y luego las inserta.

Puede usar ese mysqldumpcomando, incluido en su instalación de MySQL, o también puede instalar MySQL Workbench, que es una herramienta gráfica gratuita que incluye también esta opción de una manera muy personalizable sin tener que buscar opciones de comando específicas.

Lucia Pasarin
fuente
Lucia Pasarin, me gusta mucho tu idea, pero ¿no se truncarán los datos? ¿Algunos datos UTF8 ocupan más bytes que latin1? Si algo encajaba anteriormente en varchar 255, ¿tal vez ahora no? ¿Debería, quizás, cambiar todos los varchars a campos de "texto"?
lorm
Sí, tiene usted razón. Eso podría suceder ya usos latin1 1 byte por carbón, mientras que la mayoría de los usos utf8 en 4 bytes por char (dependiendo de la versión de MySQL y del tipo de utf8 dev.mysql.com/doc/refman/5.5/en/charset-unicode -utf8.html ). Por lo tanto, no necesariamente necesita el tipo de TEXTO. Supongo que x4 sus tamaños existentes anteriormente deberían funcionar.
Lucia Pasarin
Esta es la base de datos equivalente a volver a formatear el disco duro cuando desea eliminar un archivo. Es seguro decir que esta solución no es aceptable en un entorno de producción.
Brandon
198

No pude hacer esto:

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

(en MySQL 5.7.13).

Seguí recibiendo el Incorrect datetime value: '0000-00-00 00:00:00'error.

Curiosamente, esto funcionó: SELECT * FROM users WHERE created = '0000-00-00 00:00:00'. No tengo idea de por qué falla el primero y el último funciona ... ¿tal vez un error de MySQL?

En cualquier caso, esta consulta ACTUALIZACIÓN funcionó:

UPDATE users SET created = NULL WHERE CAST(created AS CHAR(20)) = '0000-00-00 00:00:00'
obe
fuente
13
Tuve el mismo problema, pero establecer la última parte en solo 0 lo solucionó así:UPDATE users SET created = NULL WHERE created = '0'
Brian Leishman
SELECCIONAR * DESDE entityDONDE createdAt = "0000-00-00 00:00:00" funciona bien, ¡pero con un error actualizado! Yo tuve el mismo problema. Solucionarlo con la solución de @obe CAST (creado como CHAR (20)) ... Creo que es un error.
Chrysweel
44
Para mí funcionó como UPDATE users SET created = NULL WHERE created=0(sin 'alrededor de cero)
KIR
1
Para reemplazar una fecha "0000-00-00" solo sin marca de tiempo, utilicé CHAR (11)
D. Fecha
1
Eso es puro genio. ¿Por qué esta no es la respuesta aceptada? Para la fecha solo sin marca de tiempo, el valor mínimo es 1000-01-01. Considere usar esto como el valor predeterminado para cada atributo de fecha que desee dejar en blanco o con el valor de 0000-00-00.
Arvanitis Christos
155

Cambiar el valor predeterminado para una columna con una ALTER TABLEdeclaración, p. Ej.

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

... no cambia ningún valor que ya esté almacenado. El valor "predeterminado" se aplica a las filas que se insertan y para las que no se proporciona un valor para la columna.


En cuanto a por qué te encuentras con el error, es probable que la sql_modeconfiguración de tu sesión incluya NO_ZERO_DATE.

Referencia: http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_zero_date

Cuando hizo la "importación", las instrucciones SQL que hicieron el INSERTAR en esa tabla se ejecutaron en una sesión que permitía cero fechas.

Para ver la configuración sql_mode:

SHOW VARIABLES LIKE 'sql_mode' ;

-o-

SELECT @@sql_mode ;

En cuanto a cómo "solucionar" el problema actual, para que no se arroje el error cuando ejecute la ALTER TABLEinstrucción.

Varias opciones:

1) cambie el sql_modepara permitir fechas cero, eliminando NO_ZERO_DATEy NO_ZERO_IN_DATE. El cambio se puede aplicar en el archivo my.cnf, por lo que después de reiniciar MySQL Server, la sql_modevariable se inicializará en la configuración de my.cnf.

Para un cambio temporal, podemos modificar la configuración con una sola sesión, sin requerir un cambio global.

-- 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) cambie la createdcolumna para permitir valores NULL y actualice las filas existentes para cambiar las fechas cero a valores nulos

3) actualice las filas existentes para cambiar las fechas cero a una fecha válida


No necesitamos ejecutar declaraciones individuales para actualizar cada fila. Podemos actualizar todas las filas de una sola vez (suponiendo que sea una tabla de tamaño razonable. Para una tabla más grande, para evitar la enorme generación de deshacer / deshacer, podemos realizar la operación en trozos de tamaño razonable).

En la pregunta, el AUTO_INCREMENTvalor que se muestra para la definición de la tabla nos asegura que el número de filas no es excesivo.

Si ya hemos cambiado la createdcolumna para permitir NULLvalores, podemos hacer algo como esto:

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

O bien, podemos establecerlos en una fecha válida, por ejemplo, 2 de enero de 1970

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

(Tenga en cuenta que un valor de fecha y hora de la medianoche del 1 de enero de 1970 ( '1970-01-01 00:00:00') es una "fecha cero". Eso se evaluará como'0000-00-00 00:00:00'

spencer7593
fuente
3
Sí, esto funcionó para mí. Busqué el modo sql en el archivo my.ini y eliminé NO_ZERO_IN_DATE y NO_ZERO_DATE. luego reinició el servicio. gracias spencer7593!
mili
Establecer NO_ZERO_DATE: stackoverflow.com/questions/3891896/…
usuario 1007017
Cuando hago # 2 "cambiar la columna creada para permitir valores NULL", no me deja porque los valores de la columna todavía producen el error. Muy atascado.
Mike Weir
1
@MikeWeir: presumiblemente " no me deja " significa que se devuelve un error cuando se ejecuta una instrucción SQL. Eso probablemente se deba a la configuración de sql_mode. Las versiones más recientes de MySQL tienen configuraciones predeterminadas sql_modeque son más estrictas que las versiones anteriores. Referencia de 8,0 aquí: dev.mysql.com/doc/refman/8.0/en/sql-mode.html ver NO_ZERO_DATE, ALLOW_INVALID_DATEet al. tenga en cuenta que algunos están incluidos en el modo ESTRICTO, por ejemplo STRICT_TRANS_TABLES, STRICT_ALL_TABLESy otros modos combinados. Para solucionar las restricciones, modifique temporalmente sql_mode para la sesión,
spencer7593
@ spencer7593 seguro. Tampoco sentí que esa opción fuera la mejor. Seguí su consejo de establecer un valor de fecha muy antiguo (1970) y mi sistema simplemente lo ignorará. Gracias por todos tus detalles.
Mike Weir el
67

Lo solucioné haciendo esto antes de la consulta

SET SQL_MODE='ALLOW_INVALID_DATES';
Tariq Khan
fuente
Esta es la única respuesta. Se utiliza como: --init-command = 'SET SESSION FOREIGN_KEY_CHECKS = 0; SET SQL_MODE =' ALLOW_INVALID_DATES '
Konchog
Muchas gracias. No puedo explicar qué dolor ha sido este problema para mí.
Dieter Gribnitz
42

De acuerdo con el Manual de referencia de MySQL 5.7 :

El modo SQL predeterminado en MySQL 5.7 incluye estos modos: ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER y NO_ENGINE_SUBSTITUTION.

Como 0000-00-00 00:00:00no es un DATETIMEvalor válido , su base de datos está rota. Es por eso que MySQL 5.7, que viene con el NO_ZERO_DATEmodo habilitado de forma predeterminada, genera un error cuando intenta realizar una operación de escritura.

Puede arreglar su tabla actualizando todos los valores no válidos a cualquier otro válido, como NULL:

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

Además, para evitar este problema, le recomiendo que siempre establezca la hora actual como valor predeterminado para sus createdcampos similares, de modo que se completen automáticamente INSERT. Solo haz:

ALTER TABLE users
ALTER created SET DEFAULT CURRENT_TIMESTAMP
Ivan Filho
fuente
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'
Andrew March
fuente
44
Esta respuesta se mejoraría con la discusión de por qué esto resuelve el problema.
KevinO
¿Esto afecta el almacenamiento de fecha y hora? o causar algún problema
Pregunte Bytes
8

Aquí está mi solución PhpMyAdmin / Fedora 29 / MySQL 8.0 (por ejemplo):

set sql_mode='SOMETHING'; no funciona , la llamada de comando se realizó correctamente pero nada fue un cambio.

set GLOBAL sql_mode='SOMETHING'; cambiar la configuración global cambio permanente.

set SESSION sql_mode='SOMETHING'; cambiar la configuración de la sesión La variable SESSION afecta solo al cliente actual.

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

Entonces hago esto:

  • Obtenga SQL_MODE: SHOW VARIABLES LIKE 'sql_mode';
  • Resultado: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
  • Eliminar en el resultado: NO_ZERO_IN_DATE,NO_ZERO_DATE
  • Establecer nueva configuración: set GLOBAL SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'

Puede eliminar o agregar otro modo de la misma manera.

Esto es útil para cambiar globalmente para usar y probar marcos o sql_mode debe especificarse en cada archivo o grupo de consultas.

Adaptado de una pregunta, pregunte aquí: how-can-i-disable-mysql-strictly-mode

Ejemplo: instalar el contenido más reciente de Joomla 4.0-alpha.

Editar: en PhpMyadmin, si tiene el control del servidor, puede cambiar el sql_mode(y todos los demás parámetros) directamente enPlus > Variables > sql_mode

Shim-Sao
fuente
5

Puede cambiar el tipo de creado el campo de datetimea varchar(255), entonces se puede establecer (actualización) todos los registros que tienen el valor "0000-00-00 00:00:00"a NULL.

Ahora, puede hacer sus consultas sin error. Una vez que haya terminado, puede modificar el tipo de campo creado para datetime.

Abdallah Ajlouni
fuente
4

También tengo este error después de actualizar MySQL de 5.6 a 5.7

Descubrí que la mejor solución para mí era combinar algunas de las soluciones aquí y hacer algo que funcionara con el mínimo de entrada.

Utilizo MyPHPAdmin por la simplicidad de enviar las consultas a través de la interfaz porque entonces puedo verificar la estructura y todo eso fácilmente. Puede usar ssh directamente o alguna otra interfaz. El método debe ser similar o igual de todos modos.

...

1)

Primero revise el error real cuando intente reparar el db:

joomla.jos_menu Nota: las columnas TIME / TIMESTAMP / DATETIME del formato anterior se han actualizado al nuevo formato.

Advertencia: valor de fecha y hora incorrecto: '0000-00-00 00:00:00' para la columna 'check_out_time' en la fila 1

Error: valor predeterminado no válido para 'verified_out_time'

estado: operación fallida

Esto me dice que la columna check_out_time en la tabla jos_menu necesita que se arreglen todas las fechas incorrectas y que se cambie el "valor predeterminado".

...

2)

Ejecuto la consulta SQL basada en la información en el mensaje de error:

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

Si obtiene un error, puede usar la consulta a continuación en lugar de que parezca que siempre funciona:

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)

Luego, una vez hecho esto, ejecuto la segunda consulta SQL:

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

O en el caso es una fecha que tiene que ser NULL

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

...

Si ejecuto la base de datos de reparación ahora obtengo:

joomla.jos_menu OK

...

Funciona bien :)

Don Rey
fuente
4

Cheque

SELECT @@sql_mode;

si ve cosas de 'CERO_DATE' allí, intente

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

Cierre sesión y vuelva a iniciar sesión en su cliente (esto es extraño) e intente nuevamente

Pico común
fuente
3

Hacer que el modo sql no sea estricto

si usa laravel, vaya a config-> database, vaya a la configuración de mysql y haga que el modo estricto sea falso

Milind Chaudhary
fuente
¿Puedo hacer esto en myphpadmin?
Don King
phpMyAdmin es solo una interfaz para usar el servidor mysql real, no importa qué interfaz esté usando, los comandos mysql no cambiarán con la interfaz. Pruebe este comando (set sql_mode = '';) o this (set global sql_mode = '';) para desactivarlo.
Milind Chaudhary
1
Sí, encontré que todo lo que se necesita para desactivar el modo estricto es agregar sql_mode = (y nada más), al final de my.cnf
Don King
3

Tuve un problema similar pero en mi caso alguna línea tenía el valor NULL.

así que primero actualizo la tabla:

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

problema resuelto, al menos en mi caso.

Lenon Tolfo
fuente
2

Yo tambien tengo

SQLSTATE [22007]: Formato de fecha y hora no válido: 1292 Valor de fecha y hora incorrecto: '0000-00-00 00:00:00' para la columna

información de error

Solucione esto cambiando 0000-00-00 00:00:00 a 1970-01-01 08:00:00

1970-01-01 08:00:00 la marca de tiempo de unix es 0

tekintian
fuente
1
El problema es que OP no puede cambiar la fecha debido a un error. Creo que es el error deNO_ZERO_DATE
GusDeCooL
2

Encontré la solución en https://support.plesk.com/hc/en-us/articles/115000666509-How-to-change-the-SQL-mode-in-MySQL . Tuve esto:

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)

Observe el NO_ZERO_IN_DATE,NO_ZERO_DATEen los resultados anteriores. Lo eliminé haciendo esto:

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)

Entonces tuve esto:

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)

Después de hacer eso, podría usar con ALTER TABLEéxito y alterar mis tablas.

Jaime Montoya
fuente
1

Esto es lo que hice para resolver mi problema. Probé en MySQL 5.7 local ubuntu 18.04.

set global sql_mode="NO_ENGINE_SUBSTITUTION";

Antes de ejecutar esta consulta globalmente, agregué un archivo cnf en el directorio /etc/mysql/conf.d . El nombre del archivo cnf es mysql.cnf y códigos

[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

Luego reinicio mysql

sudo service mysql restart

Espero que esto pueda ayudar a alguién.

Kalyan Halder Raaz
fuente
Esta solución funciona hasta que reinicie el servidor MySQL. Incluso después del reinicio, el valor NO_ENGINE_SUBSTITUTIONestá en todas las columnas, SELECT @@global.sql_mode, @@session.sql_mode, @@sql_mode;pero sigo recibiendo un error para la fecha 0000-00-00 00:00:00y hora no válida hasta que vuelva a ejecutar la primera consulta ¿ set global sql_mode="NO_ENGINE_SUBSTITUTION";Alguna idea?
Smamatti
La solución en mi caso fue eliminar NO_ZERO_IN_DATE,NO_ZERO_DATEen su versión de la línea my.ini que define el sql_mode.
Smamatti
1

Esto es increíblemente feo, pero también solucionó el problema rápidamente para mí. Su tabla necesita una clave única que usará para arreglar las columnas contaminadas. En este ejemplo, la clave primaria se llama 'id' y la columna de marca de tiempo rota se llama 'BadColumn'.

  1. Seleccione las ID de las columnas contaminadas.

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

  2. Recopile las ID en una cadena delimitada por comas. Ejemplo: 1, 22, 33. Utilicé un contenedor externo para esto (un script de Perl) para escupirlos rápidamente.

  3. Use su lista de ID para actualizar las columnas antiguas con una fecha válida (1971 a 2038).

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

felwithe
fuente
1

Mi solución

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

En vez de

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

Utilizar

UPDATE your_table SET your_column = new_valid_value where your_column = 0;
R2D3
fuente
0

Si está ingresando los datos manualmente, puede considerar eliminar los valores y los ceros en TIMESTAMP (6) .000000 para que se convierta en TIMESTAMP. Eso funcionó bien conmigo.

Isaac
fuente