MySQL-JSON数据说明和操作

软件行业唯一不变的就是变化,比如功能上线之后,客户或 PM 需要对已有的功能增加一些合理的需求,完成这些工作必须通过添加字段解决,或者某些功能的实现需要通过增加字段来降低实现的复杂性等等。这些问题都会改动线上的数据库表结构,一旦改动就会导致锁表,会使所有的写入操作一直等待,直到表锁关闭,特别是对于数据量大的热点表,添加一个字段可能会因为锁表时间过长而导致部分请求超时,这可能会对企业间接造成经济上的损失

官方说明,在MySQL5.7.8 的时候开始支持JSON数据类型,支持的最大值为1G(max_allowed_packet ->1073741824)。


一、Mysql老版本解决方案

1.1增加 json 格式的扩展字段。

下面配合一些代码来描述这个解决方案,便于去理解。
数据库表的字段定义:

DROP TABLE IF EXISTS `cs_dustbin`;
CREATE TABLE IF NOT EXISTS `t_guoxiuzhi_json` (
  `id` VARCHAR(45) NOT NULL COMMENT '主键自增id',
  `ext` VARCHAR(1000) NOT NULL DEFAULT '{}' COMMENT '扩展字段',
  ...
  PRIMARY KEY (`id`))
ENGINE = InnoDB

1.2Java 代码:

import com.alibaba.fastjson.JSON;
import lombok.Data;

import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;

/**
 * 实体类
 */
@Data
public class GuoxiuzhiJson {

    private String id;

    /**
     * 扩展字段,详细数据查看 DustbinExt.java
     * DefaultValue: {}
     */
    private String ext;

    ...

    public DustbinExt getExtObject() {
        return JSON.parseObject(this.getExt(), DustbinExt.class);
    }

    public void setExtObject(DustbinExt ext) {
        this.ext = JSON.toJSONString(ext);
    }

    /**
     * 垃圾桶扩展属性
     * Created by Blink on 6/28/2018 AD.
     *
     * @author Blink
     */
    @Data
    public static class DustbinExt {

        /**
         * 所在镇街
         * 根据状态,这里的含义可能是领用镇街、退还镇街、绑定的镇街
         */

        private String street;

        /**
         * 客户(收集点)id,绑定收集点的时候需要填入
         * 根据目前的需求(2018-06-29),当收集点解绑的时候
         * 需要保存垃圾桶最新绑定收集点名称,所以在解绑垃圾桶的时候不会把这个信息删掉
         * 只有当绑定收集点的时候才把他覆盖
         */
        private Long customerId;

        /**
         * 客户(收集点)名称,绑定收集点的时候需要填入
         * 根据目前的需求(2018-06-29),当收集点解绑的时候
         * 需要保存垃圾桶最新绑定收集点名称,所以在解绑垃圾桶的时候不会把这个信息删掉
         * 只有当绑定收集点的时候才把他覆盖
         */
        private String customer;

        /**
         * 损坏部位
         * 1:桶盖;2:桶口;3:桶身;4:桶轴;5:桶底;6:桶轮;
         * 对应 DustbinDamagePartEnum 类
         */
        private List<Integer> parts;
    }

    ...
}

可以看到 ext 字段就是用来存储 json 格式的数据,它可以动态地增加任何字段,甚至是对象,不需要通过 [DDL(Data Definition Language)]去创建字段,非常适合用来解决上面提到的问题。

Java 代码在这里起到辅助性作用,通过定义一个内部类来管理扩展字段的属性,方便我们了解和管理扩展字段,提高代码的可读性和可维护性,java 这种方式也是笔者总结出来的较为优雅的做法。

1.3 局限性

有经验的读者可能会提出,ext 字段在 Mysql 5.7.8 以下版本无法对扩展字段中的某一个或一部分字段建立索引,因为 Mysql 5.7.8 版本以下不支持。

没错,这是这个解决方案的一个局限性,在 Mysql 5.7.8 以下版本,我的建议是, ext 扩展字段不要存储热点数据,只存储非热点数据,这样就可以避免查询操作,降低维护 ext 字段带来的成本和风险,那如何识别新增字段是不是热点数据呢?这个需要结合实际业务需求来判断,也可以询问对业务和技术更有经验的同事,便于读者更快得出结论。

二、 Mysql 5.7.8操作JSON

MySQL JSON数据类型,但在 MySQL中,直至 5.7.8 版本中,才正式引入 JSON数据类型。在此之前,我们通常使varchar或text数据类型存储JSON格式数据。

2.1 MySQL JSON相关函数

MySQL官方列出json相关的函数,完整列表如下:

