Valore datetime errato di MySQL: '0000-00-00 00:00:00'


155

Recentemente ho rilevato un vecchio progetto creato 10 anni fa. Utilizza MySQL 5.1.

Tra le altre cose, devo cambiare il set di caratteri predefinito da latin1 a utf8.

Ad esempio, ho tabelle come questa:

  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

Ho impostato il mio Mac per lavorare su questo. Senza pensarci troppo, ho eseguito "brew install mysql" che ha installato MySQL 5.7. Quindi ho alcuni conflitti di versione.

Ho scaricato una copia di questo database e l'ho importato.

Se provo a eseguire una query come questa:

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

Ottengo questo errore:

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

Ho pensato di poterlo risolvere 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

ma ottengo:

  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

Devo aggiornare ogni valore?

Risposte:


12

Il mio consiglio se la tabella è vuota o non molto grande è di esportare le istruzioni create come file .sql, riscriverle come si desidera. Fai lo stesso anche se disponi di dati esistenti, ad esempio esporta le istruzioni di inserimento (ti consiglio di farlo in un file separato come le istruzioni di creazione). Infine, rilascia la tabella ed esegui prima l'istruzione create e quindi inserisce.

Puoi usare quel mysqldumpcomando, incluso nell'installazione di MySQL oppure puoi anche installare MySQL Workbench, che è uno strumento grafico gratuito che include anche questa opzione in un modo molto personalizzabile senza dover cercare opzioni di comando specifiche.


Lucia Pasarin, mi piace molto la tua idea, ma i dati non verranno troncati? Alcuni dati UTF8 occupano più byte di latin1? Se qualcosa si adattava precedentemente a varchar 255, forse ora non lo farà? Forse dovrei cambiare tutti i varchar in campi "di testo"?
martedì

Si hai ragione. Ciò potrebbe accadere poiché latin1 utilizza 1 byte per carattere, mentre utf8 utilizza al massimo 4 byte per carattere (a seconda della versione di MySQL e del tipo di utf8 dev.mysql.com/doc/refman/5.5/en/charset-unicode -utf8.html ). Pertanto, non è necessario necessariamente il tipo TEXT. Suppongo che x4 le tue dimensioni precedentemente esistenti dovrebbero funzionare.
Lucia Pasarin,

Questo è l'equivalente del database di riformattare il disco rigido quando si desidera eliminare un file. È sicuro dire che questa soluzione non è accettabile in un ambiente di produzione.
Brandon,

198

Non sono riuscito a farlo:

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

(su MySQL 5.7.13).

Ho continuato a ricevere l' Incorrect datetime value: '0000-00-00 00:00:00'errore.

Stranamente, questo ha funzionato: SELECT * FROM users WHERE created = '0000-00-00 00:00:00'. Non ho idea del motivo per cui il primo fallisce e il secondo funziona ... forse un bug di MySQL?

In ogni caso, questa query UPDATE ha funzionato:

UPDATE users SET created = NULL WHERE CAST(created AS CHAR(20)) = '0000-00-00 00:00:00'

13
Ho avuto lo stesso problema, ma impostando l'ultima parte su 0 è stato risolto per me in questo modo:UPDATE users SET created = NULL WHERE created = '0'
Brian Leishman

SELEZIONA * DA entityDOVE createAt = "0000-00-00 00:00:00" funziona bene, ma con un errore aggiornato! Ho avuto lo stesso problema. Risolvilo con la soluzione di @obe CAST (creato come CHAR (20)) ... Penso che sia un bug.
Chrysweel,

44
Per me ha funzionato come UPDATE users SET created = NULL WHERE created=0(senza "intorno allo zero)
KIR

1
Per sostituire una data di "registrazione" solo senza timestamp, ho usato CHAR (11)
D.Tate

1
Questo è puro genio. Perché questa non è la risposta accettata? Per la data solo senza timestamp il valore minimo è 1000-01-01. Prendi in considerazione l'idea di utilizzarlo come valore predefinito per ogni attributo della data che intendi lasciare vuoto o con valore di registrazione.
Arvanitis Christos,

155

Modifica del valore predefinito per una colonna con ALTER TABLEun'istruzione, ad es

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

... non modifica alcun valore già memorizzato. Il valore "predefinito" si applica alle righe inserite e per le quali non viene fornito un valore per la colonna.


Per quanto riguarda il motivo per cui si verifica l'errore, è probabile che l' sql_modeimpostazione per la sessione includa NO_ZERO_DATE.

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

Quando hai effettuato "l'importazione", le istruzioni SQL che hanno eseguito INSERT in quella tabella sono state eseguite in una sessione che consentiva zero date.

Per vedere l'impostazione sql_mode:

SHOW VARIABLES LIKE 'sql_mode' ;

-o-

SELECT @@sql_mode ;

Per quanto riguarda come "risolvere" il problema attuale, in modo che l'errore non venga generato quando si esegue l' ALTER TABLEistruzione.

Diverse opzioni:

1) modificare il sql_modeper consentire zero date, rimuovendo NO_ZERO_DATEe NO_ZERO_IN_DATE. La modifica può essere applicata nel file my.cnf, quindi dopo un riavvio di MySQL Server, la sql_modevariabile verrà inizializzata all'impostazione in my.cnf.

Per una modifica temporanea, possiamo modificare l'impostazione con una singola sessione, senza richiedere una modifica globale.

-- 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) modifica la createdcolonna per consentire i valori NULL e aggiorna le righe esistenti per modificare le date zero in valori null

3) aggiorna le righe esistenti per modificare le date zero in una data valida


Non è necessario eseguire singole istruzioni per aggiornare ogni riga. Possiamo aggiornare tutte le righe in un colpo solo (supponendo che sia una tabella di dimensioni ragionevoli. Per una tabella più grande, per evitare un'enorme generazione di rollback / annullamento, possiamo eseguire l'operazione in blocchi di dimensioni ragionevoli.)

Nella domanda, il AUTO_INCREMENTvalore mostrato per la definizione della tabella ci assicura che il numero di righe non è eccessivo.

Se abbiamo già modificato la createdcolonna per consentire i NULLvalori, possiamo fare qualcosa del genere:

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

Oppure, possiamo impostarli su una data valida, ad esempio il 2 gennaio 1970

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

