JSON数据类型是MySQL5.7.8开始支持的。在此之前,只能通过字符类型(CHAR、VARCHAR或TEXT)来保存JSON文档。
JSO数据类型具有的优势:
JSON 是 JavaScript Object Notation(JavaScript 对象表示法)的缩写,是一个轻量级的,基于文本的,跨语言的数据交换格式。易于阅读和编写。
JSON的基本数据类型:
[1,"abc",null,true,"11:05:00.000000",{"id":1}]
{"db":["mysql","oracle"],"id":123,"info":{"age":20}}
1)直接插入JSON格式的字符串
# 创建测试表
create table mytest(id BIGINT ,other json);
# 插入表数据
insert into mytest values(1,'[1, "abc", null, true, "00:00:00.000000"]');
2)使用函数,常用的有JSON_ARRAY()和JSON_OBJECT()
# 使用json_array()函数插入
insert into mytest values(2,json_array(2,'abc',null,true,now()));
# 使用json_object()函数插入
insert into mytest values(3,json_object('name','abc','time',now()));
注意:
MySQL5.7.x版本,如果插入键重复则会使用第一个键对应的值。
json_object('key1',10,'key2',20,'key1',30) 结果:{"key1":10,"key2":20}
MySQL8.0.x版本,如果插入键重复会使用最后出现的键对应的值。
json_object('key1',10,'key2',20,'key1',30) 结果:{"key1": 30,"key2":20}
以此数据为查询元数据
1)JSON_EXTRACT(json_doc,path[,path] ...)
json_doc是JSON文档,path是路径。该函数会从JSON文档提取指定路径(path)的元素。如果指定path不存在,会返回NULL。可指定多个path,匹配到的多个值会以数组形式返回。
数组的路径:
# 使用json_extract函数进行查询,通过下标来表示的。
select json_extract(other,'$[0]') as val from mytest;
# 使用json_extract函数进行查询,通过[M to N] 获取数组的子集。
select json_extract(other,'$[0 to 1]') as val from mytest;
# 使用$[last-1 to last],这里的 last 代表最后一个元素的下标
select json_extract(other,'$[last-1 to last]') as val from mytest;
# 使用$[*],获取数组中的所有元素
select json_extract(other,'$[*]') as val from mytest;
对象的路径:
# 如果 KEY 在路径表达式中不合法(譬如存在空格),则在引用这个 KEY 时,需用双引号括起来。
# 使用json_extract函数进行查询对象,通过 KEY 来获取属性值
select json_extract(other,'$.name') as val from mytest where id = 3;
select json_extract(other,'$."test a"') as val from mytest where id = 3;
select json_extract(other,'$.testArr[0]') as val from mytest where id = 3;
注意:以上两种语法,在MySQL5.7.x版本不支持,可以在MySQL8.0.x版本试一试。
select json_extract(other,'$.*') as val from mytest where id = 3;
# 网上其他示例:
# 这里的 $**.b 匹配 $.a.b 和 $.c.b
select json_extract('{"a": {"b": 1}, "c": {"b": 2}}', '$**.b');
# 结果:
[1, 2]
2)column->path
column->path,包括后面讲到的 column->>path,都是语法糖,在实际使用的时候都会转化为 JSON_EXTRACT。
column->path 等同于 JSON_EXTRACT(column, path) ,只能指定一个path。
注意:在MySQL5.7.x版本不支持,可以在MySQL8.0.x版本试一试。
select other->"$name" from mytest where id = 3;
同 column->path 类似,只不过其返回的是字符串。以下三者是等价的。
select other->'$.name',json_extract(c2, "$.name"),json_unquote(c2->'$.name'),c2->>'$.name' from mytest;
注意:在MySQL5.7.x版本不支持,可以在MySQL8.0.x版本试一试。
1)JSON_INSERT(json_doc, path, val[, path, val] ...)
插入新值。
仅当指定位置或指定 KEY 的值不存在时,才执行插入操作。另外,如果指定的 path 是数组下标,且 json_doc 不是数组,该函数首先会将 json_doc 转化为数组,然后再插入新值。
# 示例一:
select json_insert('1','$[0]',"10");
# 结果:
1
# 示例二:
select json_insert('1','$[1]',"10");
# 结果:
[1,"10"]
# 示例三:
select json_insert('["1","2"]','$[2]',"10");
# 结果:
["1", "2", "10"]
2)JSON_SET(json_doc, path, val[, path, val] ...)
插入新值,并替换已经存在的值。
如果指定位置或指定 KEY 的值不存在,会执行插入操作,如果存在,则执行更新操作。
set @j = '{ "a": 1, "b": [2, 3]}';
# 示例:
select json_set(@j, '$.a', 10, '$.c', '[true, false]');
#结果:
{"a": 10, "b": [2, 3], "c": "[true, false]"}
3)JSON_REPLACE(json_doc, path, val[, path, val] ...)
替换已经存在的值。
set @j = '{ "a": 1, "b": [2, 3]}';
# 示例:
select json_replace(@j, '$.a', 10, '$.c', '[true, false]');
# 结果:
{"a": 10, "b": [2, 3]}
1)JSON_REMOVE(json_doc, path[, path] ...)
删除 JSON 文档指定位置的元素。
# 数据格式:{"name":"123","time":"234"}
# 会删除other字段中的name属性及对应的值
select json_remove(other, '$.name') from mytest where id = 3;
# 数据格式:other: ["a", ["b", "c"], "d", "e"]
# 会删除other字段中数组下标为1的值
select json_remove(other, '$.[1]') from mytest;
# 结果:
["a", "d", "e"]
# 会删除other字段中数组下标为1的值,再根据新的结果,删除下标为2的值
select json_remove(@j, '$[1]','$[2]') from mytest;
# 结果:
["a", "d"]
# 会删除other字段中数组下标为1的值,再根据新的结果,删除下标为1的值
select json_remove(@j, '$[1]','$[1]') from mytest;
# 结果:
["a", "e"]
同 TEXT,BLOB 字段一样,JSON 字段不允许直接创建索引。
对文档中的元素进行查询,就需要用到 MySQL 5.7 引入的虚拟列及函数索引。
# 创建表及索引
create table t ( c1 json, c2 varchar(10) as (JSON_UNQUOTE(c1 -> "$.name")), index (c2) );
# 插入数据
insert into t (c1) values ('{"id": 1, "name": "a"}'), ('{"id": 2, "name": "b"}'), ('{"id": 3, "name": "c"}'), ('{"id": 4, "name": "d"}');
explain select * from t where c2 = 'a';
explain select json_extract(c1,'$.id') from t where c1->'$.name' = 'a';
以上可见,虚拟列和json类型的列结果分析是一样的。
explain select * from t where c2 = 'a';
explain select json_extract(c1,'$.id') from t where c1->'$.name' = 'a';
注意:在创建虚拟列时需指定 JSON_UNQUOTE,将 c1 -> "$.name" 的返回值转换为字符串。
小知识:
max_allowed_packet:指mysql服务器端和客户端再一次传送数据包的过程当中最大允许的数据包大小。