解决SQL查询,in条件参数为带逗号的字符串⽽导致查询结果错误
问题描述:前端页⾯传参⼀个数组,⽽通过SpringMVC框架将数组⾃动转换了,如页⾯传参为[1,2,3],框架转换成“1,2,3”这样的字符串,所以我直接在sql中条件中拼接的in查询,写成in ( + 参数值 +)这种,然⽽sql执⾏的结果并不是我们想要的结果,如参数
中“1,2,3”,他总是只查询出了1,没有查询出2和3。
问题原因:
在MySQL中in⾥⾯的如果是字符串的话,会⾃动转化类型的,可能会转换成整数类型(SIGNED) ,类似内部使⽤了如下⽅法:
CAST(‘1,2’ AS SIGNED),导致’1,2‘ 变成了1,所以上述查询sql结果只有第⼀个。
验证如上结论:
我们须知道如果字符串‘1,2’转换成整数会是1:
以我的某张表为例,表中数据如下:
然后执⾏sql并观察结果,为了验证原因是否正确,我们可以查看sql的执⾏计划(通过explain extended加上show warnings,我们能够看到在sql真正被执⾏前优化器做了哪些改写):
可以很清楚地看到我们想要查询出‘1002’和‘1003’两条,但sql只查询出了⼀条,可以看到show warnings中的信息,
对‘1002,1003’这样的字符串进⾏了优化。
我们可以通过trace分析优化器是如何选择执⾏计划(注意:仅MySQL5.6及以上版本⽀持):
⾸先打开trace,设置格式为JSON,
设置trace最⼤能够使⽤的内存⼤⼩,避免因为默认内存过⼩⽽⽆法完整显⽰。
执⾏sql,并检查INFORMATION_SCHEMA.OPTIMIZER_TRACE就可以知道具体执⾏计划了。
可以看到最终优化后执⾏的sql如上,将in (‘1002,1003’) 优化成了id=1002 !!
知道了原因,我们就有对应的解决办法,对于这种被‘,’符号分开的⾃链组成的字符串,MySQL提供了⼀个很⽅便的函数
FIND_IN_SET(str,strlist),可以达到我们真正想达到的in效果。。
FIND_IN_SET(str,strlist)函数:
假如字符串str 在由N ⼦链组成的字符串列表strlist 中,则返回值的范围在 1 到 N 之间。⼀个字符串列表就是⼀个由⼀些被‘,’符号分开的⾃链组成的字符串。如果第⼀个参数是⼀个常数字符串,⽽第⼆个是type SET列,则 FIND_IN_SET() 函数被优化,使⽤⽐特计算。如果str不在strlist 或strlist 为空字符串,则返回值为 0 。如任意⼀个参数为NULL,则返回值为 NULL。这个函数在第⼀个参数包含⼀个逗号(‘,’)时将⽆法正常运⾏。返回值为str在strlist中的位置,从1开始计数。
数组转换成字符串所以最终sql可以这样写:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论