分类 函数 描述
创建json json_array 创建json数组
json_object 创建json对象
json_quote 将json转成json字符串类型
查询json json_contains 判断是否包含某个json值
json_contains_path 判断某个路径下是否包json值
json_extract 提取json值
column->path json_extract的简洁写法,MySQL 5.7.9开始支持
column->>path json_unquote(column -> path)的简洁写法
json_keys 提取json中的键值为json数组
json_search 按给定字符串关键字搜索json,返回匹配的路径
修改json json_append 废弃,MySQL 5.7.9开始改名为json_array_append
json_array_append 末尾添加数组元素,如果原有值是数值或json对象,则转成数组后,再添加元素
json_array_insert 插入数组元素
json_insert 插入值(插入新值,但不替换已经存在的旧值)
json_merge 合并json数组或对象
json_remove 删除json数据
json_replace 替换值(只替换已经存在的旧值)
json_set 设置值(替换旧值,并插入不存在的新值)
json_unquote 去除json字符串的引号,将值转成string类型
返回json属性 json_depth 返回json文档的最大深度
json_length 返回json文档的长度
json_type 返回json值得类型
json_valid 判断是否为合法json文档

简单列一下常用操作,便于记忆:
JSON_EXTRACT(column_name,'$.name')返回该json列column中的name中的值
JSON_SEARCH(others, 'one', "露露") 若该字段存在,返回路径,若不存在返回null:select * from employe where JSON_SEARCH(others, 'one', "露露") is not null;//查找存在“露露”的记录;该方法中的中间参数有“one”与“all”两种,one返回该json中第一次找到的记录路径,all返回该json中所有找到的路径,即若存在多个“露露”则返回多个露露的路径
JSON_TYPE(others) 判断alias的json类型(ARRAY或者OBJECT)
JSON_VALID(others) 判断alias 是否是一个合法的json
JSON_CONTAINS(others, '露露', '$.alias');
mysql5.7.9开始增加了一种简写方式:column->path; select others->'$.address' from employe 查询json中的address列 类似:select JSON_EXTRACT(others, '$.address') from employe where id = 42332;
select json_contains('{"a":1,"b":4}','{"a":1}') 结果1
select json_contains('{"a":2,"b":1}','{"a":1}') 结果0
select json_contains('{"a":[1,2,3],"b":1}','[1,2]','$.a') 结果1。数组包含则需要所有元素都存在。
select json_contains('{"a":[1,2,3],"b":1}','1','$.a')

使用json_contains的时候,如果是字符串要用双引号包括,如果去掉双引号则报错。

2.2 MySQL JOSN相关函数语法

一、创建JSON值的函数

JSON_ARRAY([val[, val] ...])

计算(可能为空)值列表并返回包含这些值的JSON数组。

mysql> SELECT JSON_ARRAY(1, "abc", NULL, TRUE, CURTIME());
+---------------------------------------------+
| JSON_ARRAY(1, "abc", NULL, TRUE, CURTIME()) |
+---------------------------------------------+
| [1, "abc", null, true, "11:30:24.000000"] |
+---------------------------------------------+

JSON_OBJECT([key, val[, key, val] ...])

计算(可能为空)键 - 值对列表,并返回包含这些对的JSON对象.如果任何键名称NULL或参数数量为奇数,则会发生错误。

mysql> SELECT JSON_OBJECT('id', 87, 'name', 'carrot');
+-----------------------------------------+
| JSON_OBJECT('id', 87, 'name', 'carrot') |
+-----------------------------------------+
| {"id": 87, "name": "carrot"} |
+-----------------------------------------+

JSON_QUOTE(string)

通过用双引号字符包装并转义内部引号和其他字符,然后将结果作为utf8mb4字符串返回,将字符串引用为JSON值 。NULL如果参数是,则 返回 NULL。

此函数通常用于生成有效的JSON字符串文字以包含在JSON文档中。

mysql> SELECT JSON_QUOTE('null'), JSON_QUOTE('"null"');
+--------------------+----------------------+
| JSON_QUOTE('null') | JSON_QUOTE('"null"') |
+--------------------+----------------------+
| "null" | ""null"" |
+--------------------+----------------------+
mysql> SELECT JSON_QUOTE('[1, 2, 3]');
+-------------------------+
| JSON_QUOTE('[1, 2, 3]') |
+-------------------------+
| "[1, 2, 3]" |
+-------------------------+
二、搜索JSON值的函数

JSON_CONTAINS()

语法:

