MySQL 中查询和操作JSON类型数据的方法
投稿:mrr
MySQL里把JSON数组转成多行列表,最推荐用JSON_TABLE(MySQL 8.0.4+),一条SQL就能把数组“打散”成行,不用在应用层循环解析,本文给大家介绍MySQL中查询和操作JSON类型的数据的方法,感兴趣的朋友一起看看吧
MySQL 5.7 开始原生支持 JSON 数据类型,8.0 进一步增强了JSON函数、JSON表、生成列索引能力。很多业务场景(扩展属性、动态配置、标签)会选择JSON字段存储,但是很多人只会简单插入,不清楚如何提取、修改、索引JSON内部数据,本文结合实战SQL讲解JSON的增删改查与避坑要点。
一、建表:JSON字段基础定义
创建测试表,使用json类型,不要用varchar代替原生JSON类型。原生JSON会做语法校验,非法JSON无法写入。
CREATE TABLE `product` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(100) NOT NULL, `ext_info` JSON COMMENT '扩展信息,JSON类型' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
二、插入JSON数据
可以直接写JSON字符串插入,MySQL会自动校验JSON合法性。
-- 插入单行JSON
INSERT INTO product(name,ext_info)
VALUES('手机', '{"color":"黑色","price":3999,"tags":["数码","5G"],"attr":{"weight":"200g"}}');
-- 多行插入
INSERT INTO product(name,ext_info)
VALUES
('电脑','{"color":"灰色","price":5999,"tags":["数码","笔记本"],"attr":{"weight":"1.2kg"}}'),
('耳机','{"color":"白色","price":299,"tags":["数码","音频"],"attr":{"weight":"8g"}}');三、查询JSON数据(核心)
1.->和->>提取JSON字段
->:返回JSON类型,保留引号->>:返回字符串,日常业务查询优先用 ->>,会去掉外层引号
-- 提取ext_info中的color SELECT id, name, ext_info -> '$.color' AS color_json, ext_info ->> '$.color' AS color_str FROM product;
$代表整个JSON对象,$.key 代表取key字段。
2. 查询JSON数组
JSON数组通过下标取值,下标从0开始:
-- 获取tags数组第0个元素 SELECT id, name, ext_info ->> '$.tags[0]' as tag1 FROM product;
3. JSON_CONTAINS 判断是否包含元素
常用于标签数组匹配,查找tags包含数码的商品
SELECT id,name,ext_info FROM product WHERE JSON_CONTAINS(ext_info->'$.tags', '"数码"');
4. JSON_EXTRACT 函数写法(等价 ->)
SELECT JSON_EXTRACT(ext_info, '$.price') FROM product;
四、更新JSON数据
使用JSON_SET、JSON_INSERT、JSON_REPLACE、JSON_ARRAY_APPEND
JSON_SET:存在则更新,不存在则新增(最常用)
-- 修改price,新增stock字段 UPDATE product SET ext_info = JSON_SET(ext_info, '$.price', 3799, '$.stock', 100) WHERE id=1;
JSON_INSERT:只新增,已有key不修改JSON_REPLACE:只修改,不存在key不新增JSON_ARRAY_APPEND:给数组追加元素
-- tags数组新增"快充"标签 UPDATE product SET ext_info = JSON_ARRAY_APPEND(ext_info, '$.tags', "快充") WHERE id=1;
JSON_REMOVE删除JSON内指定key
-- 删除stock字段 UPDATE product SET ext_info = JSON_REMOVE(ext_info, '$.stock') WHERE id=1;
五、JSON生成列 + 索引(重点优化)
原生JSON字段不能直接建索引,如果需要根据JSON内部字段快速检索,必须创建生成列,再给生成列加索引。
-- 新增生成列,提取price,然后创建索引 ALTER TABLE product ADD COLUMN ext_price INT GENERATED ALWAYS AS (ext_info ->> '$.price') STORED; CREATE INDEX idx_product_ext_price ON product(ext_price);
之后查询可以直接使用生成列,走索引:
SELECT * FROM product WHERE ext_price>3000;
注意:
STORED表示实际存储数据,VIRTUAL不存储(默认),InnoDB只能对STORED生成列建立索引。
六、JSON_TABLE:JSON数组转多行(MySQL8.0特有)
如果JSON里是数组,想要一行拆成多条记录,使用JSON_TABLE。
SELECT p.id, p.name, jt.tag FROM product p, JSON_TABLE( p.ext_info -> '$.tags', '$[*]' COLUMNS (tag VARCHAR(32) PATH '$') ) jt;
这条SQL会把tags数组的每一个元素单独一行输出,做统计、关联查询非常好用。
七、常用JSON函数汇总
| 函数 | 作用 |
|---|---|
| JSON_EXTRACT | 提取JSON值 |
| JSON_SET | 更新/新增json键 |
| JSON_REMOVE | 删除json键 |
| JSON_ARRAY_APPEND | 数组追加元素 |
| JSON_CONTAINS | 判断包含 |
| JSON_VALID | 判断字符串是否合法JSON |
| JSON_LENGTH | 获取JSON数组/对象长度 |
八、坑点总结
- 不要大量在
WHERE条件直接写ext_info->>'$.xxx',没有索引,全表扫描,高频查询字段一定要用生成列索引。 - JSON查询大小写敏感,匹配字符串时注意。
- MySQL5.7没有
JSON_TABLE,数组拆行需要在应用层处理。 - JSON字段不支持传统的联合索引,只能针对生成单列建索引。
- 复杂JSON嵌套层级很深时,查询性能会下降,核心字段尽量提为独立普通列。
九、选型建议
- 适合:动态扩展属性、不确定字段、少量查询筛选,数据结构经常变更。
- 不适合:需要频繁WHERE、JOIN、排序、统计的核心字段,优先单独建列。
到此这篇关于MySQL 中查询和操作JSON类型的数据的文章就介绍到这了,更多相关mysql查询和操作json内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
