Oracle Joins - Comparison Between Conventional Syntax VS Ansi Syntax

Oracle Joins - Comparison between conventional syntax VS ANSI Syntax

Grouping answers together

  1. Use explicit JOINs rather than implicit (regardless whether they are outer joins or not) is that it's much easier to accidently create a cartesian product with the implicit joins. With explicit JOINs you cannot "by accident" create one. The more tables are involved the higher the risk is that you miss one join condition.
  2. Basically (+) is severely limited compared to ANSI joins. Furthermore it is only available in Oracle whereas the ANSI join syntax is supported by all major DBMS
  3. SQL will not start to perform better after migration to ANSI syntax - it's just different syntax.
  4. Oracle strongly recommends that you use the more flexible FROM clause join syntax shown in the former example. In the past there were some bugs with ANSI syntax but if you go with latest 11.2 or 12.1 that should be fixed already.
  5. Using the JOIN operators ensure your SQL code is ANSI compliant, and thus would allow a front-end application to be more easily ported for other database platforms.
  6. Join conditions have a very low selectivity on each table and a high selectivity on the tuples in the theoretical cross product. Conditions in the where statement usually have a much higher selectivity.
  7. Oracle internally converts ANSI syntax to the (+) syntax, you can see this happening in the execution plan's Predicate Information section.

Possible Pitfall in using ANSI syntax on 12c engine

Including a possibility of bug in JOIN in 12c. See here

FOLLOW UP:

Quest SQL optimizer tool rewrites the SQL to ANSI syntax.

Difference between Oracle's plus (+) notation and ansi JOIN notation?

AFAIK, the (+) notation is only present for backwards compatibility because Oracle debuted it before the ANSI standard for joins was put in place. It's specific to Oracle and you should avoid using it in new code when there's an equivalent standards-compliant version available.

It seems there are differences between the two, and the (+) notation has restrictions that the ANSI join syntax does not have. Oracle themselves recommend that you not use the (+) notation.
Full description here in the Oracle® Database SQL Language Reference
11g Release 1 (11.1):

Oracle recommends that you use the FROM clause OUTER JOIN syntax rather than the Oracle join operator. Outer join queries that use the Oracle join operator (+) are subject to the following rules and restrictions, which do not apply to the FROM clause OUTER JOIN syntax:

  • You cannot specify the (+) operator in a query block that also contains FROM clause join syntax.
  • 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.
  • 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.
  • 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.
  • 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:

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;

  • 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.
  • A WHERE condition containing the (+) operator cannot be combined with another condition using the OR logical operator.
  • A WHERE condition cannot use the IN comparison condition to compare a column marked with the (+) operator with an expression.

If the WHERE clause contains a condition that compares a column from table B with a constant, then the (+) operator must be applied to the column so that Oracle returns the rows from table A for which it has generated nulls for this column. Otherwise Oracle returns only the results of a simple join.

In a query that performs outer joins of more than two pairs of tables, a single table can be the null-generated table for only one other table. For this reason, you cannot apply the (+) operator to columns of B in the join condition for A and B and the join condition for B and C. Refer to SELECT for the syntax for an outer join.

What is difference between ANSI and non-ANSI joins, and which do you recommend?

both syntaxes usually work without problems, but if you try to add a where condition you will see that with the second one is much simpler to understand which is the join condition and which is the where clause.

1)

  SELECT a.name,
a.empno,
b.loc
FROM tab a,
tab b
WHERE a.deptno = b.deptno(+)
AND a.empno = 190;

2)

         SELECT a.name,
a.empno,
b.loc
FROM tab a,
LEFT OUTER JOIN tab b
ON a.deptno = b.deptno
WHERE a.empno = 190;

Also, it's much easier to recognize an outer join and do not forget to include the (+). Overall you can say it's just a question of taste, but the truth is that the second syntax is much more readable and less prone to errors.

Will ANSI JOIN vs. non-ANSI JOIN queries perform differently?

The two queries are the same, except the second is ANSI-92 SQL syntax and the first is the older SQL syntax which didn't incorporate the join clause. They should produce exactly the same internal query plan, although you may like to check.

You should use the ANSI-92 syntax for several of reasons

  • The use of the JOIN clause separates
    the relationship logic from the
    filter logic (the WHERE) and is thus
    cleaner and easier to understand.
  • It doesn't matter with this particular query, but there are a few circumstances where the older outer join syntax (using + ) is ambiguous and the query results are hence implementation dependent - or the query cannot be resolved at all. These do not occur with ANSI-92
  • It's good practice as most developers and dba's will use ANSI-92 nowadays and you should follow the standard. Certainly all modern query tools will generate ANSI-92.
  • As pointed out by @gbn, it does tend to avoid accidental cross joins.

Myself I resisted ANSI-92 for some time as there is a slight conceptual advantage to the old syntax as it's a easier to envisage the SQL as a mass Cartesian join of all tables used followed by a filtering operation - a mental technique that can be useful for grasping what a SQL query is doing. However I decided a few years ago that I needed to move with the times and after a relatively short adjustment period I now strongly prefer it - predominantly because of the first reason given above. The only place that one should depart from the ANSI-92 syntax, or rather not use the option, is with natural joins which are implicitly dangerous.

Why does this query perform better than the ANSI JOIN version?


Why is this so much more efficient?

One of your plans is probably doing OR expansion and the other probably is not.

Oracle's logic to transform ANSI join syntax queries is not perfect and not identical to the logic to transform non ANSI join syntax queries. If you will look on Oracle's support website for patches, you will see that just about every release has a number of bugfixes in this area.

The answer extended to other areas as well. For example, in some Oracle versions, you can have a fast-running SELECT statement that will tank if you put it into an INSERT statement or a CREATE TABLE AS SELECT statement.

Oracle joins and ANSI joins are conceptually the same and should make no difference. But, in reality, there are differences.

Is there an Oracle official recommendation on the use of explicit ANSI JOINs vs implicit joins?

I haven't seen it if there is. The reason for preferring ANSI syntax for outer joins in particular (apart from the non-standarrd, Oracle-specific (+) symbol) is that more outer joins are expressible using the ANSI syntax. The restriction "ORA-01417: a table may be outer joined to at most one other table" applies to (+) outer joins but not to ANSI outer joins. Other restrictions on (+) that do not apply to ANSI outer joins are documented here.

One highly respected Oracle expert actually recommends sticking to the old syntax for inner joins - see Jonathan Lewis's blog. He says there that ANSI joins are transformed to traditional Oracle joins under the covers anyway. I don't agree with him 100% (I prefer ANSI joins myself in general), but would not claim to have a fraction of his knowledge on the topic.

In a nutshell, ANSI outer joins are technically superior to old (+) joins, whereas with inner joins it is more just a matter of style.

Oracle (Old?) Joins - A tool/script for conversion?

The (+) is Oracle specific pre-ANSI-92 OUTER JOIN syntax, because ANSI-89 syntax doesn't provide syntax for OUTER JOIN support.

Whether it is RIGHT or LEFT is determined by which table & column reference the notation is attached to. If it is specified next to a column associated with the first table in the FROM clause - it's a RIGHT join. Otherwise, it's a LEFT join. This a good reference for anyone needing to know the difference between JOINs.

First query re-written using ANSI-92 syntax:

    SELECT e.lastname,
d.department_name
FROM EMPLOYEES e
RIGHT JOIN DEPARTMENTS d ON d.departmentid = e.departmentid

Second query re-written using ANSI-92 syntax:

   SELECT e.lastname,
d.department_name
FROM EMPLOYEES e
LEFT JOIN DEPARTMENTS d ON d.departmentid = e.departmentid

Oracle Plus (+) Joins to ANSI conversion

Here's what I came up with:

SELECT *
FROM stg_rev_apportion_csc_no t1
LEFT JOIN stg_sep_vl t3
ON t1.business_date = t3.business_date AND
t1.csc_app_no = t3.csc_app_no AND
t1.journey_no = t3.journey_no AND
t1.purse_txn_ctr = t3.purse_txn_no AND
4357 = t3.msg_type_cd
LEFT JOIN stg_sep_vl t2
ON t1.business_date = t2.business_date AND
t1.csc_app_no = t2.csc_app_no AND
t1.journey_no = t2.journey_no AND
t1.trip_no = t2.trip_no + 1 AND
13070 = t2.msg_type_cd;

Tables t2 and t3 are outer joined to t1, so you either list t1 first and do a left join, or list t2 and t3 first and do a right join.



Related Topics



Leave a reply



Submit