mysql从int列选择

wtlkbnrh  于 2021-06-21  发布在  Mysql
关注(0)|答案(1)|浏览(553)

我当时正在做一些系统测试,希望mysql(5.7.21)的结果是空的,但得到的结果让我很惊讶。
我的事务表如下所示:

Column        Data type
----------------------------
id           | INT
fullnames    | VARCHAR(40)
---------------------------

我有一些记录

--------------------------------
id           | fullnames
--------------------------------
20           | Mutinda Boniface
21           | Boniface M
22           | Some-other Guy
-------------------------------

我的示例查询:

select * from transactions where id = "20"; -- gives me 1 record which is fine
select * from transactions where id = 20; -- gives me 1 record - FINE as well

现在,当我尝试这些时,它变得有趣了:

select * from transactions where id = "20xxx"; -- gives me 1 record - what is happening here?

mysql在这里做什么??

falq053o

falq053o1#

mysql在类型转换方面又快又松。当隐式地将字符转换为数字时,只要字符是数字,它就会从字符串的开头开始,而忽略其余的字符。在你的例子中, `` 不是数字,所以mysql只取开头的“20”。
解决这个问题的一种方法(这对性能很糟糕,因为您可能会丢失对列的索引的用法)是显式地将数字端强制转换为字符:

SELECT * FROM transactions WHARE (CAST id AS CHAR) = 20;

编辑:
从注解中引用关于性能的讨论—在客户端对一个数字执行强制转换可能是最好的方法,因为这样可以避免在您知道不应返回任何行时(即,当您的输入不是有效的数字时,例如“20x”)向数据库发送查询。
另一种方法是将输入转换成一个数字,再转换回一个字符串,然后比较长度。如果长度相同,则表示输入字符串已完全转换为数字,且未省略任何字符。这应该是ok wrt性能,因为此比较是在输入的字符串上执行的,而不是在列中的值上执行的,并且如果条件通过输入的短路评估,则仍然可以使用列的索引:

SELECT *
FROM   transactions 
WHERE  LENGTH(:input) = LENGTH(CAST(:input AS SIGNED)) AND id = :input;

相关问题