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

时间:2019-02-14 18:07:44

标签: sql oracle subquery

我正在尝试编写查询以列出没有员工的部门的ID和名称。我找到了一个有效的查询,但是我不明白为什么我的方法不起作用。

除了WHERE子句中的子查询外,这两个查询都是相同的。

我不工作的方法: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;

工作方法: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;

7 个答案:

答案 0 :(得分:5)

NULL == NULL永远都不是。因此,您要问department_id是否在department_id为NULL的一组department_id中。这将永远不是真的。在第二个查询中,您要查找不在department_id列表中的department_id,其中department_id不是NULL。这将使您同时拥有department_id表中没有的NULL department_idemployees

我会注意到不需要子查询中的WHERE子句:

WHERE
department_id NOT IN (
    SELECT department_id FROM employees
)

答案 1 :(得分:2)

在子查询中的第一个查询中

 SELECT  department_id
        FROM
            employees
        WHERE
            department_id IS NULL

它不返回任何department_id,这就是您的输出为空的原因

一个in语句将执行col = val1或col = val2或col = val3。在其中放置null将归结为col = null,这将不起作用

如果使用in语句,则可以很好地滤除null

 SELECT  department_id
            FROM
                employees
            WHERE
                department_id IS not NULL --filter out 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 -- null checking is good 
    )
ORDER BY
    department_name;

在子查询中,您检查了where department_id IS NOT NULL,这可以防止您执行col = null类型的执行,并且子查询中返回的department_id将被过滤掉

答案 2 :(得分:1)

我改用NOT EXISTS

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

如果子查询返回null,则该表达式被视为false

因此,value = NULL的评估结果为NULLUNKNOWN,因此,您可以改用NOT EXISTS

答案 3 :(得分:1)

您可以在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

答案 4 :(得分:1)

如果暂时忘记is null,让我们考虑一下您的第一个查询的逻辑:

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

这将返回拥有员工的部门集合。根据定义,结果受employees.department_id集合的限制。将where department_id is null重新引入到设置为null或产生空集的子查询约束中。

简而言之,我们无法通过仅查询该表来构想表中没有的一组值。因此,我们必须使用NOT IN(如果子查询中的表包含空条目,则必须使用NOT EXISTS)或其他人建议的OUTER JOIN解决方案。

答案 5 :(得分:1)

此表达式:  X IN ( a,b,c )等效于:X = a OR X = b OR 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

您还需要学习Comparisons with NULL and the three-valued logic (3VL)

如果您了解上述内容,则可以为每个表达式以及每个值组合创建一个truth table-这将有助于您了解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) *    |
+------+------+---+---+--------------+------------------+

对于标记为*的行,请特别注意-这些行与常识不一致,如果X = false,则NOT X必须为真

答案 6 :(得分:0)

您需要的是:WHERE NOT EXISTS,因为您需要的是没有员工的所有部门。

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

在这两种情况下,使用where为null /不为null都是错误的。