Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > mysql查询和操作json

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字段

-- 提取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

  1. JSON_SET:存在则更新,不存在则新增(最常用)
-- 修改price,新增stock字段
UPDATE product
SET ext_info = JSON_SET(ext_info, '$.price', 3799, '$.stock', 100)
WHERE id=1;
  1. JSON_INSERT:只新增,已有key不修改
  2. JSON_REPLACE:只修改,不存在key不新增
  3. JSON_ARRAY_APPEND:给数组追加元素
-- tags数组新增"快充"标签
UPDATE product
SET ext_info = JSON_ARRAY_APPEND(ext_info, '$.tags', "快充")
WHERE id=1;
  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数组/对象长度

八、坑点总结

  1. 不要大量在WHERE条件直接写 ext_info->>'$.xxx',没有索引,全表扫描,高频查询字段一定要用生成列索引。
  2. JSON查询大小写敏感,匹配字符串时注意。
  3. MySQL5.7没有JSON_TABLE,数组拆行需要在应用层处理。
  4. JSON字段不支持传统的联合索引,只能针对生成单列建索引。
  5. 复杂JSON嵌套层级很深时,查询性能会下降,核心字段尽量提为独立普通列。

九、选型建议

到此这篇关于MySQL 中查询和操作JSON类型的数据的文章就介绍到这了,更多相关mysql查询和操作json内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文