MyBatis 精确查询逗号分隔字符串

MyBatis实战:如何精确查询逗号分隔字符串中的目标值?

在日常开发中,我们经常会遇到这样的场景:数据库某个字段存储的是逗号分隔的字符串(比如 "44,4401" 或 "4401,44"),需要精确查询包含某个独立值(比如 "44")的记录。

如果直接用 LIKE '%44%',很容易误匹配到 "4401"、"144" 这类包含 "44" 但并非目标值的情况。今天就来分享一种在 MyBatis 中高效解决这个问题的方案。

问题场景再现

假设数据库表 t_code 中有一个字段 codes,存储的值可能是:

  • "44,4401"(44 和 4401 两个值)
  • "4401,44"(4401 和 44 两个值)
  • "44"(单独的 44)
  • "4401"(不含 44,仅 4401)

现在需要查询所有 codes 中包含独立的 "44" 的记录,预期结果是前三种情况,而 "4401" 不应被匹配。

为什么普通 LIKE 不行?

如果直接写:

sql 复制代码
SELECT * FROM t_code WHERE codes LIKE '%44%'

此时 "4401" 会被误匹配(因为字符串中包含 "44"),不符合「精确查询独立值」的需求。

核心解决方案:用逗号"包裹"目标值

关键思路是:让目标值和字段中的每个子项都处于相同的"逗号包围"状态,再进行匹配。

具体操作:

  1. 给数据库字段 codes 前后各拼接一个逗号,变成 ",原字符串,"(比如 "44,4401" 变成 ",44,4401,");
  2. 给目标值前后也各拼接一个逗号,变成 ",目标值,"(比如 "44" 变成 ",44,");
  3. 用 LIKE 判断拼接后的字段是否包含拼接后的目标值。

这样就能确保只匹配独立的子项,不会误判包含目标值的其他字符串。

MyBatis 代码实现

1. Mapper.xml 编写 SQL

在 Mapper.xml 中,通过 CONCAT 函数完成拼接,SQL 如下:

xml 复制代码
<select id="selectByTargetCode" resultType="com.example.entity.CodeEntity">
    SELECT * FROM t_code
    WHERE 
        -- 字段前后加逗号,目标值前后加逗号,确保精确匹配独立项
        CONCAT(',', codes, ',') LIKE CONCAT('%,', #{targetCode}, ',%')
</select>
  • CONCAT(',', codes, ','):给字段值前后加逗号(处理边界情况,比如值在开头或结尾);
  • CONCAT('%,', #{targetCode}, ',%'):给目标值前后加逗号,并用 % 匹配任意位置。

2. Mapper 接口定义

对应的 Mapper 接口需要接收目标值参数:

java 复制代码
public interface CodeMapper {
    /**
     * 精确查询包含目标值的记录
     * @param targetCode 目标值(如"44")
     * @return 匹配的记录列表
     */
    List<CodeEntity> selectByTargetCode(@Param("targetCode") String targetCode);
}

3. 效果验证

数据库 codes 值 拼接后的值 目标值"44"拼接后 是否匹配 结果是否符合预期
"44,4401" ",44,4401," ",44," 是 符合
"4401,44" ",4401,44," ",44," 是 符合
"44" ",44," ",44," 是 符合
"4401" ",4401," ",44," 否 符合

方案优势

  1. 精确性:彻底避免误匹配(如"4401"不会被当作"44"查询出来);
  2. 通用性 :适用于任何数据库(CONCAT 和 LIKE 是 SQL 标准函数);
  3. 简洁性:无需复杂逻辑,一行 SQL 即可解决问题;
  4. 兼容性:无论目标值在字符串的开头、中间还是结尾,都能正确匹配。

注意事项

  • 如果字段可能为 NULL,建议先处理空值(比如 CONCAT(',', IFNULL(codes, ''), ','));
  • 若数据量极大,这种方式可能影响查询性能(因为 CONCAT 会使索引失效),此时建议考虑拆分字段为关联表(更符合数据库设计规范)。

总结

当需要在逗号分隔的字符串中精确查询独立值时,通过「前后拼接逗号 + LIKE 匹配」的方式,能简单高效地解决问题。这种方案在 MyBatis 中只需几行代码即可实现,兼容性和精确性都能得到保证。

相关推荐
灵晔君1 小时前
【MySQL】数据库基础
数据库·mysql·adb
香蕉大香蕉(06敬畏市场)1 小时前
MySQL 单点详解(03)
java·数据库·mysql·面试·八股·大厂实习
杨云龙UP3 小时前
MySQL 主从复制管理:暂停、恢复、清理主从关系及命令执行位置
运维·数据库·mysql·主从配置·主从命令·reset replica·清除复制
霂鳯3 小时前
新手勇闯网络安全 | MySQL复习
mysql·安全·web安全
凤凰院凶涛QAQ4 小时前
《MySQL内核拆解:从SQL到InnoDB》(三) : 数据库设计 & 聚合查询 & 分组查询
数据库·sql·mysql
郝学胜-神的一滴4 小时前
AI 编程智能体 20:技术栈选型与架构落地全攻略
人工智能·python·架构·langchain·1024程序员节·智能体
Decay__5 小时前
01_MySQL 体系架构全解 —— 连接层、SQL 层、存储引擎层与 InnoDB 深入
运维·数据库·sql·mysql·架构
在多学一点5 小时前
MySQL_DDL的基本命令
数据库·mysql·adb
郭小李5 小时前
mybatis的 Mapper.xml语法
xml·java·mybatis
9624566 小时前
补打一条卡,为什么要从前一天重新算:人工补录与实时重算业务复盘
java·mysql·kafka