JSON_CONTAINS(json_doc, val[, path])
说明:
返回0或者1来表示目标JSON文本中是否包含特定值,或者JSON文本的指定路径下是否包含特定值。
以下情况将返回NULL:
目标JSON文本或者特定值为NULl
指定路径非目标JSON文本下的路径
以下情况将报错:
目标JSON文本不合法
指定路径不合法
包含* 或者 ** 匹配符
若仅检查路径是否存在,使用JSON_CONTAINS_PATH()代替
这个函数中做了以下约定:
当且仅当两个标量可比较而且相等时,约定目标表标量中包含候选标量。两个标量的JSON_TYPE()值相同时约定他们是可比较的,另外类型分别为INTEGER和DECEMAL的两个标量也是可比较的
当且仅当目标数组中包含所有的候选数组元素,约定目标数组包含候选数组
当且仅当目标数组中某些元素包含空数组,约定目标数组包含空数组
当且仅当候选对象中所有的键值都能在目标对象中找到相同名称的键而且候选键值被目标键值包含,约定目标对象包含候选对象
其他的情况均为目标文本不包含候选文本
示例:
mysql> SET @j = '{"a": 1, "b": 2, "c": {"d": 4}}';
mysql> SET @j2 = '1';
mysql> SELECT JSON_CONTAINS(@j, @j2, '.a'); +-------------------------------+ | JSON_CONTAINS(@j, @j2, '.a') |
+-------------------------------+
| 1 |
+-------------------------------+
mysql> SELECT JSON_CONTAINS(@j, @j2, '.b'); +-------------------------------+ | JSON_CONTAINS(@j, @j2, '.b') |
+-------------------------------+
| 0 |
+-------------------------------+

mysql> SET @j2 = '{"d": 4}';
mysql> SELECT JSON_CONTAINS(@j, @j2, '.a'); +-------------------------------+ | JSON_CONTAINS(@j, @j2, '.a') |
+-------------------------------+
| 0 |
+-------------------------------+
mysql> SELECT JSON_CONTAINS(@j, @j2, '.c'); +-------------------------------+ | JSON_CONTAINS(@j, @j2, '.c') |
+-------------------------------+
| 1 |
+-------------------------------+
JSON_CONTAINS_PATH()

语法:

JSON_CONTAINS_PATH(json_doc, one_or_all, path[, path] ...)
说明:
返回0或者1表示JSON文本的指定的某个路径或者某些路径下是否包含特定值。
当某些参数为NULL是否返回NULL
以下情况将报错:
参数json_doc为不合法JSON文本
path参数中包含不合法的路径
one_or_all参数为非’one’或者’all’的值
检测某个路径中是否包含某个特定值,使用 JSON_CONTAINS()代替
目标文本中如果没有指定的路径,则返回0。否则,返回值依赖于one_or_all值:
’one’: 文本中存在至少一个指定路径则返回1,否则返回0
‘all’: 文本中包含所有指定路径则返回1, 否则返回0
示例:
mysql> SET @j = '{"a": 1, "b": 2, "c": {"d": 4}}';
mysql> SELECT JSON_CONTAINS_PATH(@j, 'one', '.a', '.e');
+---------------------------------------------+
| JSON_CONTAINS_PATH(@j, 'one', '.a', '.e') |
+---------------------------------------------+
| 1 |
+---------------------------------------------+
mysql> SELECT JSON_CONTAINS_PATH(@j, 'all', '.a', '.e');
+---------------------------------------------+
| JSON_CONTAINS_PATH(@j, 'all', '.a', '.e') |
+---------------------------------------------+
| 0 |
+---------------------------------------------+
mysql> SELECT JSON_CONTAINS_PATH(@j, 'one', '.c.d'); +----------------------------------------+ | JSON_CONTAINS_PATH(@j, 'one', '.c.d') |
+----------------------------------------+
| 1 |
+----------------------------------------+
mysql> SELECT JSON_CONTAINS_PATH(@j, 'one', '.a.d'); +----------------------------------------+ | JSON_CONTAINS_PATH(@j, 'one', '.a.d') |
+----------------------------------------+
| 0 |
+----------------------------------------+
JSON_EXTRACT()

语法:

JSON_EXTRACT(json_doc, path[, path] ...)
说明:
返回json_doc中与path参数相匹配的数据。当有参数为NULl或者文本中未找到指定path时将返回NULL。当参数不合法时将报错。
返回结果包含所有与path匹配的值。如果返回多个值,则将自动包装为数组,其顺序为匹配顺序;相反则返回单个匹配值。
MySQL5.7.9及之后的版本将支持’->’操作符作为本函数两个参数时的便捷写法。->左边的参数为JSON数据的列名而不是一个表达式,其右边参数JSON数据中的某个路径表达式。详细使用方法将在文末详细阐述。
示例:
mysql> SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '[1]'); +--------------------------------------------+ | JSON_EXTRACT('[10, 20, [30, 40]]', '[1]') |
+--------------------------------------------+
| 20 |
+--------------------------------------------+
mysql> SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '[1]', '[0]');
+----------------------------------------------------+
| JSON_EXTRACT('[10, 20, [30, 40]]', '[1]', '[0]') |
+----------------------------------------------------+
| [20, 10] |
+----------------------------------------------------+
mysql> SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '[2][*]'); +-----------------------------------------------+ | JSON_EXTRACT('[10, 20, [30, 40]]', '[2][*]') |
+-----------------------------------------------+
| [30, 40] |
+-----------------------------------------------+

CLOUMN->PATH

语法:

CLOUMN->PATH(c->".id") 说明: 当与两个参数一起使用时, -> 运算符用作JSON_EXTRACT()函数的别名, 左边是列标识符,右边是JSON路径,根据JSON文档(列值)计算。您可以在SQL语句中的任何位置使用此类表达式代替列标识符 返回结果包含所有与path匹配的值。如果返回多个值,则将自动包装为数组,其顺序为匹配顺序;相反则返回单个匹配值。 MySQL5.7.9及之后的版本将支持’->’操作符作为本函数两个参数时的便捷写法。->左边的参数为JSON数据的列名而不是一个表达式,其右边参数JSON数据中的某个路径表达式。详细使用方法将在文末详细阐述。 SELECT这里显示 的两个语句产生相同的输出: mysql> SELECT c, JSON_EXTRACT(c, ".id"), g
> FROM jemp
> WHERE JSON_EXTRACT(c, ".id") > 1 > ORDER BY JSON_EXTRACT(c, ".name");
+-------------------------------+-----------+------+
| c | c->"$.id" | g |
+-------------------------------+-----------+------+
| {"id": "3", "name": "Barney"} | "3" | 3 |
| {"id": "4", "name": "Betty"} | "4" | 4 |
| {"id": "2", "name": "Wilma"} | "2" | 2 |
+-------------------------------+-----------+------+
3 rows in set (0.00 sec)

mysql> SELECT c, c->".id", g > FROM jemp > WHERE c->".id" > 1
> ORDER BY c->".name"; +-------------------------------+-----------+------+ | c | c->".id" | g |
+-------------------------------+-----------+------+
| {"id": "3", "name": "Barney"} | "3" | 3 |
| {"id": "4", "name": "Betty"} | "4" | 4 |
| {"id": "2", "name": "Wilma"} | "2" | 2 |
+-------------------------------+-----------+------+
3 rows in set (0.00 sec)

此功能不限 SELECT于此,如下所示:

mysql> ALTER TABLE jemp ADD COLUMN n INT;
Query OK, 0 rows affected (0.68 sec)
Records: 0 Duplicates: 0 Warnings: 0

mysql> UPDATE jemp SET n=1 WHERE c->"$.id" = "4";
Query OK, 1 row affected (0.04 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> SELECT c, c->".id", g, n > FROM jemp > WHERE JSON_EXTRACT(c, ".id") > 1
> ORDER BY c->".name"; +-------------------------------+-----------+------+------+ | c | c->".id" | g | n |
+-------------------------------+-----------+------+------+
| {"id": "3", "name": "Barney"} | "3" | 3 | NULL |
| {"id": "4", "name": "Betty"} | "4" | 4 | 1 |
| {"id": "2", "name": "Wilma"} | "2" | 2 | NULL |
+-------------------------------+-----------+------+------+
3 rows in set (0.00 sec)

mysql> DELETE FROM jemp WHERE c->"$.id" = "4";
Query OK, 1 row affected (0.04 sec)

mysql> SELECT c, c->".id", g, n > FROM jemp > WHERE JSON_EXTRACT(c, ".id") > 1
> ORDER BY c->".name"; +-------------------------------+-----------+------+------+ | c | c->".id" | g | n |
+-------------------------------+-----------+------+------+
| {"id": "3", "name": "Barney"} | "3" | 3 | NULL |
| {"id": "2", "name": "Wilma"} | "2" | 2 | NULL |
+-------------------------------+-----------+------+------+
2 rows in set (0.00 sec)

这也适用于JSON数组值,如下所示:

mysql> CREATE TABLE tj10 (a JSON, b INT);
Query OK, 0 rows affected (0.26 sec)

mysql> INSERT INTO tj10
> VALUES ("[3,10,5,17,44]", 33), ("[3,10,5,17,[22,44,66]]", 0);
Query OK, 1 row affected (0.04 sec)

mysql> SELECT a->"[4]" FROM tj10; +--------------+ | a->"[4]" |
+--------------+
| 44 |
| [22, 44, 66] |
+--------------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM tj10 WHERE a->"$[0]" = 3;
+------------------------------+------+
| a | b |
+------------------------------+------+
| [3, 10, 5, 17, 44] | 33 |
| [3, 10, 5, 17, [22, 44, 66]] | 0 |
+------------------------------+------+
2 rows in set (0.00 sec)

支持嵌套数组。使用的表达式 ->计算NULL 好像在目标JSON文档中找不到匹配的键,如下所示:

mysql> SELECT * FROM tj10 WHERE a->"$[4][1]" IS NOT NULL;
+------------------------------+------+
| a | b |
+------------------------------+------+
| [3, 10, 5, 17, [22, 44, 66]] | 0 |
+------------------------------+------+

mysql> SELECT a->"[4][1]" FROM tj10; +--------------+ | a->"[4][1]" |
+--------------+
| NULL |
| 44 |
+--------------+
2 rows in set (0.00 sec)

这与使用时的情况相同 JSON_EXTRACT():

mysql> SELECT JSON_EXTRACT(a, "[4][1]") FROM tj10; +----------------------------+ | JSON_EXTRACT(a, "[4][1]") |
+----------------------------+
| NULL |
| 44 |
+----------------------------+
2 rows in set (0.00 sec)
COLUMN->>PATH

这是一个改进的,不引用的提取操作符,可在MySQL 5.7.13及更高版本中使用。而 ->操作者简单地提取的值时, ->>在加法运算unquotes所提取的结果。换句话说,给定 JSON列值 column和路径表达式 path,以下三个表达式返回相同的值:

JSON_UNQUOTE( JSON_EXTRACT(column, path) )

JSON_UNQUOTE(column -> path)

->>只要JSON_UNQUOTE(JSON_EXTRACT())允许 ,操作员就可以使用 。这包括(但不限于) SELECT列表,WHERE和 HAVING条款,并ORDER BY和GROUP BY条款。

演示->>在mysql客户端中其他表达式的一些 运算符等价:

mysql> SELECT * FROM jemp WHERE g > 2;
+-------------------------------+------+
| c | g |
+-------------------------------+------+
| {"id": "3", "name": "Barney"} | 3 |
| {"id": "4", "name": "Betty"} | 4 |
+-------------------------------+------+
2 rows in set (0.01 sec)
mysql> SELECT c->'.name' AS name -> FROM jemp WHERE g > 2; +----------+ | name | +----------+ | "Barney" | | "Betty" | +----------+ 2 rows in set (0.00 sec) mysql> SELECT JSON_UNQUOTE(c->'.name') AS name
-> FROM jemp WHERE g > 2;
+--------+
| name |
+--------+
| Barney |
| Betty |
+--------+
2 rows in set (0.00 sec)
mysql> SELECT c->>'$.name' AS name
-> FROM jemp WHERE g > 2;
+--------+
| name |
+--------+
| Barney |
| Betty |
+--------+
2 rows in set (0.00 sec)

此运算符也可以与JSON数组一起使用,如下所示:

mysql> CREATE TABLE tj10 (a JSON, b INT);
Query OK, 0 rows affected (0.26 sec)

mysql> INSERT INTO tj10 VALUES
-> ('[3,10,5,"x",44]', 33),
-> ('[3,10,5,17,[22,"y",66]]', 0);
Query OK, 2 rows affected (0.04 sec)
Records: 2 Duplicates: 0 Warnings: 0

mysql> SELECT a->"[3]", a->"[4][1]" FROM tj10;
+-----------+--------------+
| a->"[3]" | a->"[4][1]" |
+-----------+--------------+
| "x" | NULL |
| 17 | "y" |
+-----------+--------------+
2 rows in set (0.00 sec)
mysql> SELECT a->>"[3]", a->>"[4][1]" FROM tj10;
+------------+---------------+
| a->>"[3]" | a->>"[4][1]" |
+------------+---------------+
| x | NULL |
| 17 | y |
+------------+---------------+
2 rows in set (0.00 sec)

与此同时 ->,->>运算符总是在输出中展开EXPLAIN,如下例所示:

mysql> EXPLAIN SELECT c->>'$.name' AS name
-> FROM jemp WHERE g > 2\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: jemp
partitions: NULL
type: range
possible_keys: i
key: i
key_len: 5
ref: NULL
rows: 2
filtered: 100.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
Level: Note
Code: 1003
Message: /* select#1 */ select
json_unquote(json_extract(jtest.jemp.c,'$.name')) AS name from
jtest.jemp where (jtest.jemp.g > 2)
1 row in set (0.00 sec)
这类似于MySQL -> 在相同情况下扩展 运算符的方式。

该->>操作符已添加到MySQL 5.7.13中。

JSON_KEYS()

语法:

JSON_KEYS(json_doc[, path])
说明:
返回JSON对象的顶层目录的所有key值或者path指定路径下的顶层目录的所有key所组成的JSON数组。
以下情况返回NULL
必填参数为NULL
json_doc非对象(为数组等)
当给定path,但是在JSON中未找到
以下情况报错
json_doc为不合法的JSON文本
path为不合法的路径表达
包含 * 或者 ** 通配符
当目标对象为空时,返回值为空。返回结果不包含顶层目录下的嵌套的目录中的key
示例:
mysql> SELECT JSON_KEYS('{"a": 1, "b": {"c": 30}}');
+---------------------------------------+
| JSON_KEYS('{"a": 1, "b": {"c": 30}}') |
+---------------------------------------+
| ["a", "b"] |
+---------------------------------------+
mysql> SELECT JSON_KEYS('{"a": 1, "b": {"c": 30}}', '.b'); +----------------------------------------------+ | JSON_KEYS('{"a": 1, "b": {"c": 30}}', '.b') |
+----------------------------------------------+
| ["c"] |
+----------------------------------------------+
JSON_SEARCH()

语法:

JSON_SEARCH(json_doc, one_or_all, search_str[, escape_char[, path] ...])
说明:
返回JSON包含指定字符串的路径。
以下情况将返回NULL
json_doc, search_str 或path 为NULL
文本中不包含path
search_str未找到
以下情况将报错
json_doc不合法
path不合法
one_or_all 不是one 或者all
escape_char 不是一个常量表达式
one_or_all的作用
’one’:当查找操作找到第一个匹配对象,并将结果路径返回后就停止查找。
‘all’:将返回所有的匹配结果路径,结果中不包含重复路径。如果返回结果集中包含多个字符串,将自动封装为一个数组,元素的排序顺序无意义。
在search_str中,通配符’%’和’‘可以如同LIKE操作上一样运行。’%’可以匹配多个字符(包括0个字符),’‘则仅可匹配一个字符。
‘%’或’_’作为特殊字符出现时,需要使用转义字符进行转义。当escape_char参数为NULL或者不存在的情况下,系统默认使用’\’作为转义字符。escape_char参数必须要常量(为空或者一个字符)
对于通配符的处理上与LIKE操作不同之处在于,JSON_SEARCH()中的通配符在编译时的计算结果必须要是常量,而不像LIKE仅需在执行时为常量。例如:在prepared Statement中使用JSON_SEARCH(), escape_char参数使用’?’作为参数,那么这个参数在执行时可能是常量,而不是在编译的时候。(这句话自己也没怎么懂,想了很久没想到该怎么翻译)
示例:
mysql> SET @j = '["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]';

mysql> SELECT JSON_SEARCH(@j, 'one', 'abc');
+-------------------------------+
| JSON_SEARCH(@j, 'one', 'abc') |
+-------------------------------+
| "$[0]" |
+-------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', 'abc');
+-------------------------------+
| JSON_SEARCH(@j, 'all', 'abc') |
+-------------------------------+
| ["[0]", "[2].x"] |
+-------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', 'ghi');
+-------------------------------+
| JSON_SEARCH(@j, 'all', 'ghi') |
+-------------------------------+
| NULL |
+-------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', '10');
+------------------------------+
| JSON_SEARCH(@j, 'all', '10') |
+------------------------------+
| "$[1][0].k" |
+------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', '10', NULL, ''); +-----------------------------------------+ | JSON_SEARCH(@j, 'all', '10', NULL, '') |
+-----------------------------------------+
| "$[1][0].k" |
+-----------------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '[*]'); +--------------------------------------------+ | JSON_SEARCH(@j, 'all', '10', NULL, '[*]') |
+--------------------------------------------+
| "$[1][0].k" |
+--------------------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '**.k'); +---------------------------------------------+ | JSON_SEARCH(@j, 'all', '10', NULL, '**.k') |
+---------------------------------------------+
| "$[1][0].k" |
+---------------------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '[*][0].k'); +-------------------------------------------------+ | JSON_SEARCH(@j, 'all', '10', NULL, '[*][0].k') |
+-------------------------------------------------+
| "$[1][0].k" |
+-------------------------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '[1]'); +--------------------------------------------+ | JSON_SEARCH(@j, 'all', '10', NULL, '[1]') |
+--------------------------------------------+
| "$[1][0].k" |
+--------------------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', '10', NULL, '[1][0]'); +-----------------------------------------------+ | JSON_SEARCH(@j, 'all', '10', NULL, '[1][0]') |
+-----------------------------------------------+
| "$[1][0].k" |
+-----------------------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', 'abc', NULL, '[2]'); +---------------------------------------------+ | JSON_SEARCH(@j, 'all', 'abc', NULL, '[2]') |
+---------------------------------------------+
| "$[2].x" |
+---------------------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', '%a%');
+-------------------------------+
| JSON_SEARCH(@j, 'all', '%a%') |
+-------------------------------+
| ["[0]", "[2].x"] |
+-------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', '%b%');
+-------------------------------+
| JSON_SEARCH(@j, 'all', '%b%') |
+-------------------------------+
| ["[0]", "[2].x", "$[3].y"] |
+-------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', '%b%', NULL, '[0]'); +---------------------------------------------+ | JSON_SEARCH(@j, 'all', '%b%', NULL, '[0]') |
+---------------------------------------------+
| "$[0]" |
+---------------------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', '%b%', NULL, '[2]'); +---------------------------------------------+ | JSON_SEARCH(@j, 'all', '%b%', NULL, '[2]') |
+---------------------------------------------+
| "$[2].x" |
+---------------------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', '%b%', NULL, '[1]'); +---------------------------------------------+ | JSON_SEARCH(@j, 'all', '%b%', NULL, '[1]') |
+---------------------------------------------+
| NULL |
+---------------------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', '%b%', '', '[1]'); +-------------------------------------------+ | JSON_SEARCH(@j, 'all', '%b%', '', '[1]') |
+-------------------------------------------+
| NULL |
+-------------------------------------------+

mysql> SELECT JSON_SEARCH(@j, 'all', '%b%', '', '[3]'); +-------------------------------------------+ | JSON_SEARCH(@j, 'all', '%b%', '', '[3]') |
+-------------------------------------------+
| "$[3].y" |
+-------------------------------------------+
三、修改JSON值的函数

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

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

JSON_ARRAY_APPEND()

语法:

JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ...)
说明:

在指定的数组末尾以JSON文本形式追加指定的值并返回。当参数中包含NULL时,返回NULL。
以下情况将报错
json_doc不合法
path 不合法
包含* 或者 ** 通配符
键值对采用自左到右的顺序进行追加。追加一对键值后的新值将成为下一对键值追加的目标。
如果指定目录下为标量或者对象值,则会被封装为数组,然后将新的值加入到数组中。对于不包含任何值得键值对将直接忽略。
示例:
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_ARRAY_INSERT(json_doc, path, val[, path, val] ...)
说明:
更新一个JSON文本,向文本中插入一个数组,然后返回修改后的文本。如果参数为NULL,则返回NULL。
以下情况报错
json_doc参数不合法
path不合法
包含 * 或者 ** 通配符
不是以数组标示结尾
键值对采用自左到右的顺序进行插入,插入一对后的新值将作为下一对插入的目标。
对于不包含任何值得键值对将直接忽略。如果path指定的是一个数组元素,则其对应的值将插入到该元素右边的任意位置;如果path指定的是数组的末尾,则其值将插入到该数组末尾。
执行插入操作后,其元素位置将发生变化,也将影响后续插入数据的位置定义。如最后的示例中,第二个插入数据并未出现数数据库中,是因为第一次插入操作后,原语句中定义的位置在新数据中未找到指定的元素,从而被忽略。
示例:
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参数是不是有效的路径表达式或包含一个 *通配符。

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

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

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

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

