SQL查询以查找具有部门名称的位置以及没有部门的位置
Posted
技术标签:
【中文标题】SQL查询以查找具有部门名称的位置以及没有部门的位置【英文标题】:SQL query to find locations with department names as well as locations without departments 【发布时间】:2016-11-01 14:10:09 【问题描述】:我遇到了以下关于 Oracle 附带的著名 HR
架构的 SQL 问题:
编写一个 SQL 查询来查找每个位置的所有位置和部门,以及没有部门的位置。不要使用外连接。
OUTER JOIN
很容易:
SELECT department_name, city
FROM locations
LEFT OUTER JOIN departments USING (location_id);
我得到 43 个结果。我试过这个:
SELECT department_name, city
FROM locations l, departments d
WHERE l.location_id = d.location_id OR
l.location_id NOT IN (SELECT DISTINCT location_id FROM departments);
但我只得到 27 行,就好像我这样做:
SELECT department_name, city
FROM locations
JOIN departments USING (location_id);
为什么OR
不起作用?谢谢!
编辑:
正如@mathguy 所指出的,我在departments
表的location_id
列中有一个NULL
部门。这就是NOT IN
不返回任何行的原因。否则我会有更多的行从departments
表中寻找位置ID。
【问题讨论】:
可能错误的查询是第一个,而不是第二个。左外连接应该使用 ON,而不是 USING @Massimo,为什么?它确实产生了预期的结果。 docs.oracle.com/database/121/SQLRF/… @Massimo 进一步阅读“由于此示例中的列名在连接中的两个表中相同,因此您还可以通过指定连接语法的 USING 子句来使用公共列功能。” 你说得对,我不知道...我链接到“传统”sql 【参考方案1】:从内部连接中获取city, department_name
,然后像这样获取union all
:
select city, department_name
from <inner join>
union all
select city, NULL
from locations
where location_id not in (select location_id from departments);
union all
的第二个分店会给你 16 个没有部门的城市。
注意:如果location_id
列中有NULL
的部门,NOT IN
条件将不起作用。如果可能,条件可以更改为not in (select location_id from departments where location_id is not null)
。
【讨论】:
嗯,select city, NULL from locations where location_id not in (select location_id from departments);
返回 0 行。
一定是同一个问题:你必须有一个location_id为NULL的部门。这(我的意思是你的副本)不是标准的 HR 模式。
是的。我愿意。非常感谢!
或者 HR 架构在不同版本的 Oracle(我有 12.1)之间发生了变化,但我对此表示怀疑。
@MartinDimitrov - 我编辑了答案以解释如何修改 NOT IN 条件,以防该列中可能存在 NULL。【参考方案2】:
select l.city, d.department_name from locations l, departments d
where l.location_id=d.location_id
UNION
select l2.city, null department_name
from locations l2
where not exists (select 1 from depertments d2 where d2.location_id=l2.location_id)
【讨论】:
虽然看起来很复杂,但它仍然有效。谢谢。【参考方案3】:如果您尝试想象一些中间步骤,这很简单:
让我们想象表的交叉连接,然后用你的 where 子句过滤结果。在该行集中,不会显示任何具有非空位置和空部门的行。你可以用下一个查询来证明:
SELECT department_name, city
FROM locations l, departments d
WHERE d.location_id is null;
no row selected
但你指定l.location_id NOT IN (SELECT DISTINCT location_id FROM departments);
。这种情况不会影响表之间的交叉连接。
因此,您应该在没有部门的情况下获得额外的行数。
这就是为什么你需要left join
或union
子句。
【讨论】:
【参考方案4】:使用相关子查询:
SELECT l.*,
(SELECT d.department_name
FROM departments d
WHERE d.location_id = l.location_id
) as department_name
FROM locations l;
如果担心一个位置的多个部门,只需将它们聚合在一起即可:
SELECT l.*,
(SELECT LISTAGG(d.department_name, ', ') WITHIN GROUP (ORDER BY d.department_name) as department_names
FROM departments d
WHERE d.location_id = l.location_id
) as department_name
FROM locations l;
【讨论】:
这不起作用,因为一个位置可能有多个部门,因此从子查询返回多行。 @MartinDimitrov 连接也将返回多行?这向您展示了如何在没有 OUTER JOIN 的情况下编写查询,我已经解释了为什么 OR 在我的答案中不起作用。我不相信他们在找你使用隐式语法。 你试过了吗?它返回ORA-01427: single-row subquery returns more than one row
我喜欢使用LISTAGG
。我永远不会想到它。谢谢。以上是关于SQL查询以查找具有部门名称的位置以及没有部门的位置的主要内容,如果未能解决你的问题,请参考以下文章