MySQL中查询和操作JSON类型的数据

前言:MySQL5.7 开始正式支持原生JSON字段,8.0进一步增强JSON函数能力。很多开发会直接把JSON存成VARCHAR,但原生JSON会校验格式,并且提供内置函数方便读取、修改、删除JSON内的key和数组。这篇博客包含建表、查询、新增、修改、删除JSON数据,附带常用函数和避坑点。

一、测试表准备

sql 复制代码
CREATE TABLE product (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    attr JSON COMMENT '商品扩展JSON属性'
);

-- 插入测试数据
INSERT INTO product(name, attr) VALUES 
('手机', '{"color":"黑色","price":3999,"tags":["旗舰","5G"],"detail":{"weight":"200g","screen":"6.7英寸"}}'),
('耳机', '{"color":"白色","price":299,"tags":["蓝牙","降噪"],"detail":{"weight":"8g","screen":null}}');

二、JSON查询操作

1. -> 和 ->> 提取JSON字段值(最常用)

  • ->:返回带双引号的JSON原始值
  • ->>:返回去掉双引号的字符串,日常查询优先用 ->>
sql 复制代码
-- 查询商品名称、颜色、价格
SELECT 
    name,
    attr->>'$.color' AS color,
    attr->>'$.price' AS price
FROM product;

读取嵌套对象:

sql 复制代码
SELECT name, attr->>'$.detail.weight' AS weight FROM product;

读取数组指定下标元素:

sql 复制代码
-- 获取tags数组第0个元素
SELECT name, attr->>'$.tags[0]' AS tag1 FROM product;

2. JSON_EXTRACT()

-> 本质就是 JSON_EXTRACT() 的简写形式

sql 复制代码
-- 等价 attr->>'$.color'
SELECT JSON_UNQUOTE(JSON_EXTRACT(attr, '$.color')) FROM product;

3. 根据JSON内的值作为WHERE条件过滤

sql 复制代码
-- 查询颜色为黑色的商品
SELECT name FROM product WHERE attr->>'$.color' = '黑色';

-- 查询价格大于1000
SELECT name FROM product WHERE attr->>'$.price' > 1000;

查找数组中是否包含指定元素

sql 复制代码
-- 查询tags数组里面包含"降噪"的商品
SELECT name FROM product 
WHERE JSON_SEARCH(attr, 'one', '降噪', null, '$.tags') IS NOT NULL;

参数说明:one 找到第一个匹配;all 查找全部匹配。

5. JSON_KEYS 获取JSON对象所有key

sql 复制代码
SELECT JSON_KEYS(attr) FROM product;

三、JSON写入(插入)

直接传入标准JSON字符串,或者使用JSON_OBJECT、JSON_ARRAY构造JSON:

sql 复制代码
-- 方式1:直接字符串
INSERT INTO product(name,attr) VALUES ('平板','{"color":"灰色","price":2499}');

-- 方式2:函数构造,不用手动写引号,不容易出错
INSERT INTO product(name,attr) VALUES (
'手表',
JSON_OBJECT("color","银色","price",1299,"tags",JSON_ARRAY("智能","防水"))
);

四、JSON更新操作

JSON_SET:有则更新,无则新增(开发首选)

sql 复制代码
UPDATE product
SET attr = JSON_SET(attr, '$.color', '深空灰', '$.stock', 100)
WHERE id = 1;

JSON_REPLACE:只更新已存在key,不存在则不处理

sql 复制代码
UPDATE product
SET attr = JSON_REPLACE(attr, '$.price', 3699)
WHERE id = 1;

JSON_INSERT:只新增key,已有key不会覆盖

sql 复制代码
UPDATE product
SET attr = JSON_INSERT(attr, '$.stock', 200)
WHERE id = 1;

JSON数组追加:JSON_ARRAY_APPEND

sql 复制代码
UPDATE product
SET attr = JSON_ARRAY_APPEND(attr, '$.tags', '快充')
WHERE id = 1;

JSON数组指定位置插入:JSON_ARRAY_INSERT

sql 复制代码
UPDATE product
SET attr = JSON_ARRAY_INSERT(attr, '$.tags[0]', '新品')
WHERE id = 1;

五、JSON删除操作 JSON_REMOVE

删除JSON对象key、数组元素

sql 复制代码
-- 删除stock字段
UPDATE product
SET attr = JSON_REMOVE(attr, '$.stock')
WHERE id = 1;

-- 删除数组下标1的元素
UPDATE product
SET attr = JSON_REMOVE(attr, '$.tags[1]')
WHERE id = 1;

⚠️ 删除数组多个元素:从大下标往小下标删,删除后数组下标自动前移,顺序正向删除会导致下标错乱。

六、JSON生成列 + 索引(性能优化重点)

原生JSON字段内部key查询不走索引,大数据量查询会全表扫描。可以创建生成列并建立索引:

sql 复制代码
-- 创建生成列,提取color字段
ALTER TABLE product ADD COLUMN color VARCHAR(50) GENERATED ALWAYS AS (attr->>'$.color') STORED;
-- 建立索引
CREATE INDEX idx_product_color ON product(color);

STORED:实际存储数据;VIRTUAL(默认)不占用存储空间,查询时实时计算,不支持加索引。

七、常见踩坑汇总

  1. **路径语法 不能省略** ,`.key,嵌套 .obj.key`(.obj.key`;数组 `) `.arr[0]`
  2. -> 带引号,->> 不带引号,做等值判断WHERE条件必须用 ->>
  3. JSON函数返回新JSON文档,UPDATE时必须赋值回字段 attr=JSON_SET(...),否则不生效
  4. JSON字段本身为NULL时,JSON_SET / JSON_REMOVE都会返回NULL,可用IFNULL(attr, JSON_OBJECT())兜底
  5. JSON数组查找JSON_SEARCH只能匹配字符串;数字类型无法直接搜索,需要转换
  6. 不要用LIKE模糊匹配JSON字符串,JSON内部空格、顺序变化会导致匹配失效
  7. 频繁查询JSON内部字段,优先拆成独立字段;JSON适合存储不常检索的扩展属性

八、函数速查表

函数 作用
JSON_EXTRACT 提取JSON值
JSON_SET 更新/新增key
JSON_REPLACE 仅更新已有key
JSON_INSERT 仅新增key
JSON_REMOVE 删除key/数组元素
JSON_ARRAY_APPEND 数组末尾追加
JSON_ARRAY_INSERT 数组指定位置插入
JSON_SEARCH 查找数组/对象内文本
JSON_OBJECT 构建JSON对象
JSON_ARRAY 构建JSON数组
相关推荐
一条破秋裤1 小时前
05_设备树自定义属性_写入读取验证
linux·网络·数据库
辛迪聊物业数字化1 小时前
物业数字化选型避坑:3步判断系统是否适配你的业态
数据库
砚底藏山河1 小时前
量化新手误区:因子计算与行情数据的工程化解耦
java·数据库·python·金融
程序 代码狂人1 小时前
SQL COUNT 统计 NULL 与空字符串 ‘‘ 差异(Oracle & Impala)
数据库·sql·oracle
for_ever_love__1 小时前
MySQL 8.0 表设计规范:从业务建模、约束到索引评审的完整方法
数据库·mysql·表设计·建表规范
这个DBA有点耶2 小时前
ELT工具选型:ETL与ELT差异、CDC同步机制与主流工具对比`
数据库·数据仓库·sql·database·dba·etl·数据库管理员
ITxiaobing20232 小时前
自研 IP 库与 AppsFlyer 地理位置判定不一致,该如何排查?
网络·数据库·tcp/ip
承渊政道2 小时前
Linux网络学习【应用层自定义协议与序列化实战:从手写序列化与反序列化到深入理解进程间关系与守护进程】
linux·网络·学习·ubuntu·json·序列化与反序列化
玩AI的奶茶2 小时前
什么情况适合租算力?一张场景对照表,加三个自测问题
大数据·linux·服务器·数据库·人工智能·python