登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  MySQL

MySQL JSON_CONTAINS_PATH 怎样判断 JSON 路径是否存在

来源:17golang原创

时间:2026-11-03 03:24:46 399浏览 收藏

我在给一张订单表补 JSON 条件时,最先遇到的不是语法不会写,而是把“路径不存在”“路径存在但值是 JSON null”和“路径存在但值不等于目标”混成了一个问题。判断路径本身是否存在,应该使用 JSON_CONTAINS_PATH();它返回 0 或 1,而不是把路径上的具体值拿来比较。

最小写法是 JSON_CONTAINS_PATH(json_doc, 'one', '$.profile.phone')。多个路径用 one 表示任意一个存在,用 all 表示全部存在;输入为 NULL 时结果是 NULL,JSON 文档或路径非法时会报错。

官方参考地址:https://dev.mysql.com/doc/refman/8.4/en/json-search-functions.html

先把“路径存在”和“值匹配”分开

JSON_CONTAINS_PATH()只问路径能不能在 JSON 文档中找到数据,不关心数据具体等于多少。若要判断某个值是否包含在指定路径中,才使用 JSON_CONTAINS()。这两个函数名字接近,但判断对象完全不同。

-- 建一个同时包含对象、数组和 JSON null 的示例文档
SET @doc = '{"profile":{"name":"Lin","phone":null},"items":[{"sku":"A1"}],"disabled":false}';

-- 只判断路径是否存在:phone 存在,即使它的值是 JSON null
SELECT JSON_CONTAINS_PATH(@doc, 'one', '$.profile.phone');

-- 判断路径上的具体值,不能用路径存在函数代替
SELECT JSON_CONTAINS(@doc, 'null', '$.profile.phone');

这里的关键是“有数据”不等于“值非空”。profile.phone 这个成员确实存在,所以路径判断可以得到 1;如果业务还要求它必须是一个可用号码,就要继续取值并做类型或格式判断。

MySQL JSON_CONTAINS_PATH 的 JSON 文档、one all 模式、多个路径与返回值关系说明图
图1:JSON_CONTAINS_PATH 参数与返回值边界的静态说明图,不是运行截图。

多个路径用 one 还是 all

第三个参数是 one_or_all,后面可以继续写多个 JSON 路径。我的经验是:登录或展示场景常问“任意一个字段是否存在”,用 one;提交前的结构约束常问“必需字段是否齐全”,用 all。

-- 任意一个路径存在就返回 1,适合兼容新旧字段名
SELECT JSON_CONTAINS_PATH(@doc, 'one', '$.profile.phone', '$.profile.mobile');

-- 所有必需路径都存在才返回 1,适合结构完整性判断
SELECT JSON_CONTAINS_PATH(@doc, 'all', '$.profile.name', '$.items');

one 和 all 只改变多路径的合取方式,不改变单一路径的含义。单独传一个路径时,两种模式的结果相同;真正容易出错的是把 one 当成“所有路径都存在”,或者在字段迁移期间误用 all 导致旧数据全部被过滤。

MySQL JSON 列、JSON_CONTAINS_PATH 表达式、路径节点和 WHERE 条件关系说明图
图2:JSON 路径存在判断接入查询条件的结构说明图,不是运行截图。

对象、数组和 JSON null 怎么判断

帮助读者理解 JSON_CONTAINS_PATH 的模式、路径输入和 0/1/NULL 返回语义。
图1:结构说明图,查看 one/all 与路径输入、返回值之间的静态关系;这不是运行截图。

JSON 路径可以指向对象成员,也可以指向数组下标或数组本身。数组下标超出范围时,那个具体路径不存在;而数组字段本身存在时,判断数组路径仍然可以返回 1。JSON null 也是一个真实的 JSON 值,不应直接当成“没有这个键”。

-- 对象成员存在,返回 1
SELECT JSON_CONTAINS_PATH(@doc, 'one', '$.profile.name');

-- 数组本身存在,返回 1;指定元素是否存在要看下标
SELECT JSON_CONTAINS_PATH(@doc, 'one', '$.items');
SELECT JSON_CONTAINS_PATH(@doc, 'one', '$.items[0].sku');
SELECT JSON_CONTAINS_PATH(@doc, 'one', '$.items[2].sku');

