SQL:mybatis+foreach+like/in 健壮性实现多条件输入-多种匹配方式模糊查找/查找

项目场景:

项目背景为监控管理平台,告警配置板块,需要查询返回多个数据信息,其中需要对订阅人的查询返回功能进行优化,将原本的只能输入一个订阅人名字进行查询优化为输入多个订阅人名,以英文逗号分隔,返回包含他们的结果,同时带有模糊查找功能


问题描述:

源代码只有单一条件,即只需输入一个人名进行查找并返回结果即可,因此,只需要动态Sql同时使用like关键字,使用concat函数将%与动态数据拼接即可实现模糊查找功能。
仔细观察,这里的匹配为两种方式的匹配,即是否and该column取决于login_id或name的匹配,若两者之一满足条件(使用or关键字),那种这个数据就会最后显示出来,这一点也为我们后续的实现增加了难度。

  <!-- 原始查询   -->
            <if test="subscribeName.length != 0 and subscribeName!=null and subscribeName != 'null'">
                AND (IFNULL(s.login_id,'') LIKE
                    CONCAT('%',#{subscribeName},'%')
                OR IFNULL(l.name,'') LIKE
                    CONCAT('%',#{subscribeName},'%'))  
            </if>

原因分析:

首先我们从数据输入着手,观察接口可知原本为String类型的subscribeName,当多订阅人输入时,就变成了一个内部带英文逗号分隔的长字符串。为了保证可读性我们仍在xml文件中的sql语句修改。

要实现所有姓名的依次匹配,使用foreach进行一个遍历,遍历的数据来源为在foreach头部使用spilit将subscribeName分隔的数组。

在姓名分割时需要注意的是,如果用户错误输入了些空字段,要求我们具有健壮性依然能返回想要的结果,大致思想是replace方法或者trim方法,但实际上trim更优,我们后文讨论


解决方案:

方案一:foreach+in

在foreach中使用in来精准匹配,这是最开始想到的方法。虽然丧失了模糊查找的功能,但是这种方法最直观也容易理解,网上的资料也大多是使用in关键字。这种方法下我们使用两个foreach分别服务login_id和name。

<!--  使用in的查询   -->
            <if test="subscribeName!='' and subscribeName!=null and subscribeName != 'null'">
            and IFNULL(s.login_id,'')  in
            <foreach collection="subscribeName.split(',')" item="subscribeName" separator="," open="(" close=")">
                #{subscribeName}
            </foreach>
            or IFNULL(l.name,'')  in
            <foreach collection="subscribeName.split(',')" item="subscribeName" separator="," open="(" close=")">
                #{subscribeName}
            </foreach>
            </if>       

方案二: foreach+like+replaceAll

在每一轮遍历中,仍然使用concat拼接,进行模糊查找,使用两个foreach服务两个匹配方法,但不同之处在于foreach体的separator此时为or。
同时,我们在spilit分割前使用replaceAll将字符串中的所有空格去除掉

<!-- foreach内模糊查询like,同时使用replace除去所有空字段   -->
            <if test="subscribeName!='' and subscribeName!=null and subscribeName != 'null'">
                AND (IFNULL(s.login_id,'') LIKE
                <foreach collection="subscribeName.replaceAll('[\\[\\] ]','').split(',')" open="(" separator="or" close=")" item="subscribeName">
                    CONCAT('%',#{subscribeName},'%')
                </foreach>
                OR (IFNULL(l.name,'')) LIKE
                <foreach collection="subscribeName.replaceAll('[\\[\\] ]','').split(',')" open="(" separator="or" close=")" item="subscribeName">
                    CONCAT('%',#{subscribeName},'%'))
                </foreach>
            </if>     

方案三:foreach+like+trim

仔细想想,其实方案二的replaceAll存在不足之处,那就是我们在测试时往往只用随便随便起的名字,而实际上如果真的有外文名输入,那么空格若被一并去除,就会造成难以阅读的现象。
改进方法就是在每一轮foreach,使用trim将字段的首尾空格去掉即可。

<!-- 要在foreach语句里面使用trim    -->
            <if test="subscribeName!='' and subscribeName!=null and subscribeName != 'null'">
                AND (IFNULL(s.login_id,'') LIKE
                <foreach collection="subscribeName.split(',')" open="(" separator="or" close=")" item="subscribeName">
                    CONCAT('%',trim(#{subscribeName}),'%')
                </foreach>
                OR (IFNULL(l.name,'')) LIKE
                <foreach collection="subscribeName.split(',')" open="(" separator="or" close=")" item="subscribeName">
                    CONCAT('%',trim(#{subscribeName}),'%'))
                </foreach>
            </if>

以上即为本题所实现代码。

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值