12.17.4 修改 JSON 值的函数

本节中的函数将修改 JSON 值并返回结果。

JSON_APPEND(json_doc,path,val [,path,val] ...)

将值附加到 JSON 文档中指定数组的末尾并返回结果。在 MySQL 5.7.9 中,此函数已重命名为JSON_ARRAY_APPEND();别名JSON_APPEND()现在在 MySQL 5.7 中已弃用,在 MySQL 8.0 中已删除。

JSON_ARRAY_APPEND(json_doc,path,val [,path,val] ...)

将值附加到 JSON 文档中指定数组的末尾并返回结果。如果任何参数为NULL,则返回NULL。如果* json_doc 参数不是有效的 JSON 文档或任何 path *参数不是有效的路径 table 达式或包含***通配符,则会发生错误。

路径值对从左到右评估。通过评估一对对生成的文档将成为新的价值,根据该价值评估下一对。

如果路径选择标量或对象值,则该值将自动包装在数组中,并将新值添加到该数组中。路径未标识 JSON 文档中任何值的对将被忽略。

mysql> SET @j = '["a", ["b", "c"], "d"]';
mysql> SELECT JSON_ARRAY_APPEND(@j, '$[1]', 1);
+----------------------------------+
| JSON_ARRAY_APPEND(@j, '$[1]', 1) |
+----------------------------------+
| ["a", ["b", "c", 1], "d"]        |
+----------------------------------+
mysql> SELECT JSON_ARRAY_APPEND(@j, '$[0]', 2);
+----------------------------------+
| JSON_ARRAY_APPEND(@j, '$[0]', 2) |
+----------------------------------+
| [["a", 2], ["b", "c"], "d"]      |
+----------------------------------+
mysql> SELECT JSON_ARRAY_APPEND(@j, '$[1][0]', 3);
+-------------------------------------+
| JSON_ARRAY_APPEND(@j, '$[1][0]', 3) |
+-------------------------------------+
| ["a", [["b", 3], "c"], "d"]         |
+-------------------------------------+

mysql> SET @j = '{"a": 1, "b": [2, 3], "c": 4}';
mysql> SELECT JSON_ARRAY_APPEND(@j, '$.b', 'x');
+------------------------------------+
| JSON_ARRAY_APPEND(@j, '$.b', 'x')  |
+------------------------------------+
| {"a": 1, "b": [2, 3, "x"], "c": 4} |
+------------------------------------+
mysql> SELECT JSON_ARRAY_APPEND(@j, '$.c', 'y');
+--------------------------------------+
| JSON_ARRAY_APPEND(@j, '$.c', 'y')    |
+--------------------------------------+
| {"a": 1, "b": [2, 3], "c": [4, "y"]} |
+--------------------------------------+

mysql> SET @j = '{"a": 1}';
mysql> SELECT JSON_ARRAY_APPEND(@j, '$', 'z');
+---------------------------------+
| JSON_ARRAY_APPEND(@j, '$', 'z') |
+---------------------------------+
| [{"a": 1}, "z"]                 |
+---------------------------------+

JSON_ARRAY_INSERT(json_doc,path,val [,path,val] ...)

更新 JSON 文档,将其插入文档中的数组中并返回修改后的文档。如果任何参数为NULL,则返回NULL。如果* json_doc 参数不是有效的 JSON 文档,或者任何 path *参数不是有效的路径 table 达式,或者包含***通配符,或者不以数组元素标识符结尾,则会发生错误。

路径值对从左到右评估。通过评估一对对生成的文档将成为新的价值,根据该价值评估下一对。

路径无法标识 JSON 文档中任何数组的对将被忽略。如果路径标识数组元素,则在该元素位置插入相应的值,然后将任何后续值向右移动。如果路径标识了超出数组末尾的数组位置,则将值插入到数组末尾。