-- phone 的成员存在,但值是 JSON null;路径判断仍然只关心成员是否存在
SELECT JSON_CONTAINS_PATH(@doc, 'one', '$.profile.phone');

如果业务要区分三种状态,可以把路径判断和取值判断拆开:先用 JSON_CONTAINS_PATH 确认成员存在,再用 JSON_EXTRACT 或 -> 读取值,最后决定是否接受 JSON null。这样比用一个 IS NOT NULL 猜测字段结构更清楚。

把路径判断放进 WHERE 条件

帮助读者理解 JSON 根路径、嵌套对象、数组下标和特殊键名的静态结构。
图2:路径结构说明图,展示对象键、数组下标和特殊键名在判断中的关系;这不是数据库控制台截图。

实际查询中,我通常把它放在 WHERE 中筛选拥有某种 JSON 结构的记录。函数返回的是 0 或 1,因此可以直接作为条件;如果 JSON 列本身允许 NULL,则要先明确业务是排除这些行,还是把它们单独归类。

-- 只筛选 payload 中同时有 order_id 和 items 的记录
SELECT id, payload
FROM order_events
WHERE JSON_CONTAINS_PATH(payload, 'all', '$.order_id', '$.items');

-- 兼容两种版本字段:order_id 或 legacy_id 任意存在即可
SELECT id
FROM order_events
WHERE JSON_CONTAINS_PATH(payload, 'one', '$.order_id', '$.legacy_id');

这类条件适合做结构筛选,不等于已经完成业务校验。比如 $.items 存在,只能说明有这个路径,不代表它一定是非空数组;筛选后仍需要按业务类型、长度或元素内容继续判断。

返回 NULL 或报错时先查输入

我排查这类 SQL 时,会先把返回结果分成三组:0 表示指定路径都不存在;1 表示按 one 或 all 的规则满足存在条件;NULL 通常来自任意参数为 SQL NULL。JSON 文档不是合法 JSON、路径表达式非法,或者模式不是 one/all,则不是普通的 0,而是输入错误。

-- 用 CASE 把 SQL NULL 与明确的 0/1 分开显示
SELECT CASE
  WHEN JSON_CONTAINS_PATH(payload, 'one', '$.profile') IS NULL THEN '输入为 SQL NULL'
  WHEN JSON_CONTAINS_PATH(payload, 'one', '$.profile') = 1 THEN '路径存在'
  ELSE '路径不存在'
END AS path_state
FROM order_events;

-- 模式必须是 one 或 all;这里的拼写错误属于参数错误,不是“路径不存在”
SELECT JSON_CONTAINS_PATH(payload, 'any', '$.profile')
FROM order_events;

不要把所有异常都改写成“没有字段”。如果上游把一段损坏字符串写进 JSON 列,或者动态拼接出非法路径,继续吞掉错误会让数据问题延迟到更难排查的业务环节。

我会这样选择函数

要回答的问题优先使用结果重点
这个路径有没有数据JSON_CONTAINS_PATH0 或 1
路径上的值是否包含目标 JSONJSON_CONTAINS匹配结果
想读取路径上的值JSON_EXTRACT 或 ->提取出的 JSON 值
要求多个必需路径同时存在JSON_CONTAINS_PATH(..., 'all', ...)全部路径满足才为 1

对我来说,最稳的写法是先明确“我要判断结构、比较值,还是读取值”,再选择函数。只要把这一步写清楚,one、all 和 JSON null 的边界就不会被一个模糊的空值判断掩盖。

相关问题

JSON_CONTAINS_PATH 能判断路径上的值不为 NULL 吗?
不能。它判断路径是否有数据;如果需要排除 SQL NULL 或 JSON null,应先确认路径,再读取并按类型处理。

one 和 all 只有多个路径时才有区别吗?
是的。只传一个路径时两者结果相同;传多个路径时,one 是任意一个存在,all 是全部存在。

JSON_CONTAINS_PATH 返回 0 是 JSON 写错了吗?
不一定。合法 JSON 中路径不存在时本来就会返回 0;只有文档或路径表达式非法时,才应按输入错误排查。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>