MySQL松散比较,带有整数值的varchar字段上的WHERE会产生意外结果

时间:2013-11-10 21:13:52

标签: mysql sql string varchar

我最近在程序中发现了一个有趣的错误,它使用私钥为特定客户选择数据。请考虑以下事项:

SELECT `id` FROM (`customers`) WHERE `authenticationKey` = '#09209!ko2A-' LIMIT 1

密钥在请求时提供,并在进行查询之前进行适当的清理。但是,如果未提供密钥(应该在之前捕获;忽略该密钥),将产生类似于以下内容的查询:

SELECT `id` FROM (`customers`) WHERE `authenticationKey` = 0 LIMIT 1

哪个会从customers - 表中返回一行 - 尽管它存储了正确的字符串密钥,例如在第一个示例中。

authenticationKey - 字段的类型为VARCHAR(1024)

我的猜测是,这与松散的比较有关。造成这个问题的原因是什么,以及如何正确避免?

2 个答案:

答案 0 :(得分:4)

MySQL将尝试将数据强制转换为类似的类型。在这种情况下,它会尝试将字符串转换为数字。任何默认为0的字符串都无法理解。

待办事项

select 0 = 'banana'

看到这一点。

使您的查询与'0'而不是0进行比较会解决问题。

<强> Example SQLFiddle

答案 1 :(得分:1)

MySQL隐式将authenticationKey的前导字符转换为int,直到找到不是有效数字的字符。我想所有以非数字字符开头的行都被视为0。

例如,这会产生'b',因为强制的int值是1:

select (case when '1abc' = 0 then 'a' else 'b' end);

但这会产生'a',因为前导char不是有效数字,所以强制int值为0:

select (case when '#1abc' = 0 then 'a' else 'b' end);

应用程序应该避免这种情况。毕竟,为什么在没有给出密钥时使用0进行查询?