February 2012
M T W T F S S
« Apr    
 12345
6789101112
13141516171819
20212223242526
272829  

Limitation of Oracle syntax for left outer join (+)

Oracle guys usually use Oracle native left outer join syntax to do left outer join, such as

cbo@ORCL> select * from t1,t2 where t1.x = t2.x(+);

         C          X          Y          D          X          Y
---------- ---------- ---------- ---------- ---------- ----------
        11          1         51         21          1         51
        13          3         53         23          3         40
        15          5         55         25          5         54
        14          4         54
        12          2         52

An more advanced way is:

cbo@ORCL> select * from t1,t2 where t1.x = t2.x(+) and t2.y(+)>50;

         C          X          Y          D          X          Y
---------- ---------- ---------- ---------- ---------- ----------
        11          1         51         21          1         51
        15          5         55         25          5         54
        14          4         54
        13          3         53
        12          2         52

Be note, this is different from:

cbo@ORCL> select * from t1,t2 where t1.x = t2.x(+) and t2.y>50;

         C          X          Y          D          X          Y
---------- ---------- ---------- ---------- ---------- ----------
        11          1         51         21          1         51
        15          5         55         25          5         54

The t2.y(+) > 50, as a join condition, is applied at join time, but t2.y>50 is applied after the result set is return from joining. Also note that, as t2 > 50 make sure that the rows in t2 is not null, so the SQL statement will become an  normal equi-join. This is clear in the execution plans:

cbo@ORCL> select * from t1,t2 where t1.x = t2.x(+) and t2.y(+)>50;

Execution Plan
----------------------------------------------------------
Plan hash value: 1823443478

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     5 |    65 |     5  (20)| 00:00:01 |
|*  1 |  HASH JOIN OUTER   |      |     5 |    65 |     5  (20)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| T1   |     5 |    30 |     2   (0)| 00:00:01 |
|*  3 |   TABLE ACCESS FULL| T2   |     1 |     7 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("T1"."X"="T2"."X"(+))
   3 - filter("T2"."Y"(+)>50)

cbo@ORCL> select * from t1,t2 where t1.x = t2.x(+) and t2.y>50;

Execution Plan
----------------------------------------------------------
Plan hash value: 2959412835

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |    13 |     5  (20)| 00:00:01 |
|*  1 |  HASH JOIN         |      |     1 |    13 |     5  (20)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL| T2   |     1 |     7 |     2   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| T1   |     5 |    30 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("T1"."X"="T2"."X")
   2 - filter("T2"."Y">50)

 

But this method have its own limitations. The SQL Reference list such limitations:

  1. You cannot specify the (+) operator in a query block that also contains FROM clause join syntax.
  2. The (+) operator can appear only in the WHERE clause or, in the context of left-correlation (when specifying the TABLE clause) in the FROM clause, and can be applied only to a column of a table or view.
  3. If A and B are joined by multiple join conditions, then you must use the (+) operator in all of these conditions. If you do not, then Oracle Database will return only the rows resulting from a simple join, but without a warning or error to advise you that you do not have the results of an outer join.
  4. The (+) operator does not produce an outer join if you specify one table in the outer query and the other table in an inner query.
  5. You cannot use the (+) operator to outer-join a table to itself, although self joins are valid. For example, the following statement is not valid:
    – The following statement is not valid:
    SELECT employee_id, manager_id
       FROM employees
       WHERE employees.manager_id(+) = employees.employee_id;
    However, the following self join is valid:SELECT e1.employee_id, e1.manager_id, e2.employee_id
       FROM employees e1, employees e2
       WHERE e1.manager_id(+) = e2.employee_id
       ORDER BY e1.employee_id, e1.manager_id, e2.employee_id;
  6. The (+) operator can be applied only to a column, not to an arbitrary expression. However, an arbitrary expression can contain one or more columns marked with the (+) operator.
  7. A WHERE condition containing the (+) operator cannot be combined with another condition using the OR logical operator.
  8. A WHERE condition cannot use the IN comparison condition to compare a column marked with the (+) operator with an expression.

 

It’s a little confused to read these statements, for the limitation I highlighted, there are two variations:

1. I can’t add OR operand predicates on the right table at join time, such the one below expressed in ANSI-SQL.

select t1.c,t2.d from t1 left outer join t2 on (t1.x = t2.x and (t2.y>23 or t2.y<23) );

2. I can’t combine OR operands as left outer join condition. such the one below expressed in ANSI-SQL.

select t1.c,t2.d from t1 left outer join t2 on (t1.x = t2.x or t1.y = t2.y);

 

Another limitation is that, I can’t add predicate on the left table at join time, such as the one below expressed in ANSI-SQL.

select * from t1 left outer join t2 on (t1.x = t2.x and t1.c = 11);

Clearly, Oracle recommend use ANSI-SQL style left outer join syntax, just as the examples above.

But another question comes, how Oracle implement ANSI-SQL left outer join syntax, and how to rewrite these unsupported statements in native/complex ways?

2 comments to Limitation of Oracle syntax for left outer join (+)

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>