MySQL中的子句参数列表中的空



当您执行 IN子句为空的sql查询时会发生什么?

例如:

SELECT user WHERE id IN ();

MySQL会按预期处理(即,总是为false),如果没有,我的应用程序在动态构建IN子句时如何处理此情况?

如果我有一个动态构建IN列表的应用程序,并且可能最终为空,有时我要做的就是用不可能的值初始化列表,然后添加。例如。如果是用户名的列表,我将从一个空字符串开始,因为这不是一个可能的用户名。如果是auto_increment ID,我将使用-1,因为实际值始终为正。

如果这是不可行的,因为没有不可能的价值,则必须使用有条件地决定是否将AND column IN ($values)表达式包含在WHERE子句中。

这也给了我0个结果:

SELECT id FROM User
WHERE id IN (NULL);

在MySQL 5.6

上尝试

使用有效语法的最接近此查询的近似值为:

SELECT user FROM tbl1 WHERE id IN (SELECT id FROM tbl1 WHERE FALSE);

无条件返回一个空结果集。括号中的子查询总是返回一个空集,并且在空集中找不到值,因为一个空集没有值。

使用始终false语句

创建SQL之前,请检查数组大小。如果大小为0,则会生成where语句为 1 = 2,如:

SELECT * FROM USERS WHERE name in () 

变成

SELECT * FROM USERS WHERE 1 = 2 

对于空数组上的"不",生成一个始终为true语句,如:

SELECT * FROM USERS WHERE name not in () 

变成

SELECT * FROM USERS WHERE 1 = 1

这应该适用于更复杂的查询,例如:

SELECT * FROM USERS WHERE (name in () OR name = 'Alice') 

变成

SELECT * FROM USERS WHERE (1 = 2 OR name = 'Alice') 

您不能将操作员留在操作员中,例如,您必须将其放入其中,例如NULL。但是,即使在这种情况下,它也不会按预期工作,因为与NULL进行比较总是返回NULL(空)。一种可能的解决方案是添加一个子选择。

示例:

SELECT user_id FROM users;
+-----------+
| user_id   |
+-----------+
|      1000 |
|      1001 |
|      1002 |
|      1003 |
|      1004 |
|      1005 |
|      1006 |
|      1007 |
|      1008 |
|      1009 |
|      1010 |
+-----------+
SELECT user_id FROM users WHERE user_id NOT IN ();
ERROR: 1064: You have an error in your SQL syntax; check the manual that 
corresponds to your MySQL server version for the right syntax to use near ')' at line 1
SELECT user_id FROM users WHERE user_id NOT IN (NULL);
Empty set (0.0003 sec)    
SELECT user_id FROM users WHERE user_id IN (1001, 1002, 1003) 
AND user_id NOT IN (SELECT user_id FROM users WHERE user_id IN (NULL));
+---------+
| user_id |
+---------+
|    1001 |
|    1002 |
|    1003 |
+---------+
3 rows in set (0.0004 sec)

您有点修改(缩短)查询,但我认为,它们也会慢一点。

如果使用auto_increment for ID(1,2,3,..),并且如果数组为空,则可以添加一个项目[0]。所以它将是

if (empty($arr)) {
   $arr[] = 0;
}
SELECT user WHERE id IN (0);

并且不会有MySQL解析错误。这种情况在子查询中非常有用 - 当您的主要查询不依赖于子查询结果时。


更好的方法 - 如果数组为空,请勿调用查询。

$data = null;
if (!empty($arr)) {
    $data = ... call query
}

这是一个空列表的另一个变体,用于保留逻辑和查询中实际列的概念。

不正确的id in ()可以重写:

where id <> id;

同样错误的负面条件id not in ()可以通过自定义查询构建代码转换为:

where id = id;

这种方法比id not in (NULL)更安全,因为它没有评估为null。

但要注意这将使结果从id is null的行中过滤掉。在某些情况下,这可能被视为功能。

尤其在复杂的堆叠查询构建逻辑上有用,其中嵌套的构建器不知道如何在上面使用所产生的子查询。

我假设当您的IN为空时,您仍然需要运行查询;例如使用LEFT JOIN ... ON ... AND IN ()

当您已经在应用程序层中动态构建IN时,我会处理那里的空箱。

这是PHP

中的一个基本示例
$condition = 'FALSE' // Could feasibly want TRUE under different circumstances
if($values){
   $inParams = **dynamically generated IN parameters from $values**;
   $condition = 'IN (' . $inParams . ')';
}
$sql = 'SELECT * FROM `user` WHERE '.$condition;

如果您不需要使用空的IN运行查询,则不要;为自己节省数据库!

n.b。,如果您还没有,我会构建/使用一个可以正确绕圈并在您的IN参数中绑定的函数,而不仅仅是将它们固定到SQL中。如果用于原始数据,这将为您提供一些保护。

处理此问题的一种方法:

SELECT user WHERE id in (SELECT 1 WHERE 1!=1)

可能需要用@jameshoux的评论中提到的适当数据类型的值替换1个。
这里做出的假设是用户的ID是int。

如果您在应用程序中使用该查询,并且动态传递对象列表到查询,我不应该打电话给数据库,以执行具有不可能值的选择,我应该返回一个空列表,而无需直接致电数据库查询。

因为要在调用它之前先知道是空的查询。

最新更新