Mut*_*ace 6 mysql sql database select type-conversion
我正在进行一些系统测试,并期待MySQL(5.7.21)的空结果,但对获得结果感到惊讶.
我的交易表看起来像这样:
Column Data type
----------------------------
id | INT
fullnames | VARCHAR(40)
---------------------------
Run Code Online (Sandbox Code Playgroud)
我有一些记录
--------------------------------
id | fullnames
--------------------------------
20 | Mutinda Boniface
21 | Boniface M
22 | Some-other Guy
-------------------------------
Run Code Online (Sandbox Code Playgroud)
我的示例查询:
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
Run Code Online (Sandbox Code Playgroud)
现在,当我尝试这些时,它变得有趣:
select * from transactions where id = "20xxx"; -- gives me 1 record - what is happening here?
Run Code Online (Sandbox Code Playgroud)
MySQL在这做什么?
MySQL通过类型转换快速而松散地播放.当隐式地将char转换为数字时,只要它们是数字,它将从字符串的开头获取字符,并忽略其余字符.在您的示例中,xxx不是数字,因此MySQL仅采用初始"20".
解决这个问题的一种方法(由于你失去了对你的列上可能有的索引的使用,这对于性能而言非常糟糕),就是明确地将数字方面转换为字符:
SELECT * FROM transactions WHARE (CAST id AS CHAR) = 20;
Run Code Online (Sandbox Code Playgroud)
编辑:
从注释中引用有关性能的讨论 - 在客户端执行转换为数字可能是最好的方法,因为当您知道不应返回任何行时,它将允许您避免向数据库发送查询(即,当您的输入不是有效数字时,例如"20x").
另一种方法是将输入转换为数字并再次转换为字符串,并比较长度.如果长度相同,则意味着输入字符串被完全转换为数字,并且没有字符被省略.这应该是OK WRT性能,因为这个比较是对输入的字符串执行的,而不是对列的值执行,如果条件通过输入的短路评估,则仍然可以使用列的索引:
SELECT *
FROM transactions
WHARE LENGTH(:input) = LENGTH(CAST(:input AS SIGNED)) AND id = :input;
Run Code Online (Sandbox Code Playgroud)