Select语句返回数据,尽管where子句中的给定值为false

时间:2016-04-24 05:25:19

标签: mysql sql indexing

我的MySQL db上有一个名为membertable的表。该表由两个字段memberidmembername组成。 memberid字段的类型为integer,并使用从2001开始的auto_increment函数。 membername表的类型为varchar

membertable有两条记录,其顺序与上述相同。记录如下:

memberid:2001 会员名称:约翰史密斯

memberid:2002 会员名:将史密斯

当我针对SELECT字段运行memberid语句时,我发现了一些奇怪的东西。运行以下语句:

SELECT * FROM `membertable` WHERE `memberid` = '2001somecharacter'

它返回了第一个数据。

为什么会这样? memberid = 2001somecharacter没有记录。看起来MySQL只搜索前4个字符(2001),当它找到相关数据时,就是上面返回的数据,它会拒绝剩下的字符。

怎么会发生这种情况?有没有办法关闭这种行为?

-

membertable使用innodb引擎

4 个答案:

答案 0 :(得分:0)

这是因为mysql试图将“2001somecharacter”转换为返回2001的数字。

由于您要将数字与字符串进行比较,因此您应该使用

SELECT * FROM `membertable` WHERE CONVERT(`memberid`,CHAR) = '2001somecharacter';

避免这种行为。

要正确地执行,不要将您的搜索变量放在引号中,以便它必须是一个数字,否则它会因为语法错误而爆炸,然后在前端确保它是一个数字,然后传入查询

sqlfiddle

答案 1 :(得分:0)

您的发现是一种被驱逐的MySQL行为。 MySQL将varchar转换为从头开始的整数。只要存在可以轻松转换的数字字符,它们就会被包含在转换过程中。如果有一个字母,转换将停止返回到目前为止读取的数字字符串的整数值...

Here在MySQL文档站点上对此行为进行了一些描述。不幸的是,它没有直接在文中提及,但有一个例子可以准确地显示这种行为。

答案 2 :(得分:0)

在数值上下文中计算时,MySQL非常自由地将字符串值转换为数值。

作为演示,添加0会导致在数字上下文中计算字符串:

SELECT '2001foo' + 0   --> 2001 
     , '01.2-3E' + 0   --> 1.2
     , 'abc567g' + 0   --> 0

当在数字上下文中计算字符串时,MySQL会逐个字符地读取字符串,直到它遇到一个字符,其中字符串不能再被解释为数字值,或者直到它到达字符串的末尾。< / p>

我不知道如何关闭&#34;&#34;或禁用此行为。 (可能有一个sql_mode设置可以更改此行为,但可能该更改将影响正在工作的其他SQL语句,如果进行了更改,则可能会停止工作。

通常,这种参数检查是在应用程序中完成的。

但是如果你需要在SELECT语句中执行此操作,则会将一个选项转换/转换为字符串,然后进行比较。

但这会产生一些重大的性能影响。如果我们对WHERE子句中的条件中的列进行强制转换或转换(或任何函数),MySQL将无法对合适的索引使用范围扫描操作。我们强制MySQL在表中的每个行执行强制转换/转换操作,并将结果与​​文字进行比较。

所以,这不是最好的模式。

如果我需要在SQL语句中执行类似的检查,我会这样做:

  WHERE t.memberid = '2001foo' + 0 
    AND CAST('2001foo' + 0 AS CHAR) = '2001foo'

第一行与当前查询做同样的事情。这可以利用合适的指数。

第二个条件是将相同的值转换为数字,然后将其转换回字符,然后将结果与原始值进行比较。使用此处显示的值,它将评估为FALSE,并且查询将不返回任何行。

如果字符串值具有前导空格,那么这也不会返回一行,&#39; 2001&#39 ;.第二个条件是评估为FALSE。

答案 3 :(得分:0)

INT与'string'进行比较时,字符串将转换为数字。

将字符串转换为数字可以使用尽可能多的前导字符,但仍然是数字。因此'2001character'被视为数字2001

如果您想要member_id中的非数字字符,请将其设为VARCHAR 如果您只想要数字ID,请拒绝'200.1character'