【问题标题】:MySQL select from INT columnMySQL 从 INT 列中选择
【发布时间】:2018-12-19 04:40:12
【问题描述】:

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

【问题讨论】:

    标签: mysql sql database select type-conversion


    【解决方案1】:

    MySQL 在类型转换方面表现得既快又松。将 char 隐式转换为数字时,只要是数字,它将从字符串开头获取字符,而忽略其余字符。在您的示例中,xxx 不是数字,因此 MySQL 仅采用初始的“20”。

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

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

    编辑:
    参考 cmets 关于性能的讨论 - 在客户端执行强制转换可能是最好的方法,因为当您知道不应该返回任何行时(即,当您输入的数字不是有效数字,例如“20x”)。

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

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

    【讨论】:

    • 这很不幸。唯一看起来不会影响性能的解决方案是在应用程序级别进行强制转换。
    • @MutindaBoniface 在应用程序中执行转换将是最好的解决方案,恕我直言,但请参阅我编辑的答案以了解另一种可能的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-12
    • 1970-01-01
    • 1970-01-01
    • 2016-07-22
    • 2011-05-19
    相关资源
    最近更新 更多