12.18.4 修改 JSON 值的函数

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

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

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

    路径值对从左到右计算。通过评估一对生成的文档成为评估下一对的新值。

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

    Press CTRL+C to copy
    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"] | +---------------------------------+

    在 MySQL 5.7 中,这个函数被命名为 JSON_APPEND(). MySQL 8.0 不再支持该名称。

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

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

    路径值对从左到右计算。通过评估一对生成的文档成为评估下一对的新值。

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

    Press CTRL+C to copy
    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如果任何参数是 ,则返回NULLjson_doc如果参数不是有效的 JSON 文档或任何path参数不是有效的路径表达式或包含 ***通配符, 则会发生错误 。

    路径值对从左到右计算。通过评估一对生成的文档成为评估下一对的新值。

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

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

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

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

    对于 、 和 的比较JSON_INSERT(), 请参阅 的讨论。 JSON_REPLACE()JSON_SET()JSON_SET()

    Press CTRL+C to copy
    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 类型。要将数组作为数组插入,您必须显式执行此类转换,如下所示:

    Press CTRL+C to copy
    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 8.0.3 中弃用,并在未来版本中删除。

    Press CTRL+C to copy
    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的合并并返回合并结果,而不保留具有重复键的成员。如果作为参数传递给此函数的至少一个文档无效,则引发错误。

    笔记

    有关此函数与 之间差异的解释和示例JSON_MERGE_PRESERVE(),请参阅 JSON_MERGE_PATCH() 与 JSON_MERGE_PRESERVE() 的比较

    JSON_MERGE_PATCH()执行合并如下:

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

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

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

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

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

      • 其键同时存在于第一个和第二个对象中且其在第二个对象中的值不是 JSONnull 文字的所有成员。这些成员的值是将第一个对象中的值与第二个对象中的值递归合并的结果。

    有关其他信息,请参阅 JSON 值的规范化、合并和自动包装

    Press CTRL+C to copy
    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您可以使用此函数通过在第二个参数中指定相同成员的值 来删除成员 ,如下所示:

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

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

    Press CTRL+C to copy
    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}} | +----------------------------------------------------+

    JSON_MERGE_PATCH()MySQL 8.0.3 及更高版本支持。

    JSON_MERGE_PATCH() 与 JSON_MERGE_PRESERVE() 相比。  的行为与 的行为JSON_MERGE_PATCH()相同, JSON_MERGE_PRESERVE()但有以下两个例外:

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

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

    此示例将合并相同的 3 个 JSON 对象(每个对象都有一个匹配的键"a")的结果与这两个函数中的每一个进行比较:

    Press CTRL+C to copy
    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 值的规范化、合并和自动包装

    • 相邻的数组合并为一个数组。

    • 相邻的对象合并为一个对象。

    • 标量值自动包装为数组并合并为数组。

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

    Press CTRL+C to copy
    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 8.0.3 中作为 JSON_MERGE(). 该 JSON_MERGE()函数现已弃用,并可能在 MySQL 的未来版本中删除。

    此功能与此类似,但 JSON_MERGE_PATCH()在重要方面有所不同;有关详细信息,请参阅 JSON_MERGE_PATCH() 与 JSON_MERGE_PRESERVE()的比较。

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

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

    path参数从左到右计算 。通过评估一条路径生成的文档成为评估下一条路径所依据的新值。

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

    Press CTRL+C to copy
    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如果任何参数是 ,则返回NULLjson_doc如果参数不是有效的 JSON 文档或任何path参数不是有效的路径表达式或包含 ***通配符, 则会发生错误 。

    路径值对从左到右计算。通过评估一对生成的文档成为评估下一对的新值。

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

    在 MySQL 8.0.4 中,优化器可以对列执行部分就地更新,JSON而不是删除旧文档并将新文档完整写入列。JSON_REPLACE()可以为使用该函数并满足 JSON 值的部分更新中概述的条件的更新语句执行此优化 。

    对于 、 和 的比较JSON_INSERT(), 请参阅 的讨论。 JSON_REPLACE()JSON_SET()JSON_SET()

    Press CTRL+C to copy
    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如果任何参数是 NULLor则返回path,如果给定,则不定位对象。json_doc如果参数不是有效的 JSON 文档或任何path参数不是有效的路径表达式或包含 ***通配符, 则会发生错误 。

    路径值对从左到右计算。通过评估一对生成的文档成为评估下一对的新值。

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

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

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

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

    在 MySQL 8.0.4 中,优化器可以对列执行部分就地更新,JSON而不是删除旧文档并将新文档完整写入列。JSON_SET()可以为使用该函数并满足 JSON 值的部分更新中概述的条件的更新语句执行此优化 。

    JSON_SET()和 函数是相关的 JSON_INSERT()JSON_REPLACE()

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

    Press CTRL+C to copy
    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 字符串文字,则会发生错误。

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

    表 12.23 JSON_UNQUOTE() 特殊字符转义序列

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

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

    Press CTRL+C to copy
    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 禁用和启用的转义:

    Press CTRL+C to copy
    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 | +----------------------------+