这些查询的 Oracle 旧语法连接等价物是啥?

Posted

技术标签:

【中文标题】这些查询的 Oracle 旧语法连接等价物是啥?【英文标题】:What are Oracle's old-syntax join equivalents of these queries?这些查询的 Oracle 旧语法连接等价物是什么? 【发布时间】:2020-10-16 13:09:25 【问题描述】:

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

【问题讨论】:

为什么您希望将标准联接重写为老式的隐式联接? 不幸的是,我所在的公司很多开发人员都不擅长新语法,所以我需要好好学习旧语法。我在另一个问题上看到了这些查询,尝试过但找不到旧语法的等价物。 @oramas 。 . .教开发人员新语法。二十多年来,它已经成为标准,现在是您的开发人员学习它的时候了。这真的不是很难学习——作为一个必须学习它的人,我可以这么说。 我知道,但最后,我需要很好地了解旧语法,以维护之前编写的代码。因此,任何答案将不胜感激 @GordonLinoff - 教其他开发人员现代语法是相当困难的,如果“老师”不知道旧语法,不是吗? 【参考方案1】:

我会做这样的事情(对于第一个查询) - 明确说明多重连接是,根据定义,一次连接两个表(或更一般的“行集”)的迭代。将其视为“明确使用括号”。

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
;

这可以使用单个 SELECT 语句重写(也许),使用更多 WHERE 条件 - 但查询的可读性会降低;它在做什么不会那么清楚。

【讨论】:

我看不出没有内联视图的写法,这本身就很有趣。我设法使用 ANSI 左连接语法(我重构右连接的标准第一步)重写了它,但它仍然需要括号来保持连接优先级。【参考方案2】:

分别:

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 以来一直存在的新方法)语法,而不是恢复到旧方法。

【讨论】:

您好 MT0,首先,非常感谢。但我想问一件事。我对旧语法的了解是,如果我使用右外连接,我将 (+) 放在左侧。如果我只为一个加入这样做,它工作正常。但是,如果我的问题中有两个正确的连接,它就会失败。因为看起来我应该喜欢这个“WHERE e.job_id(+) = j.job_id AND e.department_id(+) = d.department_id;”。但是当您连接前两个表时,您在不同的列中使用了它们。顺便说一句,第二个返回相同的结果,但第一个返回 107 行,而旧语法返回 106 我们只看第一个查询。正如 OP 所说,您的解决方案在 ed 之间进行了错误的外部连接。当您将外连接标记移到另一侧并运行查询时,您会发现它返回了更多的行,原因很明显,如果您仔细查看它,它会交叉连接dj 然后将结果外连接到e。转换为旧的 Oracle 语法并不像看起来那么简单。 这是一个有趣的谜题(也是避免右连接的另一个原因)。原始查询中令人困惑的右连接是从jobsdepartments 驱动的,因此即使从departmentsemployees 的外连接包括没有员工的16 个部门,从jobsthat 隐含地排除了没有 job_id 的行,因为即使它是外部联接,我们也是从 jobs 驱动它的,因此到部门的 OJ 有效地变成了内部联接。您必须像@mathguy 的回答那样将其括起来以保留优先级。右连接是邪恶的。【参考方案3】:

只是为了添加到 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 指出的那样,由于没有员工的部门以及部门和工作之间的交叉连接,以及由于正确连接不在一个链中而出现的微妙连接优先级效应,它给出了不同的结果。

我不确定原始查询的意图是什么。使用 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 

【讨论】:

以上是关于这些查询的 Oracle 旧语法连接等价物是啥?的主要内容,如果未能解决你的问题,请参考以下文章

java连oracle中连不上,错误是“无法从套接字读取更多的数据”,是啥问题?

在连接字符串中包含服务名称的语法是啥?

旧版本中的等价物是啥。当我在旧版本中运行时,该应用程序没有给我一个大的导航栏

plsql可以连接上,历史ip 端口都是对的,但是weblogic创建数据源连接失败是啥原因呢?

python中运行oracle查询并将结果插入到新的oracle表中的语法是啥?

GetNumaProcessorNodeEx 的驱动程序等价物是啥?