这些查询的 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 所说,您的解决方案在e
和 d
之间进行了错误的外部连接。当您将外连接标记移到另一侧并运行查询时,您会发现它返回了更多的行,原因很明显,如果您仔细查看它,它会交叉连接d
和j
然后将结果外连接到e
。转换为旧的 Oracle 语法并不像看起来那么简单。
这是一个有趣的谜题(也是避免右连接的另一个原因)。原始查询中令人困惑的右连接是从jobs
和departments
驱动的,因此即使从departments
到employees
的外连接包括没有员工的16 个部门,从jobs
到that 隐含地排除了没有 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
连接。)
这是因为原始查询中的两个右联接是从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
【讨论】:
以上是关于这些查询的 Oracle 旧语法连接等价物是啥?的主要内容,如果未能解决你的问题,请参考以下文章
java连oracle中连不上,错误是“无法从套接字读取更多的数据”,是啥问题?
旧版本中的等价物是啥。当我在旧版本中运行时,该应用程序没有给我一个大的导航栏
plsql可以连接上,历史ip 端口都是对的,但是weblogic创建数据源连接失败是啥原因呢?