简体   繁体   English

3+表上的Oracle LEFT OUTER JOIN-(+)语法与ANSI语法

[英]Oracle LEFT OUTER JOIN on 3+ tables - (+) Syntax versus ANSI Syntax

Scenario: I need to convert an existing query using (+) outer join syntax to ANSI syntax. 场景:我需要使用(+)外连接语法将现有查询转换为ANSI语法。 Reason : One of the JOINS requires an OR operand, which is not allowed with the (+) operator, but is allowed with LEFT OUTER JOIN. 原因 :其中一个JOINS要求使用OR操作数,(+)运算符不允许使用OR,而LEFT OUTER JOIN允许使用。 (At least I'm assuming this is correct.) (至少我认为这是正确的。)

Goal of the Query: Table D contains that name of two hierarchies, BB and Commercial. 查询目标:表D包含两个层次结构的名称,即BB和Commercial。 Simple joins through these tables will return 19 Positions and their respective hierarchy. 通过这些表的简单联接将返回19个位置及其各自的层次结构。 I need to see ALL positions with the appropriate hierarchy if valid, else a NULL value. 我需要查看所有具有适当层次结构的位置(如果有效),否则为NULL值。

(+) Syntax Query - working correctly: (+)语法查询-正常工作:

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')

Result Example: 结果示例:

在此处输入图片说明

My Attempt with ANSI Syntax: 我对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 Query Results: ANSI查询结果:

This query returns ONLY the Positions that are assigned to a hierarchy. 该查询仅返回分配给层次结构的位置。 I need to see ALL positions, with or without a hierarchy assignment, which are currently being excluded from the results. 我需要查看所有位置(带有或不带有层次结构分配),这些位置当前已从结果中排除。

You have two date literals as outer join conditions in your first query, but you leave them in the where clause in the second query. 在第一个查询中,您有两个日期文字作为外部连接条件,但在第二个查询中将它们保留在where子句中。 To change the syntax properly, those criteria need to be left as part of the join criteria. 为了正确地更改语法,这些条件必须保留为联接条件的一部分。 It's also bad form to combine the two join syntax (ie having comma seperated tables and the join keyword in the same query). 结合两种联接语法(即在同一查询中具有逗号分隔的表和join关键字)也是一种不好的形式。

Below is the first query properly adapted to SQL-99 syntax: 以下是正确适应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')

Once that's done, adapting it to join on either column is trivial: 完成后,对其进行调整以使其可以在任一列上进行连接都是微不足道的:

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')

(Posting my comment as answer in case this was what you wanted) (如果需要的话,请发表我的评论作为答案)

OR is same as a UNION. OR与UNION相同。 In oracle syntax, you can do 在oracle语法中,您可以执行

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

This is the same as - 这与-

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

(Maybe use UNION ALL if at all possible) (如果可能,请使用UNION ALL)

Union is how a FULL OUTER JOIN was possible in oracle syntax. 联合是使用oracle语法实现完全外部联接的方式。

The problem is your date filters in where clause: 问题在于您在where子句中的日期过滤器:

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

You need to move this condition to the table's join clause, or deal with null values using NVL (I suppose you are using Oracle). 您需要将此条件移至表的join子句,或者使用NVL处理空值(我想您正在使用Oracle)。 Try this for example: 尝试以下示例:

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');

Or just add the NVL function in your condition: 或者只是在您的条件下添加NVL函数:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM