MySQL 8.0 查询JSON字段需用JSON_EXTRACT()或->提取值,注意返回带引号字符串;推荐JSON_CONTAINS()避免类型误判;高频查询应建虚拟列+索引,并用->>自动去引号。

用 JSON_EXTRACT() 提取 JSON 字段里的值
MySQL 8.0 原生支持 JSON,但直接用 = 或 LIKE 查 JSON 字段里的某个键基本无效——因为整个字段是字符串结构,数据库不会自动解析。必须用 JSON_EXTRACT()(或其简写 ->)显式提取。
比如表 users 有个 profile JSON 字段,存着 {"name": "Alice", "age": 30, "tags": ["dev", "mysql"]},想查 name 是 "Alice" 的记录:
SELECT * FROM users WHERE JSON_EXTRACT(profile, '$.name') = '"Alice"';
注意:返回值带双引号(JSON 字符串格式),所以右边也要加引号;如果用 -> 操作符,等价写法是:profile -> '$.name' = '"Alice"'。
- 路径表达式必须用单引号包裹,
$开头,键名用点号连接 - 数组元素用方括号,如
'$.tags[0]'取第一个 tag - 键名含空格或特殊字符时,要用引号:
'$.["full name"]'
用 JSON_CONTAINS() 判断对象是否存在某键值对
当你要查“某个键存在且等于某值”,又不想处理引号和类型转换,JSON_CONTAINS() 更稳妥。它把第二个参数当作“要匹配的 JSON 片段”,自动做类型和结构比对。
继续上面的例子,查 profile 中 age 等于 30(数值,不是字符串)的用户:
SELECT * FROM users WHERE JSON_CONTAINS(profile, '30', '$.age');
或者更明确地传对象:
SELECT * FROM users WHERE JSON_CONTAINS(profile, '{"age": 30}');
- 第三个参数(路径)可选,不填就整段匹配;填了就只在该路径下匹配
- 它能正确区分
30和"30",而JSON_EXTRACT()返回的是字符串,容易误判 - 性能上略低于直接
JSON_EXTRACT()+ 索引,但语义更清晰、容错更强
给 JSON 键建虚拟列 + 索引提升查询速度
频繁按 JSON 内某个键查数据?别每次都走全表 JSON 解析。MySQL 支持用虚拟列(AS)把 JSON 键“拎出来”,再加普通索引。
比如想按 profile->'$.status' 高频查询,可以加一列:
ALTER TABLE users ADD COLUMN status VARCHAR(20) AS (profile ->> '$.status') STORED;
注意用了 ->>(即 JSON_UNQUOTE(JSON_EXTRACT())),避免存多余的引号;STORED 表示物理存储,才能建索引:
CREATE INDEX idx_status ON users(status);
-
->>比->更常用,它自动去引号,结果是干净字符串或数字 - 虚拟列不能是
TEXT或BLOB类型,长度要预估好(如状态码用VARCHAR(10)足够) - 一旦加了索引,
WHERE status = 'active'就能走索引,不再触发 JSON 解析开销
常见报错和类型陷阱
查 JSON 字段时最常遇到的不是语法错,而是类型不一致导致的“查不到”。比如:
JSON_EXTRACT(profile, '$.score') 返回 "95.5"(字符串),但你写 = 95.5 就永远为 false;或者 JSON_CONTAINS(profile, '95.5', '$.score') 会失败,因为源 JSON 里存的是字符串 "95.5",而你传的是数字字面量。
- 用
JSON_TYPE()看实际类型:SELECT JSON_TYPE(profile -> '$.score') - 强制转类型可用
CAST(... AS SIGNED)或CAST(... AS DECIMAL(5,2)),但会影响索引使用 - 插入时就统一类型:数值字段别用
"95.5",直接写95.5(不加引号),MySQL 会存成 JSON number - 空值处理:JSON 中的
null不等于 SQL 的NULL,查JSON_CONTAINS(profile, 'null', '$.deleted')才能匹配{"deleted": null}
JSON 查询看着简单,但类型隐式转换和引号处理是高频翻车点,动手前先 SELECT profile -> '$.xxx' 看一眼真实返回值,比猜省半小时。











