简体   繁体   English

两者之间的差异:NOT IN(IS NOT NULL)VS IN(IS NULL)

[英]Difference between: NOT IN (IS NOT NULL) VS IN (IS NULL)

Im trying to write a query to list the id and names of departments that don't have any employee. 我正在尝试编写查询以列出没有员工的部门的ID和名称。 I have found a query that works but I don't understand why my approach is not working. 我找到了一个有效的查询,但是我不明白为什么我的方法不起作用。

Both queries are the same except for the subquery inside the WHERE clause. 除了WHERE子句中的子查询外,这两个查询都相同。

My NOT WORKING approach: IN...IS NULL (EDIT: IT RETURNS NO VALUES) 我的无效方式:IN ... IS NULL(编辑:它不返回任何值)

SELECT
    department_id,
    department_name
FROM
    departments
WHERE
    department_id IN ( 
        SELECT
            department_id
        FROM
            employees
        WHERE
            department_id IS NULL
    )
ORDER BY
    department_name;

The WORKING approach: NOT IN... IS NOT NULL 工作方法:不输入...不为空

SELECT
    department_id,
    department_name
FROM
    departments
WHERE
    department_id NOT IN ( --why -> IN... IS NULL is not working?
        SELECT
            department_id
        FROM
            employees
        WHERE
            department_id IS NOT NULL
    )
ORDER BY
    department_name;

NULL == NULL is never true. NULL == NULL永远不会成立。 So you are asking if department_id is in a set of department_id s where department_id is NULL. 所以,你问department_id是一组department_id S其中department_id为NULL。 This will NEVER be true. 这将永远不是真的。 In the second query, you're looking for department_id s that are NOT in a list of department_id s where department_id is NOT NULL . 在第二个查询,你要找的department_id s表示不在列表department_id S其中department_idNULL This will give you both NULL department_id s AND department_id s that are not in the employees table. 这将为您提供employees表中没有的NULL department_iddepartment_id

I would note that your WHERE clause in the subquery is not needed: 我会注意到不需要子查询中的WHERE子句:

WHERE
department_id NOT IN (
    SELECT department_id FROM employees
)

in your 1st query inside subquery 在子查询中的第一个查询中

 SELECT  department_id
        FROM
            employees
        WHERE
            department_id IS NULL

It does not return any department_id thats why your output will be null 它不返回任何department_id因此您的输出将为null

An in statement will do col=val1 or col=val2 or col=val3. in语句将执行col = val1或col = val2或col = val3。 Putting a null in there will boil down to col=null which won't work 在其中放置一个null将归结为col = null,这将不起作用

as a result in case of in statement it is good filter out null 因此,如果使用in语句,则可以很好地滤除null

 SELECT  department_id
            FROM
                employees
            WHERE
                department_id IS not NULL --filter out null

In your 2nd query 在第二个查询中

SELECT
    department_id,
    department_name
FROM
    departments
WHERE
    department_id NOT IN ( --why -> IN... IS NULL is not working?
        SELECT
            department_id
        FROM
            employees
        WHERE
            department_id IS NOT NULL -- null checking is good 
    )
ORDER BY
    department_name;

in sub query you cheked WHERE department_id IS NOT NULL which safe you from col=null type execution and those department_id return in subquery will be filterout 在子查询中,您检查了WHERE department_id IS NOT NULL,这可以防止您执行col = null类型的执行,并且子查询中返回的department_id将被过滤掉

I would use NOT EXISTS instead : 我会使用NOT EXISTS代替:

SELECT d.*
FROM departments d
WHERE NOT EXISTS (SELECT 1 FROM employees e WHERE e.department_id = d.department_id);

If the subquery return null then that expression considered as false . 如果子查询返回null则该表达式视为false

So, value = NULL will evaluate as NULL or UNKNOWN , So, you can use NOT EXISTS instead. 因此, value = NULL将评估为NULLUNKNOWN ,因此,您可以改用NOT EXISTS