为了进行比较 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_PATCH(json_doc, json_doc[, json_doc] ...)

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

注意

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

JSON_MERGE_PATCH() 执行合并如下:

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

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

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

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

第二个对象的所有成员在第一个对象中没有对应的键,其值不是JSON null文字。

具有在第一个和第二个对象中存在的键的所有成员,并且其在第二个对象中的值不是JSON null 文字。这些成员的值是以递归方式将第一个对象中的值与第二个对象中的值合并的结果。

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}} |
+----------------------------------------------------+
JSON_MERGE_PATCH() MySQL 5.7.22及更高版本支持。

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")与这两个函数中的每一个进行合并的结果:

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参数不是有效的路径表达式或者是$或包含* 通配符,则会发生错误 。

该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参数是不是有效的路径表达式或包含一个 *通配符。

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

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

为了进行比较 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如果任何参数是 NULL或path,如果给,不定位的对象。如果发生错误 json_doc的参数是不是一个有效的JSON文档或任何path参数是不是有效的路径表达式或包含一个 *通配符。

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

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

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

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

否则,将忽略文档中不存在路径的路径 - 值对,但不起作用。

的JSON_SET(), JSON_INSERT()和 JSON_REPLACE()功能的关系:

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字符串文字,则会发生错误。

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

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

逃脱序列 由Sequence表示的字符
" 双引号(")字符
\b 退格字符
\f 一个换文字符
\n 换行符(换行符)
\r 回车符
\t 标签字符
\ 反斜杠(\)字符
\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 |
+----------------------------+
四、返回JSON值属性的函数

JSON_DEPTH(json_doc)

返回JSON文档的最大深度。NULL如果参数是,则 返回 NULL。如果参数不是有效的JSON文档,则会发生错误。

空数组,空对象或标量值具有深度1.仅包含深度为1的元素的非空数组或仅包含深度为1的成员值的非空对象具有深度2.否则,JSON文档的深度大于2。