(Si noti che un valore datetime di mezzanotte del 1 gennaio 1970 ( '1970-01-01 00:00:00') è una "data zero". Tale valore verrà valutato come'0000-00-00 00:00:00'


3
sì, questo ha funzionato per me. Ho cercato la modalità sql nel file my.ini e ho rimosso NO_ZERO_IN_DATE e NO_ZERO_DATE. quindi riavviato il servizio. grazie spencer7593!
mili,


Quando faccio # 2 "cambio la colonna creata per consentire i valori NULL", non mi permette perché i valori della colonna producono ancora l'errore. Abbastanza bloccato.
Mike Weir,

1
@MikeWeir: presumibilmente " non mi lascerà " significa che viene restituito un errore quando viene eseguita un'istruzione SQL. Ciò è probabilmente dovuto all'impostazione di sql_mode. Le versioni più recenti di MySQL hanno impostazioni predefinite sql_modepiù rigorose rispetto alle versioni precedenti. Riferimento per 8,0 qui: dev.mysql.com/doc/refman/8.0/en/sql-mode.html See NO_ZERO_DATE, ALLOW_INVALID_DATE, et al. notare che alcuni sono inclusi nella modalità STRICT, ad esempio STRICT_TRANS_TABLES, STRICT_ALL_TABLESe altre modalità combo. Per ovviare alle restrizioni, modificare temporaneamente sql_mode per la sessione,
spencer7593

@ spencer7593 di sicuro. Non pensavo che neanche quella fosse la migliore. Ho seguito il tuo consiglio di impostare un valore di data molto vecchio (1970) e il mio sistema lo ignorerà. Grazie per tutti i tuoi dettagli.
Mike Weir,

67

L'ho risolto facendo questo prima della query

SET SQL_MODE='ALLOW_INVALID_DATES';

Questa è l'unica risposta Utilizzato come: --init-command = 'SET SESSION FOREIGN_KEY_CHECKS = 0; SET SQL_MODE =' ALLOW_INVALID_DATES '
Konchog

Grazie mille. Non riesco a spiegare che dolore questo problema è stato per me.
Dieter Gribnitz,

42

Secondo il Manuale di riferimento di MySQL 5.7 :

La modalità SQL predefinita in MySQL 5.7 include queste modalità: ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER e NO_ENGINE_SUBST.

Poiché 0000-00-00 00:00:00non è un DATETIMEvalore valido , il database è danneggiato. Ecco perché MySQL 5.7, che viene fornito con la NO_ZERO_DATEmodalità abilitata per impostazione predefinita, genera un errore quando si tenta di eseguire un'operazione di scrittura.

Puoi correggere la tua tabella aggiornando tutti i valori non validi con qualsiasi altro valido, come NULL:

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

Inoltre, per evitare questo problema, ti consiglio di impostare sempre l'ora corrente come valore predefinito per i tuoi createdcampi simili, in modo che vengano riempiti automaticamente INSERT. Basta fare:

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
Questa risposta sarebbe migliorata con la discussione del perché questo risolve il problema.
KevinO,

questo influisce sull'archiviazione del datetime.? o causare problemi
Chiedi a Bytes il

8

Ecco la mia soluzione PhpMyAdmin / Fedora 29 / MySQL 8.0 (ad esempio):

set sql_mode='SOMETHING'; non funziona , la chiamata di comando ha esito positivo ma nulla è cambiato.

set GLOBAL sql_mode='SOMETHING'; cambia la configurazione globale modifica permanente.

set SESSION sql_mode='SOMETHING'; cambia configurazione sessione La variabile SESSION ha effetto solo sul client corrente.

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

Quindi faccio questo:

  • Ottieni SQL_MODE: SHOW VARIABLES LIKE 'sql_mode';
  • Risultato: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
  • Rimuovi dal risultato: NO_ZERO_IN_DATE,NO_ZERO_DATE
  • Imposta nuova configurazione: set GLOBAL SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'

Puoi rimuovere o aggiungere un'altra modalità allo stesso modo.

Questo è utile per cambiare globale per l'utilizzo e il test di framework o sql_mode deve essere specificato in ogni file o gruppo di query.

Adattato da una domanda fai qui: how-can-i-disable-mysql-strict-mode

Esempio: installa l'ultimo contenuto di Joomla 4.0-alpha.

Modifica: in PhpMyadmin, se hai il controllo del server, puoi modificare sql_mode(e tutti gli altri parametri) direttamente inPlus > Variables > sql_mode


5

Puoi cambiare il tipo di campo creato da datetimea varchar(255), quindi puoi impostare (aggiornare) tutti i record che hanno il valore "0000-00-00 00:00:00"su NULL.

Ora puoi fare le tue domande senza errori. Al termine, è possibile modificare il tipo di campo creato in datetime.


4

Ho questo errore anche dopo aver aggiornato MySQL dalla 5.6 alla 5.7

Ho capito che la soluzione migliore per me era combinare alcune delle soluzioni qui e farne qualcosa che funzionasse con il minimo di input.

Uso MyPHPAdmin per la semplicità di invio delle query tramite l'interfaccia perché in questo modo posso controllare facilmente la struttura e tutto il resto. È possibile utilizzare ssh direttamente o un'altra interfaccia. Il metodo dovrebbe essere simile o uguale comunque.

...

1.

Per prima cosa controlla l'errore reale quando provi a riparare il db:

joomla.jos_menu Nota: le colonne TIME / TIMESTAMP / DATETIME del vecchio formato sono state aggiornate al nuovo formato.

Avviso: valore datetime errato: '0000-00-00 00:00:00' per la colonna 'checked_out_time' alla riga 1

Errore: valore predefinito non valido per "checked_out_time"

stato: operazione fallita

Questo mi dice che la colonna checked_out_time nella tabella jos_menu deve avere tutte le date errate riparate e il "default" modificato.

...

2.

Eseguo la query SQL in base alle informazioni nel messaggio di errore:

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

Se viene visualizzato un errore, è possibile utilizzare la query seguente che sembra funzionare sempre:

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.

Quindi, una volta fatto, eseguo la seconda query SQL:

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

O nel caso sia una data che deve essere NULL

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

...

Se eseguo il database di riparazione ora ottengo:

joomla.jos_menu OK

...

Funziona bene :)


4

Dai un'occhiata

SELECT @@sql_mode;

