web-dev-qa-db-ja.com

「null」が原因で、CAST(meta->> "$。field")を使用したUPDATEが失敗する

この問題はMySQL 5.7.25に影響しています。

そのため、移行では、レガシーフィールドをテーブルからJSON列に移動します。プロセスのこの部分は正常に機能します。しかし、ロールバックは無残に失敗しています!この時点で、JSONフィールドロジックをSQLからPHPに移動することを検討しています。

次のように問題を再現できます。

DBセットアップ

_CREATE TABLE `test_table` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `meta` json DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `test_table` VALUES
(null, '{"test_dt": "2019-03-28 15:43:59", "test_enum": "foo"}'),
(null, '{"test_dt": "2019-03-28 15:44:15", "test_enum": null}'),
(null, '{"test_dt": null, "test_enum": "bar"}');

ALTER TABLE `test_table`
  ADD COLUMN `test_enum` ENUM('foo', 'bar') NOT NULL DEFAULT 'foo',
  ADD COLUMN `test_dt` DATETIME NULL;
_

問題

次のクエリの回避策はありますか?可能であれば、更新クエリを1つだけにすることをお勧めします...

_-- copy from meta back into legacy fields
UPDATE `test_table` SET
  `test_enum` = `meta`->>"$.test_enum",
  `test_dt` = CAST(`meta`->>"$.test_dt" AS DATETIME);
_

行2はエラーになります:_Data truncated for column 'test_enum'_。これは、_meta->>"$.test_enum"_とJSON_EXTRACT(meta, "$.test_enum")の両方がNULLではなく_"null"_を返すためと思われます。

Enumフィールドを更新せずにもう一度試してください。

_-- copy from meta back into legacy fields
UPDATE `test_table` SET
  `test_dt` = CAST(`meta`->>"$.test_dt" AS DATETIME);
_

行3でエラーが発生するようになりました:_Incorrect datetime value: 'null'_

クエリを次のように2つに分割すると、エラーを回避できます。

_UPDATE test_table 
SET test_enum = `meta`->>"$.test_enum" 
WHERE JSON_TYPE(JSON_EXTRACT(`meta`, "$.test_enum")) != 'NULL';

UPDATE test_table 
SET test_dt = `meta`->>"$.test_dt" 
WHERE JSON_TYPE(JSON_EXTRACT(`meta`, "$.test_dt")) != 'NULL';
_

錯乱

_"null"_値のためにENUM関連の列が無効であっても、CASTを介してデータをSELECTすることは正常に機能します。 JSON_EXTRACT()がNULLを正しく返さないのはなぜですか?

_SELECT
  `meta`->>"$.test_enum" AS `test_enum`,
  CAST(`meta`->>"$.test_dt" AS DATETIME) AS `test_dt`
  FROM test_table
_
_"id","test_enum","test_dt"
1,"foo","2019-03-28 15:43:59"
2,"null","2019-03-28 15:44:15"
3,"bar",NULL
_

現在、MySQLがJSONとCAST/CONVERTメソッドの両方でNULL処理を使用してこのように動作するのはなぜですか。私は明らかな何かを見逃しているように感じます。

3
Robert K

バグだと思います。 MySQL開発者ゾーンでそのようなバグレポートを見つけることができないので、報告してください。

1
user126897

string _"2019-03-28 15:43:59"_は、DATETIMEのように見え、動作します。 CAST()を使用しないでください。

NULLNULL値ではなく、_"NULL"_は4文字の文字列ですか?つまり、あなたはヌルセルに働きすぎているのですか?

0
Rick James