mysql> SET @j = '["a", {"b": [1, 2]}, [3, 4]]';
mysql> SELECT JSON_ARRAY_INSERT(@j, '$[1]', 'x');
+------------------------------------+
| JSON_ARRAY_INSERT(@j, '$[1]', 'x') |
+------------------------------------+
| ["a", "x", {"b": [1, 2]}, [3, 4]]  |
+------------------------------------+
mysql> SELECT JSON_ARRAY_INSERT(@j, '$[100]', 'x');
+--------------------------------------+
| JSON_ARRAY_INSERT(@j, '$[100]', 'x') |
+--------------------------------------+
| ["a", {"b": [1, 2]}, [3, 4], "x"]    |
+--------------------------------------+
mysql> SELECT JSON_ARRAY_INSERT(@j, '$[1].b[0]', 'x');
+-----------------------------------------+
| JSON_ARRAY_INSERT(@j, '$[1].b[0]', 'x') |
+-----------------------------------------+
| ["a", {"b": ["x", 1, 2]}, [3, 4]]       |
+-----------------------------------------+
mysql> SELECT JSON_ARRAY_INSERT(@j, '$[2][1]', 'y');
+---------------------------------------+
| JSON_ARRAY_INSERT(@j, '$[2][1]', 'y') |
+---------------------------------------+
| ["a", {"b": [1, 2]}, [3, "y", 4]]     |
+---------------------------------------+
mysql> SELECT JSON_ARRAY_INSERT(@j, '$[0]', 'x', '$[2][1]', 'y');
+----------------------------------------------------+
| JSON_ARRAY_INSERT(@j, '$[0]', 'x', '$[2][1]', 'y') |
+----------------------------------------------------+
| ["x", "a", {"b": [1, 2]}, [3, 4]]                  |
+----------------------------------------------------+

较早的修改会影响数组中后续元素的位置,因此在同一JSON_ARRAY_INSERT()调用中的后续路径应考虑到这一点。在最后一个示例中,第二个路径不插入任何内容,因为该路径在第一个插入之后不再匹配任何内容。

JSON_INSERT(json_doc,path,val [,path,val] ...)

将数据插入 JSON 文档并返回结果。如果任何参数为NULL,则返回NULL。如果* json_doc 参数不是有效的 JSON 文档或任何 path *参数不是有效的路径 table 达式或包含***通配符,则会发生错误。

路径值对从左到右评估。通过评估一对对生成的文档将成为新的价值,根据该价值评估下一对。

文档中现有路径的路径值对将被忽略,并且不会覆盖现有文档值。如果路径中标识以下类型的值之一,则文档中不存在的路径的路径-值对会将值添加到文档中:

  • 现有对象中不存在的成员。成员被添加到对象并与新值关联。

    • 超出现有数组末尾的位置。用新值扩展数组。如果现有值不是数组,则将其自动包装为数组,然后使用新值进行扩展。

否则,将忽略文档中不存在的路径的路径-值对,并且无效。

有关JSON_INSERT()JSON_REPLACE()JSON_SET()的比较,请参见JSON_SET()的讨论。

mysql> SET @j = '{ "a": 1, "b": [2, 3]}';
mysql> SELECT JSON_INSERT(@j, '$.a', 10, '$.c', '[true, false]');
+----------------------------------------------------+
| JSON_INSERT(@j, '$.a', 10, '$.c', '[true, false]') |
+----------------------------------------------------+
| {"a": 1, "b": [2, 3], "c": "[true, false]"}        |
+----------------------------------------------------+

结果中列出的第三个也是最后一个值是带引号的字符串,而不是像第二个那样的数组(在输出中不带引号);不会将值强制转换为 JSON 类型。要将数组插入为数组,必须显式执行此类转换,如下所示:

mysql> SELECT JSON_INSERT(@j, '$.a', 10, '$.c', CAST('[true, false]' AS JSON));
+------------------------------------------------------------------+
| JSON_INSERT(@j, '$.a', 10, '$.c', CAST('[true, false]' AS JSON)) |
+------------------------------------------------------------------+
| {"a": 1, "b": [2, 3], "c": [true, false]}                        |
+------------------------------------------------------------------+
1 row in set (0.00 sec)

JSON_MERGE(json_doc,json_doc [,json_doc] ...)

合并两个或多个 JSON 文档。 JSON_MERGE_PRESERVE()的同义词;在 MySQL 5.7.22 中已弃用,并可能在将来的版本中删除。

