MySQL查询精度丢失、varchar与bigint之间隐式类型转换的问题!

问题描述:

以下内容都是在MySQL版本8.0.21复现,其他版本不知道是否有这种问题

项目中需要两张表关联查询,A表数据755条,B表中的数据754条,AB两张表是一对一关系。我尝试找到两张表中有差异的数据,可是用sql却没能查出来,最后我使用文档比对工具将两个表中的所有id进行了比较,发现了问题!


问题复现:

我们开始复现一下上面的问题

准备两张表

CREATE TABLE `test_a` (
  `id` bigint NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `test_b` (
  `id` bigint NOT NULL COMMENT '主键',
  `a_id` varchar(64) NOT NULL COMMENT 'A表的主键',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

注意:a表中的id字段是bigint类型,b表中a_id的字段是varchar类型。
导入测试数据

INSERT INTO `test_a`(`id`, `name`) VALUES (1530375756270878722, '甲');
INSERT INTO `test_a`(`id`, `name`) VALUES (1530375756270878723, '乙');
INSERT INTO `test_a`(`id`, `name`) VALUES (1530375756281493249, '丙');

INSERT INTO `test_b`(`id`, `a_id`) VALUES (1, '1530375756270878722');
INSERT INTO `test_b`(`id`, `a_id`) VALUES (2, '1530375756281493249');

执行下面的sql

select * from test_b where a_id = 1530375756270878723

在这里插入图片描述
仔细观察图片发现,查询结果a_id和sql语句中的a_id并不一致,但是如果将sql语句中的a_id加上单引号,则不会查询到任何数据。


原因分析:

出现上面问题的原因是:在MySQL中当我们对不同类型的值进行比较的时候,为了使得这些数值可比较(也可以称为类型的兼容性),MySQL 会做一些隐式转换(Implicit type conversion)
//
MySQL官方文档中有一篇介绍关于比较函数与运算符的文档。其中写到,
Strings are automatically converted to numbers and numbers to strings as necessary. 意思是必要时字符串和数字之间会互相转换。
//
https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html

比如说:
select 1530375756270878723 = '1530375756270878722'; 这个sql返回的结果就是1,认为条件成立!
而select 1530375756270878723 = 1530375756270878722;返回的结果就是0,条件不成立!
MySQL在比较字符串和数值时,会将两者都转换成双精度浮点数进行比较,因为精度丢失,导致比较结果为true

解决方案:

1、统一字段类型,用bigint就都用bigint,用varchar都用varchar。这样不仅规范,而且可以避免两表联查时索引失效
2、查询语句的条件中严格按照字段的类型写查询值。避免mysql进行隐式转换。也同时可以避免索引失效
3、使用mysql提供的CAST()函数。

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值