se vedi "ZERO_DATE", prova

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

Esci e accedi nuovamente al tuo client (è strano) e riprova


3

Rendi la modalità sql non rigorosa

se usando laravel vai su config-> database, vai su mysql settings e rendi falsa la modalità rigorosa


Posso farlo in myphpadmin?
Don King,

phpMyAdmin è solo un'interfaccia per usare l'attuale server mysql, non importa quale interfaccia stai usando i comandi mysql non cambieranno con l'interfaccia. Prova questo comando (set sql_mode = '';) o questo (imposta sql_mode = '';) globale per disattivarlo.
Milind Chaudhary,

1
sì, ho scoperto che tutto ciò che è necessario per disattivare la modalità rigorosa è l'aggiunta di sql_mode = (e niente dopo), in fondo a my.cnf
Don King,

3

Ho avuto un problema simile ma nel mio caso alcune righe avevano il valore NULL.

quindi prima aggiorno la tabella:

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

problema risolto, almeno nel mio caso.


2

Ho anche avuto

SQLSTATE [22007]: Formato datetime non valido: 1292 Valore datetime errato: '0000-00-00 00:00:00' per colonna

informazioni sull'errore

Risolvi il problema cambiando 0000-00-00 00:00:00 in 1970-01-01 08:00:00

1970-01-01 08:00:00 il timestamp unix è 0


1
il problema è che OP non può modificare la data a causa di un errore. Immagino che sia un errore diNO_ZERO_DATE
GusDeCooL l'

2

Ho trovato la soluzione su https://support.plesk.com/hc/en-us/articles/115000666509-How-to-change-the-SQL-mode-in-MySQL . Ho avuto questo:

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)

Si noti il NO_ZERO_IN_DATE,NO_ZERO_DATEnei risultati sopra. L'ho rimosso facendo questo:

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)

Quindi ho avuto questo:

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)

Dopo averlo fatto, ho potuto usare ALTER TABLEcon successo e modificare le mie tabelle.


1

Questo è quello che ho fatto per risolvere il mio problema. Ho provato in MySQL 5.7 Ubuntu 18.04 locale.

set global sql_mode="NO_ENGINE_SUBSTITUTION";

Prima di eseguire questa query a livello globale, ho aggiunto un file cnf nella directory /etc/mysql/conf.d . Il nome del file cnf è mysql.cnf e codici

[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

Quindi riavvio mysql

sudo service mysql restart

Spero che questo possa aiutare qualcuno.


Questa soluzione funziona finché non riavvio il server MySQL. Anche dopo il riavvio il valore NO_ENGINE_SUBSTITUTIONè presente in tutte le colonne SELECT @@global.sql_mode, @@session.sql_mode, @@sql_mode;ma ricevo ancora un errore per il datetime non valido 0000-00-00 00:00:00fino a quando non eseguo nuovamente la prima query set global sql_mode="NO_ENGINE_SUBSTITUTION";Qualche idea?
Smamatti,

La soluzione nel mio caso è stata quella di rimuovere NO_ZERO_IN_DATE,NO_ZERO_DATEnella tua versione della linea my.ini che definisce il file sql_mode.
Smamatti,

1

Questo è incredibilmente brutto, ma ha anche risolto rapidamente il problema per me. La tua tabella ha bisogno di una chiave univoca che utilizzerai per correggere le colonne contaminate. In questo esempio, la chiave primaria si chiama 'id' e la colonna timestamp non funzionante si chiama 'BadColumn'.

  1. Seleziona gli ID delle colonne contaminate.

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

  2. Raccogliere gli ID in una stringa delimitata da virgole. Esempio: 1, 22, 33. Ho usato un wrapper esterno per questo (uno script Perl) per sputarli rapidamente tutti.

  3. Usa il tuo elenco di ID per aggiornare le vecchie colonne con una data valida (dal 1971 al 2038).

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


1

La mia soluzione

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

1

Invece di

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

Uso

UPDATE your_table SET your_column = new_valid_value where your_column = 0;

0

Se si inseriscono i dati manualmente, è possibile prendere in considerazione la rimozione dei valori e degli zeri sul TIMESTAMP (6) .000000 in modo che diventi TIMESTAMP. Ha funzionato bene con me.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.