Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  ...  /  JSON Utility Functions

14.17.8 JSON 实用函数

本节记录了对 JSON 值或可以解析为 JSON 值的字符串进行操作的实用函数。JSON_PRETTY() 以易于阅读的格式打印出 JSON 值。JSON_STORAGE_SIZE()JSON_STORAGE_FREE() 分别显示给定 JSON 值的存储空间使用量和在部分更新后 JSON 列中的剩余空间。

  • JSON_PRETTY(json_val)

    提供类似 PHP 和其他语言和数据库系统中实现的 JSON 值的漂亮打印。提供的值必须是 JSON 值或有效的 JSON 字符串表示形式。在该值中存在的额外空格和换行符对输出没有影响。对于 NULL 值,该函数返回 NULL。如果值不是 JSON 文档,或者无法解析为 JSON 文档,该函数将失败并抛出错误。

    该函数的输出格式遵循以下规则:

    • 每个数组元素或对象成员都显示在单独的一行上,相比其父级缩进一个级别。

    • 每个缩进级别添加两个前导空格。

    • 分隔单个数组元素或对象成员的逗号将在分隔两个元素或成员的换行符之前打印。

    • 对象成员的键和值之间用冒号和空格(': ')分隔。

    • 空对象或数组将在单行上打印。不会在开括号和闭括号之间打印空格。

    • 字符串标量和键名中的特殊字符使用与 JSON_QUOTE() 函数相同的规则进行转义。

    mysql> SELECT JSON_PRETTY('123'); # scalar
    +--------------------+
    | JSON_PRETTY('123') |
    +--------------------+
    | 123                |
    +--------------------+
    
    mysql> SELECT JSON_PRETTY("[1,3,5]"); # array
    +------------------------+
    | JSON_PRETTY("[1,3,5]") |
    +------------------------+
    | [
      1,
      3,
      5
    ]      |
    +------------------------+
    
    mysql> SELECT JSON_PRETTY('{"a":"10","b":"15","x":"25"}'); # object
    +---------------------------------------------+
    | JSON_PRETTY('{"a":"10","b":"15","x":"25"}') |
    +---------------------------------------------+
    | {
      "a": "10",
      "b": "15",
      "x": "25"
    }   |
    +---------------------------------------------+
    
    mysql> SELECT JSON_PRETTY('["a",1,{"key1":
        '>    "value1"},"5",     "77" ,
        '>       {"key2":["value3","valueX",
        '> "valueY"]},"j", "2"   ]')\G  # nested arrays and objects
    *************************** 1. row ***************************
    JSON_PRETTY('["a",1,{"key1":
                 "value1"},"5",     "77" ,
                    {"key2":["value3","valuex",
              "valuey"]},"j", "2"   ]'): [
      "a",
      1,
      {
        "key1": "value1"
      },
      "5",
      "77",
      {
        "key2": [
          "value3",
          "valuex",
          "valuey"
        ]
      },
      "j",
      "2"
    ]
  • JSON_STORAGE_FREE(json_val)

    对于 JSON 列值,该函数显示在使用 JSON_SET()JSON_REPLACE()JSON_REMOVE() 更新后释放的存储空间。如果参数是有效的 JSON 文档或可以解析为 JSON 的字符串,则函数返回 0。如果参数是 JSON 列值,并且在更新后其二进制表示形式所占用的空间小于更新前,则函数返回正整数值;否则,如果更新没有释放空间或更新未能使用部分更新,则函数返回 0;如果参数为 NULL,则函数返回 NULL

    如果 json_val 不是 NULL,且既不是有效的 JSON 文档也不能成功解析为 JSON 文档,则会抛出错误。

    在这个示例中,我们创建了一个包含 JSON 列的表,然后插入了一行包含 JSON 对象的数据:

    mysql> CREATE TABLE jtable (jcol JSON);
    Query OK, 0 rows affected (0.38 sec)
    
    mysql> INSERT INTO jtable VALUES
        ->     ('{"a": 10, "b": "wxyz", "c": "[true, false]"}');
    Query OK, 1 row affected (0.04 sec)
    
    mysql> SELECT * FROM jtable;
    +----------------------------------------------+
    | jcol                                         |
    +----------------------------------------------+
    | {"a": 10, "b": "wxyz", "c": "[true, false]"} |
    +----------------------------------------------+
    1 row in set (0.00 sec)

    现在,我们使用 JSON_SET() 更新该列值,以便执行部分更新;在这种情况下,我们将键为 c 的值(数组 [true, false])替换为占用空间较小的整数 1

    mysql> UPDATE jtable
        ->     SET jcol = JSON_SET(jcol, "$.a", 10, "$.b", "wxyz", "$.c", 1);
    Query OK, 1 row affected (0.03 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    mysql> SELECT * FROM jtable;
    +--------------------------------+
    | jcol                           |
    +--------------------------------+
    | {"a": 10, "b": "wxyz", "c": 1} |
    +--------------------------------+
    1 row in set (0.00 sec)
    
    mysql> SELECT JSON_STORAGE_FREE(jcol) FROM jtable;
    +-------------------------+
    | JSON_STORAGE_FREE(jcol) |
    +-------------------------+
    |                      14 |
    +-------------------------+
    1 row in set (0.00 sec)

    连续的部分更新对自由空间的影响是累积的,如下面的示例所示,使用 JSON_SET() 减少键为 b 的值所占用的空间(并且不进行其他更改):

    mysql> UPDATE jtable
        ->     SET jcol = JSON_SET(jcol, "$.a", 10, "$.b", "wx", "$.c", 1);
    Query OK, 1 row affected (0.03 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    mysql> SELECT JSON_STORAGE_FREE(jcol) FROM jtable;
    +-------------------------+
    | JSON_STORAGE_FREE(jcol) |
    +-------------------------+
    |                      16 |
    +-------------------------+
    1 row in set (0.00 sec)

    如果不使用 JSON_SET()JSON_REPLACE()JSON_REMOVE() 更新列值,那么优化器无法执行就地更新;在这种情况下,JSON_STORAGE_FREE() 返回 0,如下所示:

    mysql> UPDATE jtable SET jcol = '{"a": 10, "b": 1}';
    Query OK, 1 row affected (0.05 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    mysql> SELECT JSON_STORAGE_FREE(jcol) FROM jtable;
    +-------------------------+
    | JSON_STORAGE_FREE(jcol) |
    +-------------------------+
    |                       0 |
    +-------------------------+
    1 row in set (0.00 sec)

    JSON 文档的部分更新只能在列值上执行。对于存储 JSON 值的用户变量,总是完全替换该值,即使使用 JSON_SET() 进行更新:

    mysql> SET @j = '{"a": 10, "b": "wxyz", "c": "[true, false]"}';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SET @j = JSON_SET(@j, '$.a', 10, '$.b', 'wxyz', '$.c', '1');
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT @j, JSON_STORAGE_FREE(@j) AS Free;
    +----------------------------------+------+
    | @j                               | Free |
    +----------------------------------+------+
    | {"a": 10, "b": "wxyz", "c": "1"} |    0 |
    +----------------------------------+------+
    1 row in set (0.00 sec)

    对于 JSON 字面量,该函数总是返回 0:

    mysql> SELECT JSON_STORAGE_FREE('{"a": 10, "b": "wxyz", "c": "1"}') AS Free;
    +------+
    | Free |
    +------+
    |    0 |
    +------+
    1 row in set (0.00 sec)
  • JSON_STORAGE_SIZE(json_val)

    该函数返回 JSON 文档的二进制表示形式所需的字节数。当参数是一个 JSON 列时,这是将 JSON 文档插入列时所需的空间,在随后可能执行的部分更新之前。json_val 必须是一个有效的 JSON 文档或可以解析为 JSON 的字符串。在字符串的情况下,该函数返回解析字符串为 JSON 并将其转换为二进制时所需的存储空间。如果参数为 NULL,则返回 NULL

    如果 json_val 不是 NULL,且不是或不能成功解析为 JSON 文档,将导致错误。

    为了说明该函数在使用 JSON 列作为参数时的行为,我们创建一个名为 jtable 的表,其中包含一个 JSONjcol,然后将 JSON 值插入表中,然后使用 JSON_STORAGE_SIZE() 获取该列所需的存储空间,如下所示:

    mysql> CREATE TABLE jtable (jcol JSON);
    Query OK, 0 rows affected (0.42 sec)
    
    mysql> INSERT INTO jtable VALUES
        ->     ('{"a": 1000, "b": "wxyz", "c": "[1, 3, 5, 7]"}');
    Query OK, 1 row affected (0.04 sec)
    
    mysql> SELECT
        ->     jcol,
        ->     JSON_STORAGE_SIZE(jcol) AS Size,
        ->     JSON_STORAGE_FREE(jcol) AS Free
        -> FROM jtable;
    +-----------------------------------------------+------+------+
    | jcol                                          | Size | Free |
    +-----------------------------------------------+------+------+
    | {"a": 1000, "b": "wxyz", "c": "[1, 3, 5, 7]"} |   47 |    0 |
    +-----------------------------------------------+------+------+
    1 row in set (0.00 sec)

    根据 JSON_STORAGE_SIZE() 的输出结果,该 JSON 文档插入列中所需的存储空间为 47 字节。我们还检查了使用 JSON_STORAGE_FREE() 释放的存储空间;由于还没有执行更新,因此该值为 0,如预期。

    接下来,我们对表执行 UPDATE 操作,以便对 jcol 中存储的文档执行部分更新,然后测试结果,如下所示:

    mysql> UPDATE jtable SET jcol = 
        ->     JSON_SET(jcol, "$.b", "a");
    Query OK, 1 row affected (0.04 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    mysql> SELECT
        ->     jcol,
        ->     JSON_STORAGE_SIZE(jcol) AS Size,
        ->     JSON_STORAGE_FREE(jcol) AS Free
        -> FROM jtable;
    +--------------------------------------------+------+------+
    | jcol                                       | Size | Free |
    +--------------------------------------------+------+------+
    | {"a": 1000, "b": "a", "c": "[1, 3, 5, 7]"} |   47 |    3 |
    +--------------------------------------------+------+------+
    1 row in set (0.00 sec)

    前一个查询中 JSON_STORAGE_FREE() 返回的值表明,执行了部分更新,释放了 3 字节的存储空间。 JSON_STORAGE_SIZE() 的结果未因部分更新而改变。

    部分更新支持使用 JSON_SET()JSON_REPLACE()JSON_REMOVE()。直接将值分配给 JSON 列不能部分更新;在这种更新后,JSON_STORAGE_SIZE() 总是显示新设置的值所需的存储空间:

    mysql> UPDATE jtable
    mysql>     SET jcol = '{"a": 4.55, "b": "wxyz", "c": "[true, false]"}';
    Query OK, 1 row affected (0.04 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    mysql> SELECT
        ->     jcol,
        ->     JSON_STORAGE_SIZE(jcol) AS Size,
        ->     JSON_STORAGE_FREE(jcol) AS Free
        -> FROM jtable;
    +------------------------------------------------+------+------+
    | jcol                                           | Size | Free |
    +------------------------------------------------+------+------+
    | {"a": 4.55, "b": "wxyz", "c": "[true, false]"} |   56 |    0 |
    +------------------------------------------------+------+------+
    1 row in set (0.00 sec)

    JSON 用户变量不能部分更新。这意味着该函数总是显示当前存储在用户变量中的 JSON 文档所需的存储空间:

    mysql> SET @j = '[100, "sakila", [1, 3, 5], 425.05]';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT @j, JSON_STORAGE_SIZE(@j) AS Size;
    +------------------------------------+------+
    | @j                                 | Size |
    +------------------------------------+------+
    | [100, "sakila", [1, 3, 5], 425.05] |   45 |
    +------------------------------------+------+
    1 row in set (0.00 sec)
    
    mysql> SET @j = JSON_SET(@j, '$[1]', "json");
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT @j, JSON_STORAGE_SIZE(@j) AS Size;
    +----------------------------------+------+
    | @j                               | Size |
    +----------------------------------+------+
    | [100, "json", [1, 3, 5], 425.05] |   43 |
    +----------------------------------+------+
    1 row in set (0.00 sec)
    
    mysql> SET @j = JSON_SET(@j, '$[2][0]', JSON_ARRAY(10, 20, 30));
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT @j, JSON_STORAGE_SIZE(@j) AS Size;
    +---------------------------------------------+------+
    | @j                                          | Size |
    +---------------------------------------------+------+
    | [100, "json", [[10, 20, 30], 3, 5], 425.05] |   56 |
    +---------------------------------------------+------+
    1 row in set (0.00 sec)

    对于 JSON 字面量,该函数总是返回当前存储空间:

    mysql> SELECT
        ->     JSON_STORAGE_SIZE('[100, "sakila", [1, 3, 5], 425.05]') AS A,
        ->     JSON_STORAGE_SIZE('{"a": 1000, "b": "a", "c": "[1, 3, 5, 7]"}') AS B,
        ->     JSON_STORAGE_SIZE('{"a": 1000, "b": "wxyz", "c": "[1, 3, 5, 7]"}') AS C,
        ->     JSON_STORAGE_SIZE('[100, "json", [[10, 20, 30], 3, 5], 425.05]') AS D;
    +----+----+----+----+
    | A  | B  | C  | D  |
    +----+----+----+----+
    | 45 | 44 | 47 | 56 |
    +----+----+----+----+
    1 row in set (0.00 sec)