我正在尝试编写查询以列出没有员工的部门的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;
答案 0 :(得分:5)
NULL == NULL
永远都不是。因此,您要问department_id
是否在department_id
为NULL的一组department_id
中。这将永远不是真的。在第二个查询中,您要查找不在department_id
列表中的department_id
,其中department_id
不是NULL
。这将使您同时拥有department_id
表中没有的NULL department_id
和employees
。
我会注意到不需要子查询中的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
的评估结果为NULL
或UNKNOWN
,因此,您可以改用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都是错误的。