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 5.7をインストールする「brew install mysql」を実行しました。だから私はいくつかのバージョンの競合があります。

このデータベースのコピーをダウンロードしてインポートしました。

次のようなクエリを実行しようとすると、

  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

テーブルが空であるか、それほど大きくない場合は、createステートメントを.sqlファイルとしてエクスポートし、必要に応じて書き換えてください。既存のデータがある場合、つまりエクスポート挿入ステートメントも同じようにします(これを作成ステートメントとして別のファイルで行うことをお勧めします)。最後に、テーブルをドロップし、最初のcreateステートメントを実行してから挿入します。

mysqldumpMySQLインストールに含まれているそのコマンドのいずれかを使用することも、MySQL Workbenchをインストールすることもできます。これは、特定のコマンドオプションを探すことなく、非常にカスタマイズ可能な方法でこのオプションを含む無料のグラフィカルツールです。


ルシア・パサリン、私はあなたの考えがとても好きですが、データは切り捨てられませんか?一部のUTF8データは、latin1よりも多くのバイトを使用しますか?以前に何かがvarchar 255に収まれば、おそらく今は収まらないでしょうか?おそらく、すべてのvarcharを「テキスト」フィールドに変更する必要がありますか?
16

はい、そうです。これは、latin1が文字ごとに1バイトを使用するために発生する可能性がありますが、utf8は文字ごとに最大4バイトを使用します(MySQLのバージョンとutf8のタイプによって異なりますdev.mysql.com/doc/refman/5.5/en/charset-unicode -utf8.html)。したがって、必ずしもTEXTタイプは必要ありません。私はあなたの既存のサイズのx4が動作するはずだと思います。
Lucia Pasarin

これは、ファイルを削除するときにハードドライブを再フォーマットするのと同等のデータベースです。このソリューションは、実稼働環境では受け入れられないと言っても安全です。
ブランドン

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 createdAt = "0000-00-00 00:00:00"は正常に機能しますが、更新が失敗します!私も同じ問題を抱えていました。@obe CAST(created AS 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の値を使用するすべての日付属性のデフォルト値としてこれを使用することを検討してください。
Arvanitis Christos

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

「インポート」を実行すると、そのテーブルへのINSERTを実行したSQLステートメントが、ゼロ日付を許可するセッションで実行されました。

sql_mode設定を表示するには:

SHOW VARIABLES LIKE 'sql_mode' ;

-または-

SELECT @@sql_mode ;

現在の問題を「修正」する方法に関する限り、ALTER TABLEステートメントを実行したときにエラーがスローされないようにします。

いくつかのオプション:

1)およびsql_modeを削除して、ゼロ日付を許可するようにを変更します。変更はmy.cnfファイルに適用できるため、MySQLサーバーの再起動後、変数はmy.cnfの設定に初期化されます。NO_ZERO_DATENO_ZERO_IN_DATEsql_mode

一時的な変更の場合、グローバルな変更を必要とせずに、1つのセッションで設定を変更できます。

-- 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値を許可し、既存の行を更新してゼロ日付をNULL値に変更します

3)既存の行を更新してゼロ日付を有効な日付に変更します


各行を更新するために個々のステートメントを実行する必要はありません。すべての行を一度に更新できます(適切なサイズのテーブルであると想定しています。大きなテーブルの場合、巨大なロールバック/取り消しの生成を避けるために、適切なサイズのチャンクで操作を実行できます。)

質問ではAUTO_INCREMENT、テーブル定義に示されている値により、行数が過剰にならないことが保証されます。

createdを使用できるように列をすでに変更している場合はNULL、次のようにすることができます。

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

または、これらを有効な日付に設定することもできます。たとえば、1970年1月2日

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

