为什么MySQL返回看似与WHERE子句不匹配的行?

时间:2013-03-30 06:30:34

标签: mysql sql select

假设用户输入

mysite.com/profile?identity=1
mysite.com/profile?identity=dinodsja
mysite.com/profile?identity=1a

获取值

$identity = $_GET['identity']; // identity can be user_id or user_name

我有一个简单的选择查询:

SELECT * FROM lb_users WHERE (user_id = 'dinodsja' OR user_name = 'dinodsja') AND user_status = 1

它工作正常。但问题是:

SELECT * FROM lb_users WHERE (user_id = '1a' OR user_name = '1a') AND user_status = 1

当我执行此查询时,它还会返回结果而不满足条件

表格结构:

user_id     bigint(25)
user_name   varchar(50)     utf8_general_ci

enter image description here

**

-> Is this a MySQL Bug ? 
-> How can we avoid this ? 
-> What will be the query ?

**

6 个答案:

答案 0 :(得分:31)

原因是因为列user_ID的数据类型是整数。

MySQL默默地删除值中的任何尾随 非数字以及中的任何内容),这就是为什么{{1} }等于1a,因为1将在值中删除。

答案 1 :(得分:24)

我记得早就遇到过类似的问题了。

首先是一些背景:这是不是一个bug。它实际上是一个功能。好吧,它可能会导致这种意外行为,但MySQL因此非常宽容w.r.t.用户输入,相应的选择查询:

mysql> SELECT 'a' = 'a ';
        -> 1
mysql> SELECT 'A' = 'a';
        -> 1

因此,对于implicit type conversion,例如,INTEGER中的'1a'的结果为1,而且:

mysql> SELECT 0 = 'x6';
        -> 1
mysql> SELECT 1 = ' 1';
        -> 1
mysql> SELECT 1 = ' 1a';
        -> 1

此功能也在其他非静态类型语言中实现。例如,PHP调用此type juggling。请参阅文档中的PHP String conversion rules和此示例:

<?php
  $foo = "0";                     // $foo is string (ASCII 48)
  $foo += 2;                      // $foo is now an integer (2)
  $foo = $foo + 1.3;              // $foo is now a float (3.3)
  $foo = 5 + "10 Little Piggies"; // $foo is integer (15)
  $foo = 5 + "10 Small Pigs";     // $foo is integer (15)
?>

请参阅JavaScript

<script>
  document.write(parseInt("40 years") + "<br>");
</script>

=> 40

尽管如此,解决问题的方法非常简单:只需将整数转换为char,然后进行比较:

mysql> SELECT * FROM lb_users WHERE (CAST(user_id AS CHAR) = '1' OR user_name = '1')
        -> 1
mysql> SELECT * FROM lb_users WHERE (CAST(user_id AS CHAR) = '1a' OR user_name = '1a')
        -> 0
mysql> SELECT * FROM lb_users WHERE (CAST(user_id AS CHAR) = 'dinodsja' OR user_name = 'dinodsja')
        -> 1

我为每个人做了一个小提琴试试:http://sqlfiddle.com/#!2/c2835/14/0

希望有所帮助,

-Hannes

答案 2 :(得分:0)

根据您之前的消息

  

是个人资料的用户输入。用户可以提供user_id或user_name。   所以输入有效。但没有数据。 - DBK 3月30日6:42

我建议测试一下它是否为整数,只搜索用户ID(如果它是整数)。对于没有处理STRING到INT比较的mySQL来说,这实际上更像是一种解决方法,但它应该可行。

declare @InputVar varchar(10)
set @InputVar = '1a'

SELECT *  
FROM lb_users
WHERE  
  (case when isnumeric(@InputVar) = 1 then 
    case when (user_id = @InputVar OR user_name = @InputVar) then 1 else 0 end
  else  
    case when user_name = @InputVar then 1 else 0 end
  end =1 )
And 
  user_status = 1

答案 3 :(得分:0)

在处理字符串时,我会使用'LIKE'而不是'='来避免这种静默类型转换的疯狂。 LIKE可以使用字符串,所以为什么不使用它。

答案 4 :(得分:0)

SELECT * FROM lb_users WHERE (user_id = '1a' OR user_name = '1a') AND user_status = 1

如果你将'1a'改为1a,你会得到1个结果:

#1064 - 您的SQL语法出错;检查与MySQL服务器版本对应的手册,以便在第1行的“1a LIMIT 0,30”附近使用正确的语法

这不是错误,请查看http://dev.mysql.com/doc/refman/5.0/en/where-optimizations.html

希望这会有所帮助

答案 5 :(得分:0)

我认为你无法复制主键和ID,我测试了那个,我想出了一个正在运行的数据..你设置user_id的属性如下:

user_id bigint(50) auto_increment primary key

这不是mysql错误。