将现有 MySQL 列更改为 JSON 数据类型

Posted

技术标签:

【中文标题】将现有 MySQL 列更改为 JSON 数据类型【英文标题】:Alter an existing MySQL column to a JSON data type 【发布时间】:2016-10-15 05:16:11 【问题描述】:

我正在尝试将 mysql 列从 varchar(9000) NULL 更改为 MySQL 5.7 中的新 JSON 数据类型。该列包含有效的 JSON 字符串,但某些值为 null。当我尝试以下操作时:

alter table log modify request json

它失败并出现以下错误:

Invalid JSON text: "The document is empty." at position 0 in value for column '#sql-2f36_168a6.request'

但是,当我创建一个新列时:

alter table log add request_json json

然后插入相同的数据:

update log set request_json=json where request != ''

新的 request_json 列已更新。如何将现有列修改为 JSON 数据类型并保留 JSON 数据而不创建新列?

【问题讨论】:

你在NULL'' 之间的专栏有什么不同?运行SELECT `log` FROM `request` WHERE JSON_VALID(`log`)=0\G 来检测那些可能导致问题的行。 我运行了您的查询,发现数百个具有空值或空白值。 NULL 对 json 数据类型无效吗? 所以在玩了一会儿之后,似乎 NULL 是有效的,但有一个空白值是无效的。这是真的吗? 【参考方案1】:

12.6 The JSON Data Type

...

自动验证存储在 JSON 列中的 JSON 文档。无效的文档会产生错误。

...

mysql> SHOW CREATE TABLE `log`\G
*************************** 1. row ***************************
       Table: log
Create Table: CREATE TABLE `log` (
  `request` json DEFAULT NULL
) ENGINE=InnoDB
1 row in set (0,00 sec)

mysql> SELECT `request`, JSON_VALID(`request`)
    -> FROM `log`;
+-----------------+-----------------------+
| request         | JSON_VALID(`request`) |
+-----------------+-----------------------+
| "type": "bug" |                     1 |
| NULL            |                  NULL |
| NULL            |                  NULL |
+-----------------+-----------------------+
3 rows in set (0,00 sec)

mysql> UPDATE `log`
    -> SET `request` = ''
    -> WHERE `request` IS NULL;
ERROR 3140 (22032): Invalid JSON text: "The document is empty." at position 0 in value for column 'log.request'.

试试:

mysql> DROP TABLE IF EXISTS `log`;
Query OK, 0 rows affected (0,00 sec)

mysql> CREATE TABLE IF NOT EXISTS `log` (
    ->   `request` VARCHAR(9000) NULL
    -> );
Query OK, 0 rows affected (0,01 sec)

mysql> INSERT INTO `log`
    ->   (`request`)
    -> VALUES
    ->   ('"type": "bug"'),
    ->   (NULL),
    ->   ('');
Query OK, 3 rows affected (0,00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT `request`, JSON_VALID(`request`)
    -> FROM `log`;
+-----------------+-----------------------+
| request         | JSON_VALID(`request`) |
+-----------------+-----------------------+
| "type": "bug" |                     1 |
| NULL            |                  NULL |
|                 |                     0 |
+-----------------+-----------------------+
3 rows in set (0,00 sec)

mysql> ALTER TABLE `log` MODIFY `request` JSON;
ERROR 3140 (22032): Invalid JSON text: "The document is empty." at position 0 in value for column '#sql-1bab_4.request'.

mysql> UPDATE `log`
    -> SET `request` = NULL
    -> WHERE `request` = '';
Query OK, 1 row affected (0,00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> ALTER TABLE `log` MODIFY `request` JSON;
Query OK, 3 rows affected (0,00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT `request`, JSON_VALID(`request`)
    -> FROM `log`;
+-----------------+-----------------------+
| request         | JSON_VALID(`request`) |
+-----------------+-----------------------+
| "type": "bug" |                     1 |
| NULL            |                  NULL |
| NULL            |                  NULL |
+-----------------+-----------------------+
3 rows in set (0,00 sec)

mysql> SHOW CREATE TABLE `log`\G
*************************** 1. row ***************************
       Table: log
Create Table: CREATE TABLE `log` (
  `request` json DEFAULT NULL
) ENGINE=InnoDB
1 row in set (0,00 sec)

【讨论】:

以上是关于将现有 MySQL 列更改为 JSON 数据类型的主要内容,如果未能解决你的问题,请参考以下文章

Oracle:将 VARCHAR2 列更改为 CLOB

将列更改为常规列而不是外键

MySQL:错误代码:1118 行大小太大(> 8126)。将某些列更改为 TEXT 或 BLOB

当主键列是mysql中不同表的外键时,如何将主键列更改为自动递增

PySpark DataFrame在使用explode之前将字符串的列更改为数组

Liquibase:使用带 H2 数据库的 modifyDataType 重构将 INT 自动增量列更改为 BIGINT