在IN
子句为空的情况下执行SQL查询时会发生什么?
例如:
SELECT user WHERE id IN ();
MySQL是否会按预期方式处理(即始终为false),否则,我的应用程序在IN
动态构建子句时如何处理这种情况?
在IN
子句为空的情况下执行SQL查询时会发生什么?
例如:
SELECT user WHERE id IN ();
MySQL是否会按预期方式处理(即始终为false),否则,我的应用程序在IN
动态构建子句时如何处理这种情况?
IN
子句,请不要执行查询。嘘!
Answers:
这也给了我0个结果:
SELECT id FROM User
WHERE id IN (NULL);
在MYSQL 5.6上试用
id IN (NULL)
评估为NULL
而不是FALSE
。这主要是一个问题NOT IN
:SELECT id FROM User WHERE id NOT IN (NULL);
还将返回0个结果。
使用有效语法对此查询的最接近近似值是:
SELECT user FROM tbl1 WHERE id IN (SELECT id FROM tbl1 WHERE FALSE);
它无条件地返回一个空结果集。括号中的子查询始终返回一个空集,并且在空集中找不到任何值,因为空集不包含任何值。
(select top 0 0)
,其优点是不需要表名。
IN
动态生成文字列表的情况下,这实际上没有帮助。他没有在寻找产生虚空IN
子句的方法,他想知道当意外发生时如何处理它,因为给了他空值数组。
SELECT user FROM tbl1 WHERE id IN (FALSE)
id
不是布尔值字段,这可能是一个合理的假设,但是仍然是一个假设。
SELECT TOP N
而不是MySQL。在另一方面(SELECT 0 WHERE 0)
。但是,这样做IN (SELECT ...)
似乎在MySQL 5.7中创建了一个依赖子查询(如图所示explain
),结果查询非常慢。
使用始终为假的陈述
在创建SQL之前,请检查数组大小。如果大小为0,则将where语句生成为1 = 2
,如下所示:
SELECT * FROM USERS WHERE name in ()
变成
SELECT * FROM USERS WHERE 1 = 2
对于空数组上的“ not in”,生成一个始终为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')
这是空列表的始终为false语句的另一种形式,它保留了逻辑和查询中实际列的概念。
错误的id in ()
可以改写为:
where id <> id;
同样,不正确的否定条件id not in ()
可以通过自定义查询构建代码转换为:
where id = id;
这种方法比id not in (NULL)
不评估为NULL更安全。
但要注意,这会从结果中过滤出where的行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;
如果您不需要使用empty运行查询IN
,则不需要;节省您的数据库之旅!
注意:如果还没有的话,我会构建/使用一个可以长期运行并IN
正确绑定参数的函数,而不是仅仅将其原始打包为SQL。如果对原始数据使用SQL注入,这将为您提供一些保护,以防止SQL注入。
您不能将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)
您可以稍微修改(缩短)查询,但是我认为它们也会稍微慢一点。