(1970年1月1日の午前0時の日付時刻値('1970-01-01 00:00:00'「ゼロ日付」であることに注意してください。'0000-00-00 00:00:00'


3
はい、これでうまくいきました。my.iniファイルでsql-modeを検索し、NO_ZERO_IN_DATEおよびNO_ZERO_DATEを削除しました。その後、サービスを再起動しました。スペンサー7593ありがとう!
mili


#2「作成された列を変更してNULL値を許可する」を実行しても、列の値がまだエラーを生成するため、許可されません。かなり立ち往生。
Mike Weir

1
@MikeWeir:おそらく「私を許可しない」とは、SQLステートメントが実行されたときにエラーが返されることを意味します。の設定が原因である可能性がありますsql_mode。MySQLの最新バージョンにはsql_mode、以前のバージョンよりも厳しいデフォルト設定があります。ここでは8.0のリファレンス:dev.mysql.com/doc/refman/8.0/en/sql-mode.html 参照NO_ZERO_DATEALLOW_INVALID_DATEら、。いくつかは、STRICTモードなどに含まれていることに注意してくださいSTRICT_TRANS_TABLESSTRICT_ALL_TABLESと他のコンボモード。制限を回避するには、セッションのsql_modeを一時的に変更します
spencer7593

確かに@ spencer7593。そのオプションも最高だとは思わなかった。非常に古い日付値(1970)を設定するというアドバイスをいただきましたが、私のシステムでは無視されます。すべての詳細をありがとう。
マイク・ウィアー

67

クエリの前にこれを行うことで修正しました

SET SQL_MODE='ALLOW_INVALID_DATES';

これが唯一の答えです。使用方法:--init-command = 'SET SESSION FOREIGN_KEY_CHECKS = 0; SET SQL_MODE =' ALLOW_INVALID_DATES '
Konchog

どうもありがとうございます。この問題が私にとってどのような苦痛であったか説明できません。
Dieter Gribnitz

42

MySQL 5.7リファレンスマニュアルによると:

MySQL 5.7のデフォルトのSQLモードには、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のモードが含まれます。

0000-00-00 00:00:00は有効なDATETIME値ではないため、データベースが壊れています。そのためNO_ZERO_DATE、デフォルトで有効になっているモードが付属しているMySQL 5.7 では、書き込み操作を実行しようとするとエラーが出力されます。

すべての無効な値を更新するテーブルを修正して、次のような他の有効な値に更新できます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 2018

これは日時ストレージに影響しますか?または問題を引き起こす
Bytes

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


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列は、新しい形式にアップグレードされました。

警告:不正な日時値:行1の列 'checked_out_time'の '0000-00-00 00:00:00'

エラー:「checked_out_time」のデフォルト値が無効です

ステータス:操作に失敗しました

これは、テーブルjos_menuのカラムchecked_out_timeがすべての不正な日付を修正し、「デフォルト」が変更されている必要があることを示しています。

...

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。

その後、2番目の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 OK

...

うまく動作します:)


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を使用している場合は、config-> databaseに移動し、mysql設定に移動して、strictモードをfalseにします。


これをmyphpadminで実行できますか?
Don King

phpMyAdminは実際のmysqlサーバーを使用するための単なるインターフェースであり、mysqlコマンドを使用しているインターフェースがインターフェースによって変更されないことは問題ではありません。このコマンド(set sql_mode = '';)またはこれ(set sql_mode = '';)を試して、無効にしてください。
Milind Chaudhary

1
ええ、ストリクトモードをオフにするために必要なすべてのことは、my.cnfの下部にsql_mode =(およびその後は何もない)を追加することでした
Don King

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:001970-01-01 08:00:00

1970-01-01 08:00:00 UNIXタイムスタンプは0です


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";

このクエリをグローバルに実行する前に、/ etc / mysql / conf.dディレクトリにcnfファイルを追加しました 。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でした。
Smamatti

1

これは信じられないほど醜いですが、私にとっても問題はすぐに修正されました。テーブルには、汚染された列を修正するために使用する一意のキーが必要です。この例では、主キーは「id」と呼ばれ、壊れたタイムスタンプ列は「BadColumn」と呼ばれます。

  1. 汚染された列のIDを選択します。

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

  2. IDをカンマ区切りの文字列に収集します。例:1, 22, 33。私はこれに外部ラッパー(Perlスクリプト)を使用して、それらすべてをすばやく吐き出しました。

  3. IDのリストを使用して、古い列を有効な日付(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にすることを検討してください。それでうまくいきました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.