You can use a LEFT JOIN with a WHERE ... IS NULL condition in the WHERE clause, as follows : 您可以在WHERE子句中使用带有WHERE ... IS NULL条件的LEFT JOIN,如下所示:

SELECT
    d.department_id,
    d.department_name
FROM
    departments d
    LEFT JOIN employees e 
        ON e.department_id = d.department_id
WHERE e.department_id IS NULL

If we forget about the is null for a moment, let's consider the logic of your first query: 如果我们暂时忘记了is null ,那么请考虑您的第一个查询的逻辑:

SELECT
    department_id,
    department_name
FROM
    departments
WHERE
    department_id IN ( 
        SELECT
            department_id
        FROM
            employees
    )
ORDER BY
    department_name;

This returns the set of departments which have employees. 这将返回拥有员工的部门集合。 By definition, the result is bounded by the set of employees.department_id . 根据定义,结果由employees.department_id集合限制。 Re-introducing the where department_id is null to the subquery constrains that set to null or produces an empty set. 重新将where department_id is null的子查询约束设置为null或产生一个空集合。

Simply, there is no way we can conjure up the set of values which aren't in a table by querying only that table. 简而言之,我们无法通过仅查询该表来混淆表中没有的值集。 Consequently we have to use the NOT IN (or NOT EXISTS if the table in the subquery contains null entries) or the OUTER JOIN solution suggested by others. 因此,我们必须使用NOT IN(或如果子查询中的表包含空条目,则不存在)或其他人建议的OUTER JOIN解决方案。

This expression: X IN ( a,b,c ) is equivalent to: X = a OR X = b OR X = c 该表达式: X IN ( a,b,c )等效于: X = a OR X = b OR X = c

This expession: NOT X IN ( a,b,c ) is equivalent to: NOT (X = a OR X = b OR X = c) , which in turn is eqivalent to: NOT X = a AND NOT X = b AND NOT X = c 此表达式: NOT X IN ( a,b,c )等效于: NOT (X = a OR X = b OR X = c) ,其等效于: NOT X = a AND NOT X = b AND NOT X = c

You also need to study Comparisons with NULL and the three-valued logic (3VL) 您还需要研究NULL和三值逻辑(3VL)的比较

If you know the above, you can create a truth table for each of expressions and for for each combination of values - this will help you to gain understanding of behaviour of IN/NOT IN in SQL Queries: 如果您了解上述内容,则可以为每个表达式以及每个值组合创建一个真值表 -这将有助于您了解SQL查询中IN / NOT IN的行为:

+------+------+---+---+--------------+------------------+
|  X   |  a   | b | c | X in (a,b,c) | NOT X in (a,b,c) |
+------+------+---+---+--------------+------------------+
| 1    | 0    | 1 | 2 | true         | false            |
| 1    | NULL | 1 | 2 | false        | NULL(false) *    |
| 1    | 0    | 2 | 3 | false        | true             |
| 1    | NULL | 2 | 3 | false        | NULL(false) *    |
| NULL | 0    | 1 | 2 | NULL(false)  | NULL(false) *    |
| NULL | NULL | 1 | 2 | NULL(false)  | NULL(false) *    |
+------+------+---+---+--------------+------------------+

Please pay a special attenton for rows marked with * - these are the ones that are not consistent with common sense where if X = false then NOT X must be true 请为带有*行支付特殊的Attenton * -这些行与常识不一致,如果X = false则NOT X必须为true

What you need here is: WHERE NOT EXISTS since what you need is all departments where no employee exists. 您需要的是: WHERE NOT EXISTS因为您需要的是没有员工的所有部门。

select department_id, department_name from departments 
where not exists (
  select 1 from employees where employees.department_id = departments.department_id
)

using where is null/is not null is wrong in both cases here. 在这两种情况下,使用where null / is not null是错误的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM