MySQL Json函数(5.7以上)

oracle mysql 5.7.8 之后增加了对json数据格式的函数处理,可更加灵活的在数据库中操作json数据,如可变属性、自定义表单等等都使用使用该方式解决。

在创建表时,可以使用“GENERATED ALWAYS AS” 与json中的某个字段关联,并创建虚拟字段使json字符串也可以添加索引。

1-- 创建测试json表 2 3CREATE TABLE `test_json` ( 4 `$json` json NOT NULL, 5 `userid` varchar(50) COLLATE utf8mb4_unicode_ci GENERATED ALWAYS AS (json_unquote(json_extract(`$json`,_utf8mb4'$."userid"'))) VIRTUAL, 6 `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, 7 `$createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, 8 `$updateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 9 `name` varchar(60) GENERATED ALWAYS AS ((json_extract(`$json`,_utf8mb4'$."name"') = TRUE)) VIRTUAL, 10 PRIMARY KEY (`id`), 11 KEY `by_userid` (`userid`) 12) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 13 14SET FOREIGN_KEY_CHECKS = 1;

创建json

json_array(val1,val2,val3...)

创建json数组

json_object(key1,value1,key2,value2...)

创建json对象

json_quote

将json转成json字符串类型

插入json数据

1-- 方式1 :直接插入json字符串 2insert into test_json (id,`$json`) values(1,'{"userid":"1","name":"test name","sex":"男"}'); 3 4-- 方式2 :使用json_object 5insert into test_json (id,`$json`) values(2,json_object("userid","2","name","test name2","sex","男")); 6 7-- 方式3 :组合使用 8insert into test_json (id,`$json`) values(3,json_object("userid","3","name","name3","sex","女","item",json_array("item1","item2","item3")));

查询json

json_contains(json_doc,val[,path])

判断是否包含某个json值

json_contains_path(json_doc,one_or_all,path[,path]...)

判断是否有某个路径

json_extract(json_doc,path[,path])

提取json值

column->path json_extract

简洁写法5.7.9开始支持

column->>path json_unquote(column -> path)

简洁写法5.7.13开始支持相当于

JSON_UNQUOTE(JSON_EXTRACT())

json_keys(json_doc[,path])

提取json中的键值结果为json数组

json_search(json_doc, one_or_all, search_str[,escape_char[,path]...])

按给定字符串关键字搜索json,返回匹配的路径

 搜索数组下的多个属性时可使用通配符“*”,如获取数组下对象的某属性$.item[*].name

1-- 判断是否包含某个json值 2 3-- 方式1 4select json_contains(`$json`,'{"name":"test name2"}') from test_json; 5 6-- 方式2 (请注意第二个参数,带双引号,官网案例是number类型) 7select json_contains(`$json`,'"name3"','$.name') from test_json; 8 9 10 11-- 判断json是否指定路径,one至少存在一条路径,all存在所有路径 12select json_contains_path($json,'one','$.item') from test_json; 13 14 15-- 获取json值 16-- 方式1 17select json_extract(`$json`,'$.item') from test_json; 18 19-- 方式2 简洁写法 20select `$json` -> '$.item' from test_json; 21 22-- 方式3 简洁写法,并取消字符串,可用于select\where\having子句 23select `$json` ->> '$.name' from test_json; 24 25 26-- 获取json中的key数组 27select json_keys($json) from test_json; 28 29 30-- 获取json中指定value的json_path 31select json_search($json,'one','item2') from test_json; 32 33-- 可使用通配符 34select json_search($json,'one','item%') from test_json; 35 36 37select json_search($json,'all','2') from test_json;

修改json

json_append (废弃)

废弃,MySQL 5.7.9开始改名为json_array_append

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

末尾添加数组元素,如果原有值是数值或json对 象,则转成数组后,再添加元素

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

插入数组元素

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

插入值(插入新值,但不替换已经存在的旧值)

json_merge(json_doc,json_doc[,json_doc]...)

合并json数组或对象

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

删除json数据

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

替换值(只替换已经存在的旧值)

json_set(json_doc,path,val[,path,val])

设置值(替换旧值,并插入不存在的新值)

json_unquote(val)

去除json字符串的引号,将值转成string类型

CAST('jsonString' as json)

可将json字符串转为json对象格式

1-- 修改json 2 3-- 只会给有item属性的json添加 4 5select json_array_append(`$json`,'$.item','new item') from test_json ; 6 7 8-- 会将对象转为数组 9 10select json_array_append(`$json`,'$.name','new item') from test_json ; 11 12-- 向数组指定位置插入,指定的json path必须是数组类型 13 14select json_array_insert(`$json`,'$.item[10]','new item') from test_json ; 15 16 17-- 添加新属性,如果没有新属性会增加 18select json_insert(`$json`,'$.address','北京') from test_json ; 19 20-- 修改原属性,如果没有属性会增加,如果有则不处理 21 22select json_insert(`$json`,'$.name','新名字') from test_json ; 23 24-- 也可向数组中插入 25select json_insert(`$json`,'$.item[10]','new item') from test_json ; 26 27-- 合并,根据属性进行合并,如有相同属性转为数组 28select json_merge(`$json`,`$json`) from test_json ; 29 30-- 添加新属性,合并数组 31select json_merge(`$json`,'{"company":"companyName","address":"address","item":["newItem"]}') from test_json ; 32 33-- 删除指定路径属性或数组值 34select json_remove(`$json`,'$.item','$.sex') from test_json ; 35 36select json_remove(`$json`,'$.item[0]','$.sex') from test_json ; 37 38-- 替换属性值 39select json_replace(`$json`,'$.sex','男') from test_json ; 40 41-- 替换没有的属性不做任何操作 42select json_replace(`$json`,'$.address','替换不存在的地址属性','$.item[20]','4444') from test_json ; 43 44-- 有的属性做替换值,没有的做添加 45select json_set(`$json`,'$.sex','男','$.address','替换不存在的地址属性','$.item[20]','4444') from test_json ; 46 47 48 49 50-- 原始获取json会带引号 51 52select `$json` -> '$.name' from test_json ; 53 54-- 可去除双引号 55select json_unquote(`$json` -> '$.name') from test_json ;

返回json属性

json_depth(json_doc)

返回json文档的最大深度

json_length(json_doc[,path])

返回json文档的长度

json_type(json_val)

返回json值得类型

json_valid()val

判断是否为合法json文档

1-- json属性最大深度 2select json_depth(`$json`) from test_json ; 3 4-- json对象则是属性数,数组则是数组长度 5select json_length(`$json`) from test_json ; 6 7-- 判断数据类型 8 9select json_type(`$json`) from test_json ; 10 11 12select json_type(`$json` -> '$.name') from test_json ; 13 14 15select json_type(`$json` -> '$.item') from test_json ;

json类型

ARRAY

JSON数组

BOOLEAN

JSON true和false字符串

NULL

JSON NULL字符串

数字类型

INTEGER

MySQL中 TINYINT, SMALLINT, MEDIUMINT, INT 和 BIGINT 

DOUBLE

MySQL中 DOUBLE FLOAT 

DECIMAL

DECIMAL 和 NUMERIC 

时间类型

DATETIME

MySQL中 DATETIME 和 TIMESTAMP 

DATE

MySQL中 DATE 

TIME

MySQL中 TIME 

字符串类型

STRING

MySQL字符串: CHAR, VARCHAR, TEXT, ENUM, 和 SET

二进制

BLOB

MySQL 二进制: BINARY, VARBINARY, BLOB

BIT

MySQL中 BIT

其他

OPAQUE

(raw bits)

JSON的存储结构及具体实现

引用:https://blog.csdn.net/qian\_xiaoqian/article/details/53128170

在处理JSON时,MySQL使用的utf8mb4字符集,utf8mb4是utf8和ascii的超集。由于历史原因,这里utf8并非是我们常说的UTF-8 Unicode变长编码方案,而是MySQL自身定义的utf8编码方案,最长为三个字节。具体区别非本文重点,请大家自行Google了解。

MySQL在内存中是以DOM的形式表示JSON文档,而且在MySQL解析某个具体的路径表达式时,只需要反序列化和解析路径上的对象,而且速度极快。要弄清楚MySQL是如何做到这些的,我们就需要了解JSON在硬盘上的存储结构。有个有趣的点是,JSON对象是BLOB的子类,在其基础上做了特化。

使用示意图更清晰的展示它的结构:

JSON文档本身是层次化的结构,因而MySQL对JSON存储也是层次化的。对于每一级对象,存储的最前面为存放当前对象的元素个数,以及整体占的大小。需要注意的是:

  • JSON对象的Key索引(图中橙色部分)都是排序好的,先按长度排序,长度相同的按照code point排序;Value索引(图中黄色部分)根据对应的Key的位置依次排列,最后面真实的数据存储(图中白色部分)也是如此

  • Key和Value的索引对存储了对象内的偏移和大小,单个索引的大小固定,可以通过简单的算术跳转到距离为N的索引

  • 通过MySQL5.7.16源代码可以看到,在序列化JSON文档时,MySQL会动态检测单个对象的大小,如果小于64KB使用两个字节的偏移量,否则使用四个字节的偏移量,以节省空间。同时,动态检查单个对象是否是大对象,会造成对大对象进行两次解析,源代码中也指出这是以后需要优化的点

  • 现在受索引中偏移量和存储大小四个字节大小的限制,单个JSON文档的大小不能超过4G;单个KEY的大小不能超过两个字节,即64K

  • 索引存储对象内的偏移是为了方便移动,如果某个键值被改动,只用修改受影响对象整体的偏移量

  • 索引的大小现在是冗余信息,因为通过相邻偏移可以简单的得到存储大小,主要是为了应对变长JSON对象值更新,如果长度变小,JSON文档整体都不用移动,只需要当前对象修改大小

  • 现在MySQL对于变长大小的值没有预留额外的空间,也就是说如果该值的长度变大,后面的存储都要受到影响

  • 结合JSON的路径表达式可以知道,JSON的搜索操作只用反序列化路径上涉及到的元素,速度非常快,实现了读操作的高性能

  • 不过,MySQL对于大型文档的变长键值的更新操作可能会变慢,可能并不适合写密集的需求

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )