这些查询的Oracle旧语法联接等效项是什么?

时间:2020-10-16 13:09:25

标签: sql oracle join

用这些查询的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行

3 个答案:

答案 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加入。)

这是因为原始查询中的两个右联接由jobsdepartments驱动,因此即使从departmentsemployees的外部联接也包括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

第二个查询仅切换jobsdepartments

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