在工作中遇到的一个问题。就是mysql的一个表中的一个字段是varchar类型的,这个字段用来存储身份证,身份证正好是18位的。但是在根据身份证号来查询用户的时候,忘了给这个查询条件的身份证号加上'',然后就产生了问题。
先来看表结构:
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0 ; -- ---------------------------- -- Table structure for kaoshi_user -- ---------------------------- DROP TABLE IF EXISTS `kaoshi_user`; CREATE TABLE `kaoshi_user` ( `ID` bigint ( 20 ) NOT NULL AUTO_INCREMENT COMMENT '用户ID' , `jgid` int ( 11 ) NULL DEFAULT NULL COMMENT '培训机构ID' , `examid` int ( 11 ) NULL DEFAULT NULL COMMENT '考试ID' , `username` varchar ( 10 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户姓名' , `createtime` datetime( 0 ) NULL DEFAULT CURRENT_TIMESTAMP ( 0 ), `sex` int ( 3 ) NULL DEFAULT 0 COMMENT '性别(1男,2女,0未知)' , `sfzh` varchar ( 50 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '身份证号' , `dwname` varchar ( 50 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '单位名称' , `zhiwu` varchar ( 20 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '职务' , `xzarea` varchar ( 30 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '行政区域' , `phone` varchar ( 20 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号' , `address` varchar ( 50 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '家庭住址,联系地址' , `examtime` int ( 11 ) NULL DEFAULT NULL COMMENT '考试剩余时间' , PRIMARY KEY (`ID`) USING BTREE, INDEX `sfzh`(`sfzh`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 236 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Records of kaoshi_user -- ---------------------------- INSERT INTO `kaoshi_user` VALUES ( 110 , 1 , 1 , '张三' , '2020-04-27 14:25:38' , 1 , '330382199602254678' , 'xxxx单位' , 'xxxx职务' , 'xxxx街道' , '15058977786' , 'xxx省xxx市xxxx' , 3326 ); INSERT INTO `kaoshi_user` VALUES ( 111 , 1 , 1 , '张三' , '2020-04-27 14:25:38' , 1 , '330382199602254672' , 'xxxx单位' , 'xxxx职务' , 'xxxx街道' , '15058977787' , 'xxx省xxx市xxxx' , 3600 ); INSERT INTO `kaoshi_user` VALUES ( 112 , 1 , 1 , '张三' , '2020-04-27 14:25:38' , 2 , '330382199602254675' , 'xxxx单位' , 'xxxx职务' , 'xxxx街道' , '15058977788' , 'xxx省xxx市xxxx' , 2444 ); INSERT INTO `kaoshi_user` VALUES ( 113 , 1 , 1 , '张三' , '2020-04-27 14:25:38' , 1 , '330382199602254679' , 'xxxx单位' , 'xxxx职务' , 'xxxx街道' , '15058977789' , 'xxx省xxx市xxxx' , 0 ); INSERT INTO `kaoshi_user` VALUES ( 114 , 1 , 1 , '张三' , '2020-04-27 14:25:38' , 1 , '330382199602254673' , 'xxxx单位' , 'xxxx职务' , 'xxxx街道' , '15058977790' , 'xxx省xxx市xxxx' , 3600 ); INSERT INTO `kaoshi_user` VALUES ( 115 , 1 , 1 , '张三' , '2020-04-27 14:25:38' , 2 , '330382199602254671' , 'xxxx单位' , 'xxxx职务' , 'xxxx街道' , '15058977791' , 'xxx省xxx市xxxx' , 3558 ); INSERT INTO `kaoshi_user` VALUES ( 128 , 1 , 3 , '张三' , '2020-05-06 09:59:31' , 1 , '330382199602254678' , 'xxxx单位' , 'xxxx职务' , 'xxxx街道' , '15058977786' , 'xxx省xxx市xxxx' , 3784 ); SET FOREIGN_KEY_CHECKS = 1 ;接着来看sql语句:
select * from kaoshi_user where sfzh=330382199602254675
这条sql语句 本来以为只会查出 身份证号是330382199602254675的用户,没想到查询结果如下图:
但是把sql语句修改一下,在身份证号那个条件语句用字符串来查询,而不是整数,如:
select * from kaoshi_user where sfzh='330382199602254675'
查出来的结果那就只有这一条了。
明显上述sql语句在条件加单引号是符合我的要求的。但是不明白为什么用整数数值来查询会出现问题,在网上查询资料发现关于这方面的资料也很少。
后来在查询了官方文档后(MySql官方文档表达式中隐式类型转换),知道了结果。
得出的结论如下:
在字符串和数值作比较的时候,字符串和数值都会转换成浮点数进行比较。
字符串在转浮点数时,如果字符串开头是数字,那就一直截取,直到截取到的不是数字是其他字符为止。若开头不是数字,那么转换数值类型的结果就直接取0。(如'123abc'转成的值是123,'ab123'取到的值是0)
在上述中,我的字符串存储的是18位varchar类型。由于在转换成浮点数的时候,数值太大会自动转换成科学计数法,而且浮点数的精度不准确,都是取近似值,所以会出现意外的内容。也就是说我的查询sql条件在用数值类型时,由于数值太大了,所以在转换成浮点数的时候变成了科学计数法,同理被查询的字段也被转换成了浮点数的科学计数法,又由于浮点数精度的不准确,导致查询结果出现不准确。
如果用了字符串字段,在查询的时候最好不要用数值(如整数之类的)来查询,因为如果用数值查询,也就是如上面说的,MySql会自动把表达式中的值都转换成浮点数。而这里索引字段varchar类型进行自动转换成了浮点数,导致了索引失效。