mysql> SELECT JSON_DEPTH('{}'), JSON_DEPTH('[]'), JSON_DEPTH('true');
+------------------+------------------+--------------------+
| JSON_DEPTH('{}') | JSON_DEPTH('[]') | JSON_DEPTH('true') |
+------------------+------------------+--------------------+
| 1 | 1 | 1 |
+------------------+------------------+--------------------+
mysql> SELECT JSON_DEPTH('[10, 20]'), JSON_DEPTH('[[], {}]');
+------------------------+------------------------+
| JSON_DEPTH('[10, 20]') | JSON_DEPTH('[[], {}]') |
+------------------------+------------------------+
| 2 | 2 |
+------------------------+------------------------+
mysql> SELECT JSON_DEPTH('[10, {"a": 20}]');
+-------------------------------+
| JSON_DEPTH('[10, {"a": 20}]') |
+-------------------------------+
| 3 |
+-------------------------------+
JSON_LENGTH(json_doc[, path])

返回JSON文档的长度,或者,如果path给出参数,则返回 由路径标识的文档中的值的长度。返回NULL如果任何参数 NULL或path 参数不文档中确定的值。如果json_doc参数不是有效的JSON文档或 path参数不是有效的路径表达式或包含*或 **通配符,则会发生错误。

文件的长度确定如下:

标量的长度为1。

数组的长度是数组元素的数量。

对象的长度是对象成员的数量。

长度不计算嵌套数组或对象的长度。

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

JSON_TYPE(json_val)

返回utf8mb4表示JSON值类型的字符串。这可以是对象,数组或标量类型,如下所示:

mysql> SET @j = '{"a": [10, true]}';
mysql> SELECT JSON_TYPE(@j);
+---------------+
| JSON_TYPE(@j) |
+---------------+
| OBJECT |
+---------------+
mysql> SELECT JSON_TYPE(JSON_EXTRACT(@j, '.a')); +------------------------------------+ | JSON_TYPE(JSON_EXTRACT(@j, '.a')) |
+------------------------------------+
| ARRAY |
+------------------------------------+
mysql> SELECT JSON_TYPE(JSON_EXTRACT(@j, '.a[0]')); +---------------------------------------+ | JSON_TYPE(JSON_EXTRACT(@j, '.a[0]')) |
+---------------------------------------+
| INTEGER |
+---------------------------------------+
mysql> SELECT JSON_TYPE(JSON_EXTRACT(@j, '.a[1]')); +---------------------------------------+ | JSON_TYPE(JSON_EXTRACT(@j, '.a[1]')) |
+---------------------------------------+
| BOOLEAN |
+---------------------------------------+
JSON_TYPE()返回 NULL如果参数为 NULL:

mysql> SELECT JSON_TYPE(NULL);
+-----------------+
| JSON_TYPE(NULL) |
+-----------------+
| NULL |
+-----------------+
如果参数不是有效的JSON值,则会发生错误:

mysql> SELECT JSON_TYPE(1);
ERROR 3146 (22032): Invalid data type for JSON data in argument 1
to function json_type; a JSON string or JSON type is required.
对于NULL非非错误结果,以下列表描述了可能的 JSON_TYPE()返回值:

纯JSON类型:

OBJECT:JSON对象

ARRAY:JSON数组

BOOLEAN:JSON真假文字

NULL:JSON null文字

数字类型:

INTEGER:MySQL的 TINYINT, SMALLINT, MEDIUMINT和 INT和 BIGINT标量

DOUBLE:MySQL 标量 DOUBLE FLOAT

DECIMAL:MySQL DECIMAL和 NUMERIC标量

时间类型:

DATETIME:MySQL DATETIME和 TIMESTAMP标量

DATE:MySQL DATE标量

TIME:MySQL TIME标量

字符串类型:

STRING:MySQL的 utf8字符类型标量: CHAR, VARCHAR, TEXT, ENUM,和 SET

二进制类型:

BLOB:MySQL二进制类型标量: BINARY, VARBINARY, BLOB

BIT:MySQL BIT标量

所有其他类型:

OPAQUE (原始位)

JSON_VALID(val)

返回0或1以指示值是否为有效JSON。NULL如果参数是,则 返回NULL。

mysql> SELECT JSON_VALID('{"a": 1}');
+------------------------+
| JSON_VALID('{"a": 1}') |
+------------------------+
| 1 |
+------------------------+
mysql> SELECT JSON_VALID('hello'), JSON_VALID('"hello"');
+---------------------+-----------------------+
| JSON_VALID('hello') | JSON_VALID('"hello"') |
+---------------------+-----------------------+
| 0 | 1 |
+---------------------+-----------------------+

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270