MySQL中无原生集合类型,JSON数组仅是结构形式,不支持去重或交并补;JSON_CONTAINS对类型敏感;复杂集合操作需JSON_TABLE转行集再用SQL处理;高频关系查询应改用关联表。

MySQL JSON数组和集合不是一回事
MySQL 里没有原生的“集合”数据类型,JSON 数组只是 JSON 值的一种结构形式,它不提供去重、交并补等集合运算能力。你存一个 ["a","b","a"],MySQL 完全接受——它不会自动去重,也不认为这是个“集合”。
用 JSON_CONTAINS() 判断元素是否存在,但要注意类型匹配
这是最常用的“类似集合成员判断”的操作,但它对类型敏感:
-
JSON_CONTAINS('["1", "2"]', '"1"')→1(字符串匹配) -
JSON_CONTAINS('[1, 2]', '1')→1(数字匹配) -
JSON_CONTAINS('[1, 2]', '"1"')→0(字符串"1"不等于数字1)
如果字段是 JSON 类型列 tags,查是否含标签 "mysql",得写成:
SELECT * FROM posts WHERE JSON_CONTAINS(tags, '"mysql"');
去重、交集、并集只能靠 SQL 拆解 + 临时表或 CTE
MySQL 8.0+ 提供 JSON_TABLE(),能把 JSON 数组转成行集,之后才能用标准 SQL 做集合操作:
- 想从
["a","b","a"]中取唯一值?得先JSON_TABLE展开,再DISTINCT - 想算两个 JSON 数组的交集?得分别展开,然后
INNER JOIN或IN子查询 - 没有内置
JSON_UNION()或JSON_INTERSECT()函数
例如提取唯一标签:
SELECT DISTINCT tag FROM posts, JSON_TABLE(tags, '$[*]' COLUMNS (tag TEXT PATH '$')) AS jt;
真正需要集合语义时,别硬扛 JSON 数组
如果业务频繁做成员判断、增删元素、求交并差,JSON 数组很快会成为性能和可维护性瓶颈:
-
JSON_SET()/JSON_REMOVE()每次都重写整个字段,无法部分更新 - 无法在 JSON 数组内部建索引(除非用生成列 + 虚拟列 + 普通索引)
- 复杂查询难写、难读、难优化
更稳的做法是拆成关联表,比如 post_tags(post_id, tag),加联合索引,该走索引就走索引。
JSON 数组适合存配置项、日志片段、前端直接消费的扁平列表——一旦涉及关系、约束、高频查询,它就不是集合,只是个字符串容器。










