JSON_CONTAINS查嵌套数组中对象字段必须指定数组路径而非字段路径,正确写法是JSON_CONTAINS(JSON_EXTRACT(data, '$.items'), '{"id": 2}', '$'),错误写法如'$.items.id'会导致永远返回0。

MySQL 8.0+ 中用 JSON_CONTAINS 查嵌套数组是否包含某值
直接用 JSON_CONTAINS 查最外层数组没问题,但查「数组里的对象字段」必须配合路径表达式,否则永远返回 0。比如 {"items": [{"id": 1}, {"id": 2}]},想查有没有 id = 2 的项,不能写 JSON_CONTAINS(data, '2', '$.items.id') —— 这是常见错误,$.items.id 是路径,但 JSON_CONTAINS 要求路径指向数组本身,不是数组元素的字段。
正确做法是先用 JSON_EXTRACT 提取整个 items 数组,再对它做 JSON_CONTAINS:
SELECT * FROM orders
WHERE JSON_CONTAINS(
JSON_EXTRACT(data, '$.items'),
'{"id": 2}',
'$'
);-
JSON_EXTRACT(data, '$.items')返回一个 JSON 数组(如[{"id":1},{"id":2}]) - 第二个参数必须是完整对象字面量,不能只传
2 - 第三个参数
'$'表示在提取出的数组根节点上匹配,不是在原 JSON 的$.items.id
PostgreSQL 用 jsonb_path_exists 查嵌套数组中满足条件的对象
PostgreSQL 的 jsonb_path_exists 更直观,支持类似 XPath 的谓词语法,适合查「数组里某个对象字段等于某值」。例如查 tags 数组中是否存在 name = 'urgent' 的元素:
SELECT * FROM tasks WHERE jsonb_path_exists( metadata, '$.tags[*] ? (@.name == "urgent")' );
-
$.tags[*]遍历数组每个元素,@指代当前元素 - 注意双引号必须是英文,且字符串值要用双引号包裹(
"urgent"),单引号会报错 - 如果字段可能为
null,加&& @.name != null避免空值干扰判断 - 性能上,没建
jsonb_path_ops索引时,大表扫描会明显变慢
SQLite 3.38+ 用 json_each 展开嵌套数组再过滤
SQLite 没有原生路径查询函数,得靠 json_each 把数组“炸开”成行,再用普通 SQL 过滤。比如查 config.features 数组里是否有 enabled = true:
SELECT t.* FROM apps t, json_each(t.config, '$.features') j WHERE j.value LIKE '%"enabled":true%';
-
json_each第二个参数是路径,必须精确到数组字段('$.features'),不能写'$.features.enabled' -
j.value是每个数组元素的完整 JSON 字符串,所以用LIKE或json_extract(j.value, '$.enabled')都可以,后者更准但稍慢 - 如果数组为空或路径不存在,
json_each返回 0 行,所以结果自然为空,无需额外判空 - 注意别漏掉逗号连接表,写成
FROM apps t JOIN json_each(...)会导致无匹配行被丢弃
跨数据库通用陷阱:NULL 和类型不一致导致查不到
几乎所有 JSON 函数在遇到 NULL 字段、非 JSON 值或数字/字符串类型混淆时,都会静默失败——不报错,但返回 false 或空结果。比如 MySQL 的 JSON_EXTRACT 对非 JSON 字段返回 NULL,后续 JSON_CONTAINS 就失效;PostgreSQL 的 jsonb_path_exists 遇到 text 类型字段(不是 jsonb)直接报错。
- 先用
JSON_VALID()(MySQL)或jsonb_typeof()(PostgreSQL)确认字段确实是 JSON - 查数字字段时,确保传入的值类型一致:MySQL 中
1和"1"不等价,PostgreSQL 里1和"1"在路径表达式里也不等价 - SQLite 的
json_valid()只能判断顶层是否合法,嵌套结构错误(如数组里混了逗号)可能逃过检测
嵌套越深,路径写错的概率越高,建议先用 JSON_PRETTY 或 jsonb_pretty 看一眼实际结构,再动手写路径。


















