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

Din*_*ino 22 mysql sql select

假设用户输入

mysite.com/profile?identity=1
mysite.com/profile?identity=dinodsja
mysite.com/profile?identity=1a
Run Code Online (Sandbox Code Playgroud)

获得价值

$identity = $_GET['identity']; // identity can be user_id or user_name
Run Code Online (Sandbox Code Playgroud)

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

SELECT * FROM lb_users WHERE (user_id = 'dinodsja' OR user_name = 'dinodsja') AND user_status = 1
Run Code Online (Sandbox Code Playgroud)

它工作正常.但问题是:

SELECT * FROM lb_users WHERE (user_id = '1a' OR user_name = '1a') AND user_status = 1
Run Code Online (Sandbox Code Playgroud)

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

表结构:

user_id     bigint(25)
user_name   varchar(50)     utf8_general_ci
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

**

-> Is this a MySQL Bug ? 
-> How can we avoid this ? 
-> What will be the query ?
Run Code Online (Sandbox Code Playgroud)

**

Joh*_*Woo 31

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

MySQL的默默丢弃任何尾随的 非数字(以及任何如下内)的价值,这就是为什么1a等于1,因为a将在值删除.

  • 我认为这是MySQL中的一个错误.每个其他DBMS都正确拒绝数字和非数字字符串之间的比较.并且没有其他DBMS尝试智能并删除部分比较值以避免错误消息(冒着返回错误结果的风险) (6认同)
  • 好.感谢你.那么我们可以避免这种情况.扫管笏将是查询? (3认同)
  • 我进入PHP后差不多1年就意识到这一点(int列丢弃非数值).这是一件小事,但当我遇到类似的情况时,它确实给我带来了很多麻烦 (2认同)

Han*_*s M 24

我记得很久以前遇到过类似的问题.

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

mysql> SELECT 'a' = 'a ';
        -> 1
mysql> SELECT 'A' = 'a';
        -> 1
Run Code Online (Sandbox Code Playgroud)

因此,使用隐式类型转换,例如'1a'INTEGER中的结果为1,但也是:

mysql> SELECT 0 = 'x6';
        -> 1
mysql> SELECT 1 = ' 1';
        -> 1
mysql> SELECT 1 = ' 1a';
        -> 1
Run Code Online (Sandbox Code Playgroud)

此功能也在其他非静态类型语言中实现.例如,PHP称这种类型为杂耍.请参阅文档中的PHP字符串转换规则和此示例:

<?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)
?>
Run Code Online (Sandbox Code Playgroud)

查看JavaScript:

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

=> 40
Run Code Online (Sandbox Code Playgroud)

然而,解决问题的方法非常简单:只需将整数转换为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
Run Code Online (Sandbox Code Playgroud)

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

希望有所帮助,

-Hannes

  • 这可能适用于PHP(或其他弱类型语言),但SQL是强类型语言(如Java),这种行为不仅完全出乎意料,而且违反了SQL标准,该标准明确指出必须抛出异常这种情况 (8认同)
  • 我不同意.这**是一个错误,而不是一个功能. (4认同)