web-dev-qa-db-ja.com

JSONからのMySQL一時テーブルの挿入はnull値を処理できません

MySql-8 JSON_TABLE function を使用すると、JSONデータをテーブルのように処理できます。

これを使用して、生成されたテーブルを使用して一時テーブルにデータを入力しようとしていますが、バグが発生していると思います。

Null値がINT NULL列に挿入されると、次のエラーがスローされます:Invalid JSON value for CAST to INTEGER from column quantity at row 1

これが問題のコードです

DROP TABLE IF EXISTS json_temp_table;
CREATE TEMPORARY TABLE json_temp_table (
  item_id int NOT NULL PRIMARY KEY,
  model_number varchar(100),
  quantity int NULL
)
ENGINE = INNODB
SELECT
  json_tb.item_id,
  json_tb.model_number,
  json_tb.quantity
FROM JSON_TABLE
(
'[{"item_id":1,"model_number":"MFJA53","quantity":4},{"item_id":2,"model_number":"HSRHJN5","quantity":null},{"item_id":3,"model_number":"FAFAF1","quantity":345}]'
, "$[*]"
COLUMNS
(
item_id int PATH "$.item_id",
model_number varchar(100) PATH "$.model_number",
quantity int PATH "$.quantity"
)
) json_tb;
SELECT
  *
FROM json_temp_table

Jsonで生成されたテーブルで一時テーブルにnullを挿入する方法はありますか?

奇妙な部分は、selectステートメントが挿入なしで正常に機能することです。また、一時テーブル自体は間違いなくnull int値を処理できます。これら2つが混ざらない理由がわかりません。

3
A_V

解決策は、nullにするプロパティを省略することです。

しばらく検索したところ、1年以上前に このバグレポート が見つかりました。これは、値NULLを含むjson文字列が実際には値であり、nullではないことを説明しています。

{"item":1,"quantity":4}->アイテム= 1、数量= 4

{"item":1,"quantity":null}->アイテム= 1、数量= 'null'(ある種の不親切なjson null)

{"item":1}->アイテム= 1、数量= NULL(古き良きSQLのnull!)

これを見た後、「この非友好的なjson nullをNice nullにキャストする方法があるはずだ」と思いました。うまくいったことをたくさん試しましたが、一時テーブルに挿入できるものはありませんでした。

これは私の上で述べたことに基づいて、うまくいくはずの私の最後の試みでした。インラインのIFステートメントを使用して値がnullであるかどうかを検出し、実際のSQL NULLSIGNED intにキャストしようとしています。値を選択する方法を示しますが、何らかの理由で値を挿入することは不可能です。

コード自体:

DROP TABLE IF EXISTS json_temp_table;
CREATE TEMPORARY TABLE json_temp_table (
  item_id int NOT NULL PRIMARY KEY,
  model_number varchar(100),
  quantity int NULL
)
ENGINE = INNODB;

INSERT INTO json_temp_table
SELECT X.item_id,X.model_number,CAST(IF(x.quantity_is_null=1,NULL, X.quantity) AS SIGNED) 'quantity' FROM (
SELECT
  json_tb.item_id,
  json_tb.model_number,
  json_tb.quantity,
  if(json_type(json_extract(JSON_OBJECT('b',json_tb.quantity),'$.b')) = 'NULL',1 ,0) 'quantity_is_null'
FROM JSON_TABLE
(
'[{"item_id":1,"model_number":"MFJA53","quantity":4},{"item_id":2,"model_number":"HSRHJN5","quantity":null},{"item_id":3,"model_number":"FAFAF1","quantity":345}]'
, "$[*]"
COLUMNS
(
item_id int PATH "$.item_id",
model_number varchar(100) PATH "$.model_number",
quantity int PATH "$.quantity"
)
) json_tb) x;

CLI mysqlクライアントで実行

mysql> DROP TABLE IF EXISTS json_temp_table;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> CREATE TEMPORARY TABLE json_temp_table (
    ->   item_id int NOT NULL PRIMARY KEY,
    ->   model_number varchar(100),
    ->   quantity int NULL
    -> )
    -> ENGINE = INNODB;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT X.item_id,X.model_number,CAST(IF(x.quantity_is_null=1,NULL, X.quantity) AS SIGNED) 'quantity' FROM (
    -> SELECT
    ->   json_tb.item_id,
    ->   json_tb.model_number,
    ->   json_tb.quantity,
    ->   if(json_type(json_extract(JSON_OBJECT('b',json_tb.quantity),'$.b')) = 'NULL',1 ,0) 'quantity_is_null'
    -> FROM JSON_TABLE
    -> (
    -> '[{"item_id":1,"model_number":"MFJA53","quantity":4},{"item_id":2,"model_number":"HSRHJN5","quantity":null},{"item_id":3,"model_number":"FAFAF1","quantity":345}]'
    -> , "$[*]"
    -> COLUMNS
    -> (
    -> item_id int PATH "$.item_id",
    -> model_number varchar(100) PATH "$.model_number",
    -> quantity int PATH "$.quantity"
    -> )
    -> ) json_tb) x;
+---------+--------------+----------+
| item_id | model_number | quantity |
+---------+--------------+----------+
|       1 | MFJA53       |        4 |
|       2 | HSRHJN5      |     NULL |
|       3 | FAFAF1       |      345 |
+---------+--------------+----------+
3 rows in set, 1 warning (0.00 sec)

mysql> INSERT INTO json_temp_table
    -> SELECT X.item_id,X.model_number,CAST(IF(x.quantity_is_null=1,NULL, X.quantity) AS SIGNED) 'quantity' FROM (
    -> SELECT
    ->   json_tb.item_id,
    ->   json_tb.model_number,
    ->   json_tb.quantity,
    ->   if(json_type(json_extract(JSON_OBJECT('b',json_tb.quantity),'$.b')) = 'NULL',1 ,0) 'quantity_is_null'
    -> FROM JSON_TABLE
    -> (
    -> '[{"item_id":1,"model_number":"MFJA53","quantity":4},{"item_id":2,"model_number":"HSRHJN5","quantity":null},{"item_id":3,"model_number":"FAFAF1","quantity":345}]'
    -> , "$[*]"
    -> COLUMNS
    -> (
    -> item_id int PATH "$.item_id",
    -> model_number varchar(100) PATH "$.model_number",
    -> quantity int PATH "$.quantity"
    -> )
    -> ) json_tb) x;
ERROR 3156 (22018): Invalid JSON value for CAST to INTEGER from column quantity at row 1
mysql>
2
A_V