开开心心写程序,程序出错,出错又出错。。。。。。。。。。卒
进入正题☞MySQL数字对比char类型,隐性转换
select * from t_pr_apply where APPLY_ID =532922233950044176;
这样的数据库语句,apply_id是varchar(32) 而后面很明显是数字
这样查出的结果是。。。。
一堆值,实际上,我只要一个值,结果是这么多,查了百度后发现,大概是这样的
where条件的类型自动转换,就是对于的类型不会装换,不对应的类型就会转换,
按照这样的说法,当where条件之后的值的类型和表结构不一致的时候,MySQL会做隐式的类型转换,所以我觉得我上面的那个18位的id是被转换了,而且有可能发生了数据截取,就是变成了 like ‘5329222339500441%’这样来查询,所以查询了这么多的数据。
但是经过测试数据,发现并不是上面我所说的那样子
但是确实好像是发生了隐性转换,并全表查询,产生了慢查询
为了解决这个困惑,我查询了官方文档
当运算符与不同类型的操作数一起使用时,会发生类型转换以使操作数兼容。某些转换是隐式发生的。例如,MySQL会根据需要自动将字符串转换为数字,反之亦然。
SELECT 1+'1';
-> 2
SELECT CONCAT(2,' test');
-> '2 test'
也可以使用该CAST()
函数显式地将数字转换为字符串。转换与CONCAT()
函数隐式发生, 因为它需要字符串参数。
mysql> SELECT 38.8, CAST(38.8 AS CHAR);
-> 38.8, '38.8'
mysql> SELECT 38.8, CONCAT(38.8);
-> 38.8, '38.8'
有关隐式数字到字符串转换的字符集以及适用于CREATE TABLE ... SELECT
语句的已修改规则的信息,请参阅本节后面的内容。
以下规则描述了比较操作的转换方式:
-
如果一个或两个参数都是
NULL
,则比较的结果是NULL
,除了NULL
-safe<=>
相等比较运算符。因为NULL <=> NULL
,结果是真的。无需转换。 -
如果比较操作中的两个参数都是字符串,则将它们作为字符串进行比较。
-
如果两个参数都是整数,则将它们作为整数进行比较。
-
如果不与数字进行比较,十六进制值将被视为二进制字符串。
-
如果其中一个参数是a
TIMESTAMP
或DATETIME
列而另一个参数是常量,则在执行比较之前将常量转换为时间戳。这样做是为了更友好的ODBC。这不是针对参数的IN()
。为安全起见,在进行比较时始终使用完整的日期时间,日期或时间字符串。例如,要在使用BETWEEN
日期或时间值时获得最佳结果 ,请使用CAST()
显式将值转换为所需的数据类型。 -
如果其中一个参数是十进制值,则比较取决于另一个参数。如果另一个参数是十进制或整数值,则将参数作为十进制值进行比较,如果另一个参数是浮点值,则将参数作为浮点值进行比较。
-
在所有其他情况下,参数被比较为浮点(实数)。
有关将值从一种时间类型转换为另一种时间类型的信息,请参见第11.3.7节“日期和时间类型之间的转换”。
以下示例说明了将字符串转换为数字以进行比较操作:
SELECT 1 > '6x';
-> 0
SELECT 7 > '6x';
-> 1
SELECT 0 > 'x6';
-> 0
SELECT 0 = 'x6';
-> 1
为了比较字符串列和数字,MySQL不能使用列上的索引来快速查找值。如果 str_col
是索引字符串列,则在以下语句中执行查找时,不能使用索引:
SELECT * FROM tbl_name WHERE str_col=1;
这样做的原因是,有许多不同的字符串可以转换为价值1
,例如 '1'
,' 1'
或 '1a'
。
使用浮点数(或转换为浮点数的值)的比较是近似的,因为这些数字是不精确的。这可能会导致结果看起来不一致:
mysql> SELECT '18015376320243458' = 18015376320243458;
-> 1
mysql> SELECT '18015376320243459' = 18015376320243459;
-> 0
这样的结果可能会发生,因为值被转换为浮点数,它只有53位的精度并且可以舍入:
mysql> SELECT '18015376320243459'+0.0;
-> 1.8015376320243e+16
此外,从字符串到浮点以及从整数到浮点的转换不一定以相同的方式发生。整数可以由CPU转换为浮点数,而字符串在涉及浮点乘法的运算中逐位转换。
显示的结果将因系统而异,并且可能受计算机体系结构或编译器版本或优化级别等因素的影响。避免此类问题的一种方法是使用CAST()
以便不将值隐式转换为浮点数:
mysql> SELECT CAST('18015376320243459' AS UNSIGNED) = 18015376320243459; -> 1
到这里终于明白,为什么会查出这么多条数据了,原来都是精度惹的祸
SELECT '532922233950044176'+0.0;
SELECT '532922233950044175'+0.0
SELECT '532922233950044164'+0.0;
SELECT '532922233950044175'= 532922233950044176;
SELECT '532922233950044100'= 532922233950044176;
以上还是有些问题,就比如为什么'532922233950044100'= 532922233950044176;就不相等呢
至今对我来说仍是个迷。。。。。。。。☹
算了,还是直接解决问题吧,上面官方文档有介绍,虽然我这里是跟上面不太一样,但是原理是一样的
因为我传的是一段很长的数据,所以需要在java先进行的截取
我使用的是一个StringUtils 的工具类,里面含有split 的方法,将字符串用逗号分隔开来
先进行截图,存为数组,我这里存到数据库是用map,所以在数据库也要搞一搞
item对应的applyid 需要跟下面的#{applyid}的#{}里面的值对应。
foreach属性
属性 | 描述 |
item | 循环体中的具体对象。支持属性的点路径访问,如item.age,item.info.details。 具体说明:在list和数组中是其中的对象,在map中是value。 该参数为必选。 |
collection | 要做foreach的对象,作为入参时,List<?>对象默认用list代替作为键,数组对象有array代替作为键,Map对象用map代替作为键。 当然在作为入参时可以使用@Param("keyName")来设置键,设置keyName后,list,array,map将会失效。 除了入参这种情况外,还有一种作为参数对象的某个字段的时候。举个例子: 如果User有属性List ids。入参是User对象,那么这个collection = "ids" 如果User有属性Ids ids;其中Ids是个对象,Ids有个属性List id;入参是User对象,那么collection = "ids.id" 上面只是举例,具体collection等于什么,就看你想对那个元素做循环。 该参数为必选。 |
separator | 元素之间的分隔符,例如在in()的时候,separator=","会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样。该参数可选。 |
open | foreach代码的开始符号,一般是(和close=")"合用。常用在in(),values()时。该参数可选。 |
close | foreach代码的关闭符号,一般是)和open="("合用。常用在in(),values()时。该参数可选。 |
index | 在list和数组中,index是元素的序号,在map中,index是元素的key,该参数可选。 |