【问题标题】:outer join more than 1 table外连接多于 1 个表
【发布时间】:2012-12-27 10:49:18
【问题描述】:

假设我有 5 个表,如下:

CREATE TABLE T1 (
FIRST_NAME VARCHAR2(100),
LAST_NAME VARCHAR2(100),
CITY NUMERIC,
SALARY NUMERIC);

CREATE TABLE T2 (
CITY NUMERIC,
DISTRICT  NUMERIC);

CREATE TABLE T3 (
DISTRICT NUMERIC,
DOMAIN NUMERIC);

CREATE TABLE T4 (
DOMAIN NUMERIC,
DETAILS_BOOK NUMERIC);

CREATE TABLE T5 (
DETAILS_BOOK NUMERIC,
FIRST_NAME VARCHAR2(100),
LAST_NAME VARCHAR2(100),
EMAIL VARCHAR2(100));

INSERT INTO T1 VALUES ('john', 'doe',1001,1000); 
INSERT INTO T1 VALUES ('jack', 'jill',1001,2000);
INSERT INTO T1 VALUES ('jeff', 'bush',1001,1500);

INSERT INTO T2 VALUES (1001,1);

INSERT INTO T3 VALUES (1,543);

INSERT INTO T4 VALUES (543,22);

INSERT INTO T5 VALUES (22,'john', 'doe','john@22.com');
INSERT INTO T5 VALUES (44,'john', 'doe','john@44.com');
INSERT INTO T5 VALUES (22,'jeff', 'bush','jeff@22.com');
INSERT INTO T5 VALUES (44,'jeff', 'bush','jeff@44.com');

现在,我想要来自 t1 的所有记录,包括他们的工资和电子邮件,对应于表 t2、t3 和 t4,因此结果应该是:

FIRST_NAME | LAST_NAME | SALARY | EMAIL
--------------------------------------------------
john       | doe       |  1000  | john@22.com
jeff       | bush      |  1500  | jeff@22.com
jack       | jill      |  2000  | (NULL)

到目前为止我得到的是:

SELECT T1.FIRST_NAME, T1.LAST_NAME,T1.SALARY,T5.EMAIL
FROM T1,T2,T3,T4,T5
WHERE   T1.FIRST_NAME = T5.FIRST_NAME (+)
and     T1.LAST_NAME = T5.LAST_NAME(+)
AND     T1.CITY = T2.CITY
AND     T2.DISTRICT = T3.DISTRICT
AND     T3.DOMAIN = T4.DOMAIN
AND     T4.DETAILS_BOOK = T5.DETAILS_BOOK

只返回前两行。

【问题讨论】:

  • 请采用 Mahmoud Gamal 的解决方案。但是,如果您真的非常想使用旧语法,您当然不会添加更多(+)。在您的情况下,您需要在 WHERE 子句的每一行都有一个。
  • @Codo 使用旧语法真的可以吗?我收到一个错误:一个表最多可以外部连接到另一个表when tried to do so.
  • 是的,你是对的。我刚刚意识到表 T5 连接到 T1 和 T4,即你有多列外连接。使用旧语法是不可能的。您必须使用较新的 ANSI 语法才能使您的查询正常工作。

标签: sql oracle outer-join


【解决方案1】:

试试这个:

SELECT 
  T1.FIRST_NAME, 
  T1.LAST_NAME,
  T1.SALARY,
  T5.EMAIL
FROM T1
LEFT JOIN T2  ON T1.CITY         = T2.CITY
LEFT JOIN T3  ON T2.DISTRICT     = T3.DISTRICT
LEFT JOIN T4  ON T3.DOMAIN       = T4.DOMAIN
LEFT JOIN T5  ON T4.DETAILS_BOOK = T5.DETAILS_BOOK
             AND T1.FIRST_NAME   = T5.FIRST_NAME
             AND T1.LAST_NAME    = T5.LAST_NAME;

SQL Fiddle Demo

这会给你:

| FIRST_NAME | LAST_NAME | SALARY |       EMAIL |
-------------------------------------------------
|       john |       doe |   1000 | john@22.com |
|       jeff |      bush |   1500 | jeff@22.com |
|       jack |      jill |   2000 |      (null) |

问题在于 OUTER JOIN 之后的 INNER JOIN 使您的联接像 INNER 一样工作,因为内部联接消除了来自外部联接的那些不匹配的行。

请注意:我使用了 ANSI SQL-92 显式 LEFT OUTER JOIN 语法,而不是您在查询中使用的旧隐式 OUTERINNER 连接语法。

请尝试使用LEFT OUTER JOIN 代替旧的外连接语法,并避免在OUTER JOINs 之后使用INNER JOIN

有关详细信息,请参阅以下内容:


更新:

FROM 子句中有许多表引用且它们之间有JOIN 时,每个表都与从FROM 子句请求的下一个表连​​接1,产生一个临时结果集,然后这个临时结果集与下一个表连​​接,依此类推。对于OUTER JOIN,有左有右:

  • LEFT JOIN 将包括左表中那些不匹配的行,其中,
  • RIGHT JOIN 将包含右表中那些不匹配的行。

根据你要选择的数据,你要注意JOIN运算符两侧的那些表和它们的顺序。


1:这只是逻辑查询处理顺序,但实际顺序始终由查询优化器决定。

【讨论】:

  • 谢谢!但是有没有办法使用隐式OUTER JOIN
  • @Nati 抱歉,我不了解 Oracle,以及隐含的 OUTER JOIN 是如何完成的。您可以通过LEFT JOIN 与我在回答中所做的所有方式相同,并且不要在外部联接之后进行内部联接。它将使其成为内部连接。但请尝试使用显式外连接语法。
  • +1 获取链接和建议。您还应该指出连接顺序(当它们是外部连接时)确实很重要,并且可能会产生不同的结果集。 t1 LEFT JOIN t2 ... LEFT JOIN t5 不等于 t1 LEFT JOIN t5 LEFT JOIN t2 ...
  • 从 FROM 子句请求每个表与下一个表连​​接,生成一个临时结果集,然后将这个临时结果集与下一个表连​​接,依此类推返回的将是好像已经发生,但实际顺序始终取决于优化器。
  • @ShannonSeverance 感谢您的提示。
猜你喜欢
  • 2015-02-05
  • 1970-01-01
  • 2012-07-28
  • 1970-01-01
  • 1970-01-01
  • 2011-11-03
  • 1970-01-01
  • 2021-12-08
  • 2015-03-13
相关资源
最近更新 更多