现象:
一个主外键关联查询的场景,原本主键为”2105191446220001115“的数据,通过关联查询,查询出了”2105191446220001115“,”2105191446220001116“,”2105191446220001117“三条数据,
一时间超出了自己的认知范围,数据库本身是不可能犯这种低级错误的,那错误一定是在我们的代码本身,经排除,是由于数据库字段类型不一致,在查询时,由于字段类型转换,数据精度损失造成的。
背景:
- 数据库:MySql,版本:5.7.38,数据表主键类型为长整型(BigInt),最大长度20
- 程序生成一个19位的数据作为主键值
- 由于19位长整型数值在前端Javascript中会有精度损失,所以前后端交互时,将数值类型的主键转换为字符串,进行传递
之前已经发现了长整型在Javascript中会存在精度损失,所以从数据库读取数据时,进行了数据转换,后台程序的做法是通过CAST函数进行转换,如下所示,
-- 在Sql语句中,将一个整型数据,转换为字符串数据
CAST(NumericalOrderDetail AS CHAR (20)) AS NumericalOrderDetail
分析:
基于以上背景,在某个查询中,出现了开头说的,查询结果与预期不一致的情况,经排除,锁定了错误原因,如下图所示,
由于子查询中习惯性的对主键进行类型转换,而主查询中m的主键并没有进行类型转换,是长整型,有一种我无法证实的说法 Mysql中两个字段进行比较,如果类型不一致,会将类型小的字段自动转换为类型大的字段,然后进行比较,但在这个例子中,并不是将一个字段类型转换成了另一种,而是参与比对的双方都进行了转换,后来经过几次测试发现,这种情况下,前17位数据相同是可以匹配成功的,显然,最后2位数据,成了类型转换的牺牲品。
结论:
MySql中,进行join查询时,参与关联查询的字段,要保证类型的一致。
建议:如果采用20位长整型作为主键的数据,不要在Sql中直接进行类型转换,将转换放到程序代码,或ORM中进行,实现数据库层面与代码层面的职责隔离。
做程序多了,真是啥问题都能遇到......