mysql> SELECT JSON_MERGE('[1, 2]', '[true, false]');
+---------------------------------------+
| JSON_MERGE('[1, 2]', '[true, false]') |
+---------------------------------------+
| [1, 2, true, false]                   |
+---------------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Warning
   Code: 1287
Message: 'JSON_MERGE' is deprecated and will be removed in a future release. \
 Please use JSON_MERGE_PRESERVE/JSON_MERGE_PATCH instead
1 row in set (0.00 sec)

有关其他示例,请参见JSON_MERGE_PRESERVE()的条目。

JSON_MERGE_PATCH(json_doc,json_doc [,json_doc] ...)

对两个或多个 JSON 文档执行RFC 7396兼容的合并,并返回合并的结果,而不会保留具有重复键的成员。如果至少有一个作为该函数的参数传递的文档无效,则会引发错误。

Note

有关此函数和JSON_MERGE_PRESERVE()之间的区别的说明和示例,请参见JSON_MERGE_PATCH()与 JSON_MERGE_PRESERVE()比较

JSON_MERGE_PATCH()执行如下合并:

  • 如果第一个参数不是对象,则合并的结果与将空对象与第二个参数合并的结果相同。

  • 如果第二个参数不是对象,则合并的结果为第二个参数。

  • 如果两个参数都是对象,则合并的结果是具有以下成员的对象:

  • 在第二个对象中,第一个对象的所有成员都没有具有相同键的对应成员。

    • 第二个对象的所有成员,在第一个对象中没有对应的键,并且其值不是 JSON nullLiterals。

    • 具有第一个和第二个对象中都存在的键的所有成员,并且其在第二个对象中的值不是 JSON nullLiterals。这些成员的值是将第一个对象中的值与第二个对象中的值递归合并的结果。

有关更多信息,请参见JSON 值的规范化,合并和自动包装

mysql> SELECT JSON_MERGE_PATCH('[1, 2]', '[true, false]');
+---------------------------------------------+
| JSON_MERGE_PATCH('[1, 2]', '[true, false]') |
+---------------------------------------------+
| [true, false]                               |
+---------------------------------------------+

mysql> SELECT JSON_MERGE_PATCH('{"name": "x"}', '{"id": 47}');
+-------------------------------------------------+
| JSON_MERGE_PATCH('{"name": "x"}', '{"id": 47}') |
+-------------------------------------------------+
| {"id": 47, "name": "x"}                         |
+-------------------------------------------------+

mysql> SELECT JSON_MERGE_PATCH('1', 'true');
+-------------------------------+
| JSON_MERGE_PATCH('1', 'true') |
+-------------------------------+
| true                          |
+-------------------------------+

mysql> SELECT JSON_MERGE_PATCH('[1, 2]', '{"id": 47}');
+------------------------------------------+
| JSON_MERGE_PATCH('[1, 2]', '{"id": 47}') |
+------------------------------------------+
| {"id": 47}                               |
+------------------------------------------+

mysql> SELECT JSON_MERGE_PATCH('{ "a": 1, "b":2 }',
     >     '{ "a": 3, "c":4 }');
+-----------------------------------------------------------+
| JSON_MERGE_PATCH('{ "a": 1, "b":2 }','{ "a": 3, "c":4 }') |
+-----------------------------------------------------------+
| {"a": 3, "b": 2, "c": 4}                                  |
+-----------------------------------------------------------+

mysql> SELECT JSON_MERGE_PATCH('{ "a": 1, "b":2 }','{ "a": 3, "c":4 }',
     >     '{ "a": 5, "d":6 }');
+-------------------------------------------------------------------------------+
| JSON_MERGE_PATCH('{ "a": 1, "b":2 }','{ "a": 3, "c":4 }','{ "a": 5, "d":6 }') |
+-------------------------------------------------------------------------------+
| {"a": 5, "b": 2, "c": 4, "d": 6}                                              |
+-------------------------------------------------------------------------------+

您可以使用此函数通过将null指定为 seond 参数中相同成员的值来删除成员,如下所示:

mysql> SELECT JSON_MERGE_PATCH('{"a":1, "b":2}', '{"b":null}');
+--------------------------------------------------+
| JSON_MERGE_PATCH('{"a":1, "b":2}', '{"b":null}') |
+--------------------------------------------------+
| {"a": 1}                                         |
+--------------------------------------------------+

本示例说明该函数以递归方式运行;也就是说,成员的值不限于标量,而是本身可以是 JSON 文档:

mysql> SELECT JSON_MERGE_PATCH('{"a":{"x":1}}', '{"a":{"y":2}}');
+----------------------------------------------------+
| JSON_MERGE_PATCH('{"a":{"x":1}}', '{"a":{"y":2}}') |
+----------------------------------------------------+
| {"a": {"x": 1, "y": 2}}                            |
+----------------------------------------------------+

MySQL 5.7.22 和更高版本支持JSON_MERGE_PATCH()

JSON_MERGE_PATCH()与 JSON_MERGE_PRESERVE()比较. JSON_MERGE_PATCH()的行为与JSON_MERGE_PRESERVE()相同,但以下两个 exception:

  • JSON_MERGE_PATCH()删除第二个对象中具有匹配键的第一个对象中的任何成员,前提是与第二个对象中的键关联的值不是 JSON null

    • 如果第二个对象的成员具有与第一个对象中的成员匹配的键,则JSON_MERGE_PATCH() 第一个对象中的值替换为第二个对象中的值,而JSON_MERGE_PRESERVE() 将第二个值附加到第一个值。

此示例比较了将相同的 3 个 JSON 对象(每个都具有匹配的键"a")与以下两个函数的每个对象的合并结果:

mysql> SET @x = '{ "a": 1, "b": 2 }',
     >     @y = '{ "a": 3, "c": 4 }',
     >     @z = '{ "a": 5, "d": 6 }';

mysql> SELECT  JSON_MERGE_PATCH(@x, @y, @z)    AS Patch,
    ->         JSON_MERGE_PRESERVE(@x, @y, @z) AS Preserve\G
*************************** 1. row ***************************
   Patch: {"a": 5, "b": 2, "c": 4, "d": 6}
Preserve: {"a": [1, 3, 5], "b": 2, "c": 4, "d": 6}

JSON_MERGE_PRESERVE(json_doc,json_doc [,json_doc] ...)

合并两个或多个 JSON 文档并返回合并的结果。如果任何参数为NULL,则返回NULL。如果任何参数不是有效的 JSON 文档,则会发生错误。

合并根据以下规则进行。有关更多信息,请参见JSON 值的规范化,合并和自动包装

  • 相邻数组合并为单个数组。

    • 相邻对象合并为单个对象。

    • 标量值将自动包装为数组,然后合并为数组。

    • 通过将对象自动包装为一个数组并将两个数组合并,可以合并相邻的数组和对象。

mysql> SELECT JSON_MERGE_PRESERVE('[1, 2]', '[true, false]');
+------------------------------------------------+
| JSON_MERGE_PRESERVE('[1, 2]', '[true, false]') |
+------------------------------------------------+
| [1, 2, true, false]                            |
+------------------------------------------------+

mysql> SELECT JSON_MERGE_PRESERVE('{"name": "x"}', '{"id": 47}');
+----------------------------------------------------+
| JSON_MERGE_PRESERVE('{"name": "x"}', '{"id": 47}') |
+----------------------------------------------------+
| {"id": 47, "name": "x"}                            |
+----------------------------------------------------+

mysql> SELECT JSON_MERGE_PRESERVE('1', 'true');
+----------------------------------+
| JSON_MERGE_PRESERVE('1', 'true') |
+----------------------------------+
| [1, true]                        |
+----------------------------------+

mysql> SELECT JSON_MERGE_PRESERVE('[1, 2]', '{"id": 47}');
+---------------------------------------------+
| JSON_MERGE_PRESERVE('[1, 2]', '{"id": 47}') |
+---------------------------------------------+
| [1, 2, {"id": 47}]                          |
+---------------------------------------------+

mysql> SELECT JSON_MERGE_PRESERVE('{ "a": 1, "b": 2 }',
     >    '{ "a": 3, "c": 4 }');
