99

当您在IN子句为空的情况下执行 SQL 查询时会发生什么?

例如:

SELECT user WHERE id IN ();

MySQL 会按预期处理这种情况(即总是错误),如果不是,我的应用程序在IN动态构建子句时如何处理这种情况?

4

10 回答 10

66

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

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

于 2012-11-03T15:30:46.430 回答
17

这也给了我 0 个结果:

SELECT id FROM User
WHERE id IN (NULL);

在 MYSQL 5.6 上试过

于 2016-05-24T17:11:16.577 回答
13

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

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

它无条件地返回一个空的结果集。括号中的子查询总是返回一个空集,并且在一个空集中找不到任何值,因为一个空集不包含任何值。

于 2012-11-03T14:58:46.787 回答
8

使用总是错误的陈述

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

SELECT * FROM USERS WHERE name in () 

变成

SELECT * FROM USERS WHERE 1 = 2 

对于空数组上的“不在”,生成一个始终为真的语句,如下所示:

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') 
于 2017-09-24T14:36:02.223 回答
5

您不能将 IN 运算符留空,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)

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

于 2020-05-21T15:08:02.290 回答
4

如果您对 id (1,2,3, ..) 使用 AUTO_INCREMENT 并且如果数组为空,则可以添加一项 [0]。所以会是

if (empty($arr)) {
   $arr[] = 0;
}

SELECT user WHERE id IN (0);

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


更好的方法 - 如果数组为空,则不要调用查询。

$data = null;
if (!empty($arr)) {
    $data = ... call query
}
于 2017-11-05T15:28:40.713 回答
2

这是针对空列表的 always false 语句的另一种变体,它保留了查询中的逻辑和实际列的概念。

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

where id <> id;

同样不正确的否定条件id not in ()可以通过自定义查询构建代码转换为:

where id = id;

这种方法比id not in (NULL)它不评估为 NULL 更安全。

但请注意,这会从结果中过滤掉 where 的行id is null。在某些情况下,这可能被视为一项功能。

特别适用于复杂的堆叠查询构建逻辑,其中嵌套构建器不知道如何在上面使用生成的子查询。

于 2019-09-24T10:40:58.867 回答
1

我假设您仍然需要在您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,则不要;为自己节省一趟数据库!

注意如果您还没有,我会构建/使用一个可以长期使用并IN正确绑定参数的函数,而不是仅仅将它们原始连接到 SQL 中。如果将 SQL 注入用于原始数据,这将为您提供一些保护。

于 2016-05-10T12:02:48.320 回答
1

处理此问题的一种方法:

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

如@JamesHoux 的评论中所述,可能需要将 1 替换为适当数据类型的值。
这里的一个假设是用户的 id 是一个 int。

于 2021-12-07T17:29:07.800 回答
-1

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

因为在调用它之前执行一个你知道它是空的查询是没有意义的。

于 2019-10-14T10:03:55.050 回答