首页/数据/SQL 速查/JSON_CONTAINS 与 jsonb 包含查询
函数速查60 条

JSON_CONTAINS 与 jsonb 包含查询

判断 JSON 里是否包含某个值或结构:MySQL 用 JSON_CONTAINS/JSON_CONTAINS_PATH,PostgreSQL 用 jsonb 的 @> 与存在运算符。

SQL 速查数据更新于 2026-10-13

JSON 包含查询是什么

判断 JSON 文档里是否包含某个值或结构:MySQL 用 JSON_CONTAINS 与 JSON_CONTAINS_PATH,PostgreSQL 用 jsonb 的 @> 包含运算符与 ? 系列键存在判断。它适合标签、属性这类半结构化数据,但索引必须配套才不至于全表扫描。

基本信息

MySQL 包含JSON_CONTAINS(target, candidate[, path])
MySQL 路径判断JSON_CONTAINS_PATH(doc, 'one' 或 'all', '$.a', '$.b')
MySQL 数组成员value MEMBER OF (json_array),或 JSON_CONTAINS
PostgreSQL 包含tags @> '["vip"]'::jsonb
PostgreSQL 键判断? 键存在、?| 任一键存在、?& 全部键存在
索引MySQL 多值索引(8.0.17+);PG 用 GIN

MySQL 写法

MySQL 写法
-- 数组里是否包含字符串 vip:candidate 是 JSON 文本,字符串要带双引号
SELECT * FROM users WHERE JSON_CONTAINS(tags, '"vip"');

-- 路径判断:all 表示两个路径都必须存在
SELECT * FROM users WHERE JSON_CONTAINS_PATH(doc, 'all', '$.a', '$.b');

-- 8.0.17+ 的多值索引,可加速数组包含查询
CREATE INDEX idx_tags ON users ((CAST(tags AS CHAR(16) ARRAY)));
SELECT * FROM users WHERE 'vip' MEMBER OF (tags);

PostgreSQL 写法

PostgreSQL 写法
SELECT * FROM users WHERE tags @> '["vip"]'::jsonb;   -- 数组包含
SELECT * FROM users WHERE doc ? 'status';              -- 顶层键存在
SELECT * FROM users WHERE doc ?| ARRAY['a','b'];        -- 任一键存在
SELECT * FROM users WHERE doc ?& ARRAY['a','b'];        -- 全部键存在

-- 包含查询配 GIN 索引;jsonb_path_ops 更省空间,但只支持 @>
CREATE INDEX idx_doc ON users USING gin (doc jsonb_path_ops);

两库对照

需求MySQL 8PostgreSQL
数组包含某值JSON_CONTAINS(tags,'"vip"')tags @> '[\"vip\"]'::jsonb
判断键存在JSON_CONTAINS_PATHdoc ? 'key'
多个键任一存在JSON_CONTAINS_PATH 配 onedoc ?| ARRAY[…]
多个键全部存在JSON_CONTAINS_PATH 配 alldoc ?& ARRAY[…]
索引支持多值索引(8.0.17+)GIN 索引

典型使用场景

  • 用户标签筛选:找出含某个标签的用户群
  • 属性过滤:按 JSON 里的渠道、来源、设备类型筛选
  • 数据完整性检查:确认必备的键都存在
  • 风控规则:把命中某个特征的记录单独拉出来
  • 配置查询:找出开启了某个开关的对象
  • 排查脏数据:找出缺少关键字段的记录
  • 权限校验:确认用户的权限数组里包含所需角色
  • 埋点分析:按事件参数里的取值筛出特定行为的人群
MySQL 的 candidate 参数必须是合法 JSON 文本:查字符串要写成 '"vip"'(带双引号),少写引号会成为非法 JSON 而报错,静默匹配不到的情况更难查。
包含判断是“结构包含”不是字符串包含:PG 的 @> 要求类型对齐,判断字符串要写成 '"vip"'::jsonb;MySQL 的 candidate 同理,两边都把值包成合法 JSON 才不会误判。
把 json(文本)列当 jsonb 用会付出代价:PostgreSQL 的 json 类型不支持 @>,也无法使用 GIN 索引,每次查询都要重新解析。建表时就选 jsonb,后期改类型需要重写整表。

易错点

  • MySQL candidate 少写引号:字符串值必须写成 '"vip"',写成 'vip' 会因非法 JSON 报错
  • 在 json 类型上做包含查询:PG 里 json 不支持 @>,也没有 GIN 索引可用,建表应选 jsonb
  • 包含查询没用上索引:数据量大时全表扫描,先确认索引类型与查询写法是否匹配
  • 忽略排序规则影响:MySQL 的 JSON 比较受列排序规则影响,需要精确匹配时显式指定
  • 把大 JSON 全量取回应用层再过滤:网络与内存开销远高于在库内用包含条件筛选,能下推就下推

数据来源与参考

  • MySQL 8.0 Reference Manual · JSON Functions
  • PostgreSQL Documentation · JSON Functions and Operators
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