MySQL SELECT WHERE = 1649972899018952705 返回 '1649972899018952706' | MySQL 5.7

问题描述 投票:0回答:1

今天的故事是我得到了一些错误的结果,我找到了空洞日的原因

原因是我试图使用 BIGINT id 来等于 VARCHAR(64) id。

错误的SQL是:

select t1.id,t1.name,
       t2.id,t2.name
from location t1
     left join location t2 on t2.parent_id = t1.id
where id = 1649972899018952705

我不知道这个表是谁创建的,但事实是id的类型是BIGINT,parent_id的类型是VARCHAR(64)。

但是为什么?我试过这些:

select 1649972899018952705 = '1649972899018952706' # returns 1 
select  164997289901895270 = '164997289901895271'  # returns 1 
select  164997289901895271 = '164997289901895261'  # returns 1 
select   16499728990189527 = '164997289901895261'  # returns 0
select  164997289901895271 = '16499728990189526'   # returns 0
select   16499728990189527 = '16499728990189526'   # returns 0
select                   1 = '2'                   # returns 0

我猜MySQL会改变'1649972899018952706'或1649972899018952705的类型来操作,但是参数是怎么改变的,好像MySQL会截断它们。

我可以通过使用不同的 MySQL 版本得到不同的结果吗?

mysql mysql-5.7
1个回答
0
投票

在 MySQL 5.7(以及 MySQL 8.0)中,当一个参数是字符串而另一个是数字时,比较运算符的参数确实会转换为浮点数(双精度),如 12.3 表达式求值中的类型转换中所定义:

以下规则描述了比较操作如何进行转换:

  • [...]
  • 在所有其他情况下,参数作为浮点(双精度)数字进行比较。例如,字符串和数字操作数的比较是作为浮点数的比较进行的。

所以这就像在参数上调用

CAST(value AS DOUBLE)
(在 MySQL 8.0 中)然后比较它们。显式使用
CAST()
函数时看到如下结果:

SELECT CAST(1649972899018952705 AS DOUBLE), CAST('1649972899018952706' AS DOUBLE), CAST(1649972899018952705 AS DOUBLE) = CAST('1649972899018952706' AS DOUBLE);
+-------------------------------------+---------------------------------------+-----------------------------------------------------------------------------+
| CAST(1649972899018952705 AS DOUBLE) | CAST('1649972899018952706' AS DOUBLE) | CAST(1649972899018952705 AS DOUBLE) = CAST('1649972899018952706' AS DOUBLE) |
+-------------------------------------+---------------------------------------+-----------------------------------------------------------------------------+
|               1.6499728990189527e18 |                 1.6499728990189527e18 |                                                                           1 |
+-------------------------------------+---------------------------------------+-----------------------------------------------------------------------------+

文档还提到了一个解决方案,您可以在其中将一个参数转换为

UNSIGNED

(...) 避免此类问题的一种方法是使用 CAST(),这样一个值就不会隐式转换为浮点数:

mysql> SELECT CAST('9223372036854775807' AS UNSIGNED) = 9223372036854775806;
        -> 0

所以您可以在查询中使用这样的

CAST()
函数:

select t1.id,t1.name,
       t2.id,t2.name
from location t1
     left join location t2 on CAST(t2.parent_id AS UNSIGNED) = t1.id
where id = 1649972899018952705
© www.soinside.com 2019 - 2024. All rights reserved.