MySQL JSON 数组查询实战:JSON_CONTAINS 用法详解与 LIKE 的本质区别

MySQL 中如何优雅地查询 JSON 数组字段(以及它和 LIKE 的区别)

很多业务表里都会有这么一个字段:

json
[{"uri":"/v1/xxx"}]

它是一个 JSON 数组,数组里是对象。
问题来了:

如果我想查出「数组中存在 uri = '/v1/xxx'」的记录,该怎么写 SQL?

再进一步:

这样写和 LIKE 有什么区别?

这篇文章把这个问题讲清楚。


一、推荐写法:JSON_CONTAINS

假设表结构:

  • 表名:api_table
  • 字段名:data
  • 类型:JSON(推荐)或 VARCHAR

查询语句:

sql
SELECT * FROM api_table WHERE JSON_CONTAINS( data, JSON_OBJECT('uri', '/v1/xxx') );

这句 SQL 做了两件事。


1️⃣ JSON_OBJECT 是什么?

sql
JSON_OBJECT('uri', '/v1/xxx')

它会生成:

json
{"uri":"/v1/xxx"}

也就是说,它只是帮你构造一个 JSON 对象,而不是手写 JSON 字符串。

这样可以避免转义错误,也更规范。


2️⃣ JSON_CONTAINS 是什么?

sql
JSON_CONTAINS(target, candidate)

意思是:

判断 target 这个 JSON 文档里,是否包含 candidate。

在我们的场景里,它实际在做类似这样的判断:

pseudo
for item in data_array: if item.uri == "/v1/xxx": return true

只要数组里有一个对象满足条件,就会匹配成功。


二、它的匹配规则是什么?

这是理解它的关键。

假设数据是:

json
[{"uri":"/v1/xxx","method":"GET"}]

你查询:

sql
JSON_CONTAINS(data, JSON_OBJECT('uri','/v1/xxx'))

仍然会匹配成功。

因为:

json
{"uri":"/v1/xxx","method":"GET"}

包含了:

json
{"uri":"/v1/xxx"}

它做的是“结构包含”,不是字符串比较。


三、为什么不直接用 LIKE?

很多人会写:

sql
WHERE data LIKE '%"/v1/xxx"%'

看起来简单直接,但问题不少。


❌ 问题一:误匹配

如果数据是:

json
[{"uri":"/v1/xxxx"}]

也会被匹配到。

因为 LIKE 只是字符串匹配。


❌ 问题二:依赖格式

JSON 里如果有空格:

json
{"uri" : "/v1/xxx"}

或者 key 顺序变化,匹配行为可能出现不可预期的结果。


❌ 问题三:语义不清晰

看到 LIKE '%xxx%',读代码的人无法一眼判断:

  • 是模糊查询?
  • 是结构查询?
  • 是精确匹配?

JSON_CONTAINS 非常明确:

在 JSON 结构里找对象。


四、两者本质区别

对比项JSON_CONTAINSLIKE
匹配方式结构匹配字符串匹配
是否严谨
是否容易误匹配不容易容易
可读性

简单说:

LIKE 是“文本层面的解决方案”。
JSON_CONTAINS 是“数据结构层面的解决方案”。

如果字段本身是 JSON,就应该用 JSON 的方式去查询它。


五、什么时候适合这样做?

这种写法适合:

  • 配置类字段
  • 半结构化数据
  • 不频繁过滤的场景

如果这个字段是核心查询条件,并且数据量很大,那可能需要重新考虑数据结构设计,而不是只纠结 SQL 写法。


六、总结

如果你只记住一句话:

当字段是 JSON,就用 JSON 函数查询,而不是用 LIKE 拼字符串。

JSON_OBJECT 用来构造 JSON。
JSON_CONTAINS 用来判断结构是否存在。

它的优势不在于“更快”,
而在于“更准确、更规范、更可维护”。

数据库查询,能用结构表达,就不要退回字符串匹配。

这往往是代码质量的分水岭。