+--------------------------------------------------------------+
| JSON_MERGE_PRESERVE('{ "a": 1, "b": 2 }','{ "a": 3, "c":4 }') |
+--------------------------------------------------------------+
| {"a": [1, 3], "b": 2, "c": 4}                                |
+--------------------------------------------------------------+

mysql> SELECT JSON_MERGE_PRESERVE('{ "a": 1, "b": 2 }','{ "a": 3, "c": 4 }',
     >    '{ "a": 5, "d": 6 }');
+----------------------------------------------------------------------------------+
| JSON_MERGE_PRESERVE('{ "a": 1, "b": 2 }','{ "a": 3, "c": 4 }','{ "a": 5, "d": 6 }') |
+----------------------------------------------------------------------------------+
| {"a": [1, 3, 5], "b": 2, "c": 4, "d": 6}                                         |
+----------------------------------------------------------------------------------+

此功能已在 MySQL 5.7.22 中添加为JSON_MERGE()的同义词。现在不推荐使用JSON_MERGE()函数,并且在将来的 MySQL 版本中可能会删除该函数。

此功能在很多方面与JSON_MERGE_PATCH()类似但有所不同;有关更多信息,请参见JSON_MERGE_PATCH()与 JSON_MERGE_PRESERVE()比较

JSON_REMOVE(json_doc,path [,path] ...)

从 JSON 文档中删除数据并返回结果。如果任何参数为NULL,则返回NULL。如果* json_doc参数不是有效的 JSON 文档,或者任何* path *参数不是有效的路径 table 达式,或者是$或包含***通配符,则会发生错误。

  • path *参数从左到右求值。通过评估一个路径生成的文档将成为评估下一个路径所依据的新值。

如果要删除的元素在文档中不存在,这不是错误;在这种情况下,路径不会影响文档。

mysql> SET @j = '["a", ["b", "c"], "d"]';
mysql> SELECT JSON_REMOVE(@j, '$[1]');
+-------------------------+
| JSON_REMOVE(@j, '$[1]') |
+-------------------------+
| ["a", "d"]              |
+-------------------------+

JSON_REPLACE(json_doc,path,val [,path,val] ...)

替换 JSON 文档中的现有值并返回结果。如果任何参数为NULL,则返回NULL。如果* json_doc 参数不是有效的 JSON 文档或任何 path *参数不是有效的路径 table 达式或包含***通配符,则会发生错误。

路径值对从左到右评估。通过评估一对对生成的文档将成为新的价值,根据该价值评估下一对。

文档中现有路径的路径-值对将使用新值覆盖现有文档值。文档中不存在的路径的路径-值对将被忽略,并且无效。

有关JSON_INSERT()JSON_REPLACE()JSON_SET()的比较,请参见JSON_SET()的讨论。

mysql> SET @j = '{ "a": 1, "b": [2, 3]}';
mysql> SELECT JSON_REPLACE(@j, '$.a', 10, '$.c', '[true, false]');
+-----------------------------------------------------+
| JSON_REPLACE(@j, '$.a', 10, '$.c', '[true, false]') |
+-----------------------------------------------------+
| {"a": 10, "b": [2, 3]}                              |
+-----------------------------------------------------+

JSON_SET(json_doc,path,val [,path,val] ...)

在 JSON 文档中插入或更新数据并返回结果。如果任何参数是NULL或* path ,则返回NULL,如果给出,则找不到对象。如果 json_doc 参数不是有效的 JSON 文档,或者任何 path *参数不是有效的路径 table 达式或包含***通配符,则会发生错误。

路径值对从左到右评估。通过评估一对对生成的文档将成为新的价值,根据该价值评估下一对。

文档中现有路径的路径-值对将使用新值覆盖现有文档值。如果路径中标识以下类型的值之一,则文档中不存在的路径的路径-值对会将值添加到文档中:

  • 现有对象中不存在的成员。成员被添加到对象并与新值关联。

    • 超出现有数组末尾的位置。用新值扩展数组。如果现有值不是数组,则将其自动包装为数组,然后使用新值进行扩展。

