用这些查询的Oracle旧联接语法编写的等效联接是什么?
SELECT first_name, last_name, department_name, job_title
FROM employees e RIGHT JOIN departments d
ON(e.department_id = d.department_id)
RIGHT JOIN jobs j USING(job_id);
->返回106行
SELECT first_name, last_name, department_name, job_title
FROM employees e RIGHT JOIN jobs j
ON(e.job_id = j.job_id)
RIGHT JOIN departments d
USING(department_id);
->返回122行
答案 0 :(得分:2)
我会做这样的事情(对于第一个查询)-明确地表明一个事实,即多重联接,根据定义,是一次两个表(或更通常是“行集”)的联接的迭代。将其视为“显式使用括号”。
select first_name, last_name, department_name, job_title
from (
select first_name, last_name, job_id, department_name
from employees e, departments d
where e.department_id (+) = d.department_id
) sq
, jobs j
where sq.job_id (+) = j.job_id
;
可以使用一个具有更多WHERE条件的单个SELECT语句重写(也许),但是查询的可读性较低;不会很清楚它在做什么。
答案 1 :(得分:1)
分别:
SELECT first_name,
last_name,
department_name,
job_title
FROM employees e,
jobs j,
departments d
WHERE e.job_id (+) = j.job_id
AND e.department_id = d.department_id (+);
和:
SELECT first_name,
last_name,
department_name,
job_title
FROM employees e,
departments d,
jobs j
WHERE e.department_id (+) = d.department_id
AND e.job_id = j.job_id (+);
db <>提琴here
但是,请仅使用ANSI连接语法。旧的旧式联接语法让人难以理解,将(+)
置于联接条件的错误一侧会导致错误,您应该教会人们如何使用不太混乱的“新”(很难自2001年Oracle 9i以来就被称为新语法,而不是恢复到旧方法。
答案 2 :(得分:0)
仅添加到Mathguy的答案中,这很有趣,因为那些看起来很无辜的正确连接看上去并不像它们。我的第一次(不正确)尝试是:
select e.department_id, e.job_id, e.first_name, e.last_name, d.department_name
from jobs j
, departments d
, employees e
where e.job_id(+) = j.job_id
and e.department_id(+) = d.department_id;
但是,正如Mathguy指出的,由于没有员工的部门以及部门与工作之间的交叉联接,以及由于正确的联接不在一个链中而出现的微妙的联接优先效应,它给出了不同的结果。 / p>
我不确定原始查询的目的是什么。使用Oracle HR demo schema时,结果与内部联接相同,但这仅是因为每项工作至少都有一名员工。这说明了在测试外部联接查询时的一个陷阱,因为您可能会运行测试,获得相同的结果,并且认为您的重写逻辑上是相同的,而实际上却不是。
如果将原始的右连接重写为左连接,则必须变成这样:
select e.department_id, e.job_id, e.first_name, e.last_name, d.department_name
from jobs j
left join (
departments d
left join employees e on e.department_id = d.department_id
)
on e.job_id = j.job_id;
(您还可以将departments
> employees
联接扩展到内联视图或with
子句中,或使用outer apply
构造包含job_id
加入。)
这是因为原始查询中的两个右联接由jobs
和departments
驱动,因此即使从departments
到employees
的外部联接也包括16个没有员工的部门,一旦我们从jobs
外部连接到那个,我们就隐式地排除了没有job_id的行,因为我们是从jobs
开始的。因此,将部门的外部联接过滤为有效的内部联接,并且只要所有工作都有相应的员工,则其结果也将与内部联接相同。要了解两者之间的区别,您必须插入另一个作业,该作业将在结果中添加一行,其中包含该职务,但没有员工详细信息。
因此,旧版本必须为以下版本:
select de.first_name, de.last_name, de.department_name, j.job_title
from jobs j
, lateral (
select e.department_id, e.job_id, e.first_name, e.last_name, d.department_name
from departments d
, employees e
where e.department_id(+) = d.department_id
) de
where de.job_id(+) = j.job_id;
或不包含lateral
:
select first_name, last_name, department_name, job_title
from jobs j
, ( select e.first_name, e.last_name, e.job_id, d.department_name
from departments d, employees e
where e.department_id (+) = d.department_id ) de
where de.job_id(+) = j.job_id
第二个查询仅切换jobs
和departments
:
select first_name, last_name, department_name, job_title
from departments d
, ( select e.first_name, e.last_name, e.department_id, e.job_id, j.job_title
from jobs j, employees e
where e.job_id(+) = j.job_id ) je
where je.department_id(+) = d.department_id