MySQL从INT列中选择

时间:2018-07-11 08:12:23

标签: mysql sql database select type-conversion

我正在做一些系统测试,并期望从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在这里做什么?

1 个答案:

答案 0 :(得分:7)

MySQL通过类型转换快速而轻松地运行。在将char隐式转换为数字时,只要字符是数字,它将从字符串的开头开始提取字符,而忽略其余字符。在您的示例中,xxx不是数字,因此MySQL仅采用首字母“ 20”。

解决此问题的一种方法(这对性能来说是可怕的,因为您失去了列上可能使用的索引的用法),是将数字侧显式转换为字符:

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

编辑:
从注释中重述关于性能的讨论-在客户端执行强制转换为数字可能是最好的方法,因为它使您可以避免在不知道应返回任何行的情况下(例如,当输入的数字无效,例如“ 20x”。

另一种方法是将输入转换为数字,然后再次转换为字符串,然后比较长度。如果长度相同,则表示输入字符串已完全转换为数字,并且未省略任何字符。 WRT性能应该不错,因为此比较是对输入的字符串而不是列中的值执行的,并且如果条件通过了输入的短路评估,则仍可以使用列的索引:

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