2016-04-24 43 views
0

我的MySQL db的表名为membertable。该表由两个字段组成,分别是memberidmembernamememberid字段的类型为integer,并使用从2001开始的auto_increment函数。 membername表的类型为varchar虽然在where子句中给定的值为假,但select语句返回数据

membertable有两个记录具有与上述相同的顺序。这些记录是这样的:

MEMBERID:2001 成员名称:约翰史密斯

MEMBERID:2002 成员名称:威尔·史密斯

,我发现一个很奇怪的,当我跑反对memberid领域SELECT声明。运行以下语句:

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

它返回第一个数据。

为什么会发生这种情况?没有记录memberid = 2001somecharacter。它看起来像MySQL只搜索前4个字符(2001年),并且当它找到相关数据(这是上面返回的数据)时,它会拒绝其余字符。

这怎么会发生?有什么办法可以关闭这种行为?

-

membertable使用innodb引擎

+0

你可以让[sqlfiddle.com](http://sqlfiddle.com)证明这种行为吗? – Terminus

回答

0

这是因为MySQL试图以“2001somecharacter”转换为数字,返回2001年

既然你一些比较字符串,您应该使用

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

以避免此行为。

或者正确地做,不会将您的搜索变量放在引号中,以便它必须是一个数字,否则它会由于语法错误而炸毁,然后在前端确认它是一个数字,然后传递查询。

sqlfiddle

0

你发现是一个expexted MySQL的行为。 MySQL从一开始就将varchar转换为一个整数。只要有数字字符可以很容易地转换,它们在转换过程中被包含。如果有字母,转换将停止返回到目前为止读取的数字字符串的整数值...

Here的这种行为在MySQL文档站点上的一些描述。不幸的是,它并没有在文中直接提到,但是有一个恰好显示这种行为的例子。

0

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

作为示范,加入0使字符串在数值上下文进行评估:

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

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

我不知道“关闭”或禁用此行为的方法。 (可能有一个sql_mode设置改变了这种行为,但这种改变很可能会影响正在工作的其他SQL语句,如果发生这种改变,这些SQL语句可能会停止工作。

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

但是,如果你需要做这个SELECT语句,其中一个方案是投/转换列作为一个字符串,然后做比较。

但是,可以有一些如果我们对处于WHERE子句中条件的列执行强制转换或转换(或任何函数),MySQL将无法对合适的指数。我们强制MySQL在表中每行行上执行上的转换/转换操作,并将结果与​​字面值进行比较。

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

如果我需要在SQL语句中进行这样的检查,我会做这样的事情:

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

第一行是做同样的事情,当前查询。这可以利用合适的索引。

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

如果字符串值有一个前导空格'2001',这也不会返回一行。第二个条件将评估为FALSE。

0

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

将字符串转换为数字需要尽可能多的前导字符,并且仍然是一个数字。所以'2001character'被视为数字2001

如果要在member_id中使用非数字字符,请将其设为VARCHAR
如果你只想要数字ID,然后拒绝'200.1character'