否则,将忽略文档中不存在的路径的路径-值对,并且无效。

JSON_SET()JSON_INSERT()JSON_REPLACE()函数相关:

以下示例使用文档中存在的一个路径($.a)和不存在的另一路径($.c)说明了这些差异:

mysql> SET @j = '{ "a": 1, "b": [2, 3]}';
mysql> SELECT JSON_SET(@j, '$.a', 10, '$.c', '[true, false]');
+-------------------------------------------------+
| JSON_SET(@j, '$.a', 10, '$.c', '[true, false]') |
+-------------------------------------------------+
| {"a": 10, "b": [2, 3], "c": "[true, false]"}    |
+-------------------------------------------------+
mysql> SELECT JSON_INSERT(@j, '$.a', 10, '$.c', '[true, false]');
+----------------------------------------------------+
| JSON_INSERT(@j, '$.a', 10, '$.c', '[true, false]') |
+----------------------------------------------------+
| {"a": 1, "b": [2, 3], "c": "[true, false]"}        |
+----------------------------------------------------+
mysql> SELECT JSON_REPLACE(@j, '$.a', 10, '$.c', '[true, false]');
+-----------------------------------------------------+
| JSON_REPLACE(@j, '$.a', 10, '$.c', '[true, false]') |
+-----------------------------------------------------+
| {"a": 10, "b": [2, 3]}                              |
+-----------------------------------------------------+

JSON_UNQUOTE(json_val)

取消引用 JSON 值,并以utf8mb4字符串的形式返回结果。如果参数为NULL,则返回NULL。如果该值以双引号开头和结尾,但不是有效的 JSON 字符串 Literals,则会发生错误。

在字符串中,某些序列具有特殊含义,除非启用了NO_BACKSLASH_ESCAPES SQL 模式。这些序列中的每个序列都以反斜杠(\)开头,称为转义字符。 MySQL 识别table12.22,“ JSON_UNQUOTE()特殊字符转义序列”中显示的转义序列。对于所有其他转义序列,将忽略反斜杠。即,将转义字符解释为好像没有转义。例如,\x只是x。这些序列区分大小写。例如,\b被解释为退格,而\B被解释为B

table12.22 JSON_UNQUOTE()特殊字符转义序列

Escape Sequence序列 table 示的字符
\" 双引号(")字符
\b 退格字符
\f 换页符
\n 换行符(换行符)
\r 回车符
\t 制 table 符
\\ 反斜杠(\)字符
\uXXXX Unicode 值的 UTF-8 字节* XXXX *

下面显示了使用此功能的两个简单示例:

mysql> SET @j = '"abc"';
mysql> SELECT @j, JSON_UNQUOTE(@j);
+-------+------------------+
| @j    | JSON_UNQUOTE(@j) |
+-------+------------------+
| "abc" | abc              |
+-------+------------------+
mysql> SET @j = '[1, 2, 3]';
mysql> SELECT @j, JSON_UNQUOTE(@j);
+-----------+------------------+
| @j        | JSON_UNQUOTE(@j) |
+-----------+------------------+
| [1, 2, 3] | [1, 2, 3]        |
+-----------+------------------+

以下示例集显示了JSON_UNQUOTE如何在禁用和启用NO_BACKSLASH_ESCAPES的情况下处理转义:

mysql> SELECT @@sql_mode;
+------------+
| @@sql_mode |
+------------+
|            |
+------------+

mysql> SELECT JSON_UNQUOTE('"\\t\\u0032"');
+------------------------------+
| JSON_UNQUOTE('"\\t\\u0032"') |
+------------------------------+
|       2                           |
+------------------------------+

mysql> SET @@sql_mode = 'NO_BACKSLASH_ESCAPES';
mysql> SELECT JSON_UNQUOTE('"\\t\\u0032"');
+------------------------------+
| JSON_UNQUOTE('"\\t\\u0032"') |
+------------------------------+
| \t\u0032                     |
+------------------------------+

mysql> SELECT JSON_UNQUOTE('"\t\u0032"');
+----------------------------+
| JSON_UNQUOTE('"\t\u0032"') |
+----------------------------+
|       2                         |
+----------------------------+