Oracle LEFT OUTER JOIN on 3+ tables - (+)Syntax vs ANSI Syntax

时间:2015-03-03 18:02:59

标签: sql oracle

场景我需要使用(+)外连接语法将现有查询转换为ANSI语法。 原因:其中一个JOINS需要一个OR操作数,而(+)运算符不允许这样操作,但允许使用LEFT OUTER JOIN。 (至少我认为这是正确的。)

查询目标:表D包含两个层次结构的名称,BB和Commercial。通过这些表的简单连接将返回19个位置及其各自的层次结构。如果有效,我需要查看具有适当层次结构的所有位置,否则为NULL值。

(+)语法查询 - 正常工作:

select a.userid, a.firstname, a.lastname, b.name PositionName, d.name Hierarchy

from cs_participant a, cs_position b, cs_positionrelation c, cs_positionrelationtype d

where a.payeeseq = b.payeeseq
and b.ruleelementownerseq = c.childpositionseq(+)
and c.positionrelationtypeseq = d.datatypeseq(+)
and b.removedate = to_date('01/01/2200','dd/mm/yyyy')
and b.effectiveenddate = to_date('01/01/2200','dd/mm/yyyy')
and c.removedate(+) = to_date('01/01/2200','dd/mm/yyyy')
and d.removedate(+) = to_date('01/01/2200','dd/mm/yyyy')
and a.removedate = to_date('01/01/2200','dd/mm/yyyy')
and a.effectiveenddate = to_date('01/01/2200','dd/mm/yyyy')

结果示例:

enter image description here

我尝试使用ANSI语法:

select a.firstname, a.lastname, b.name, d.name as "Hierarchy"
from cs_participant a, cs_position b

left outer join cs_positionrelation c on c.parentpositionseq = b.ruleelementownerseq 
or c.childpositionseq = b.ruleelementownerseq (--This is the OR clause
that I cannot execute in the (+) syntax query)

left outer join cs_positionrelationtype d on d.datatypeseq = c.positionrelationtypeseq

where a.payeeseq = b.payeeseq
and b.removedate = to_date('01/01/2200','dd/mm/yyyy')
and b.effectiveenddate = to_date('01/01/2200','dd/mm/yyyy')
and a.removedate = to_date('01/01/2200','dd/mm/yyyy')
and c.removedate = to_date('01/01/2200','dd/mm/yyyy')
and c.effectiveenddate = to_date('01/01/2200','dd/mm/yyyy')
and d.removedate = to_date('01/01/2200','dd/mm/yyyy')

ANSI查询结果:

此查询仅返回分配给层次结构的位置。我需要查看所有位置,无论是否有层次结构分配,目前正从结果中排除。

3 个答案:

答案 0 :(得分:2)

在第一个查询中,您有两个日期文字作为外部联接条件,但是您将它们留在第二个查询的where子句中。要正确更改语法,需要将这些条件保留为连接条件的一部分。将两种连接语法(即在同一查询中使用逗号分隔表和join关键字)组合起来也是一种不好的形式。

以下是第一个适合SQL-99语法的查询:

SELECT a.userid,
       a.firstname,
       a.lastname,
       b.name AS positionname,
       d.name AS hierarchy
FROM   cs_participant a
       JOIN cs_position b ON a.payeeseq = b.payeeseq
       LEFT JOIN cs_positionrelation c
          ON     b.ruleelementownerseq = c.childpositionseq
             AND c.removedate = TO_DATE ('01/01/2200', 'dd/mm/yyyy')
       LEFT JOIN cs_positionrelationtype d
          ON     c.positionrelationtypeseq = d.datatypeseq
             AND d.removedate = TO_DATE ('01/01/2200', 'dd/mm/yyyy')
WHERE      b.removedate = TO_DATE ('01/01/2200', 'dd/mm/yyyy')
       AND b.effectiveenddate = TO_DATE ('01/01/2200', 'dd/mm/yyyy')
       AND a.removedate = TO_DATE ('01/01/2200', 'dd/mm/yyyy')
       AND a.effectiveenddate = TO_DATE ('01/01/2200', 'dd/mm/yyyy')

一旦完成,将其调整为连接任一列都是微不足道的:

SELECT a.userid,
       a.firstname,
       a.lastname,
       b.name AS positionname,
       d.name AS hierarchy
FROM   cs_participant a
       JOIN cs_position b ON a.payeeseq = b.payeeseq
       LEFT JOIN cs_positionrelation c
          ON     (   c.parentpositionseq = b.ruleelementownerseq
                  OR c.childpositionseq = b.ruleelementownerseq)
             AND c.removedate = TO_DATE ('01/01/2200', 'dd/mm/yyyy')
       LEFT JOIN cs_positionrelationtype d
          ON     c.positionrelationtypeseq = d.datatypeseq
             AND d.removedate = TO_DATE ('01/01/2200', 'dd/mm/yyyy')
WHERE      b.removedate = TO_DATE ('01/01/2200', 'dd/mm/yyyy')
       AND b.effectiveenddate = TO_DATE ('01/01/2200', 'dd/mm/yyyy')
       AND a.removedate = TO_DATE ('01/01/2200', 'dd/mm/yyyy')
       AND a.effectiveenddate = TO_DATE ('01/01/2200', 'dd/mm/yyyy')

答案 1 :(得分:1)

(发布我的评论作为答案,以防这是你想要的)

OR与UNION相同。在oracle语法中,您可以执行

SELECT * FROM TABLE1, TABLE2 WHERE B1=C1(+) 
union 
SELECT * FROM TABLE1, TABLE2 WHERE B2=C2(+)

这与 -

相同
SELECT * FROM TABLE1 LEFT JOIN TABLE2 ON (B1=C1 OR B2=C2)

(如果可能的话,也许可以使用UNION ALL)

Union是如何在oracle语法中实现FULL OUTER JOIN。

答案 2 :(得分:0)

问题是你的日期过滤器在where子句:

and d.removedate = to_date('01/01/2200','dd/mm/yyyy')

您需要将此条件移至表的join子句,或使用NVL处理空值(我假设您使用的是Oracle)。 试试这个例子:

select a.firstname,
        a.lastname,
        b.name as "PositionName",
        d.name as "Hierarchy"
  from cs_participant a
      , cs_position b
  left outer join cs_positionrelation c
    on c.parentpositionseq = b.ruleelementownerseq 
    or c.childpositionseq = b.ruleelementownerseq
  left outer join cs_positionrelationtype d
    on d.datatypeseq = c.positionrelationtypeseq
   and d.removedate = c.removedate --MOVED FROM WHERE
 where a.payeeseq = b.payeeseq
   and b.removedate = to_date('01/01/2200','dd/mm/yyyy')
   and b.effectiveenddate = to_date('01/01/2200','dd/mm/yyyy')
   and a.removedate = to_date('01/01/2200','dd/mm/yyyy')
   and c.removedate = to_date('01/01/2200','dd/mm/yyyy')
   and c.effectiveenddate = to_date('01/01/2200','dd/mm/yyyy');

或者只是在你的条件下添加NVL功能:

and nvl(d.removedate,to_date('01/01/2200','dd/mm/yyyy')) = to_date('01/01/2200','dd/mm/yyyy')