The join syntax (involving the JOIN, INNER, OUTER, CROSS, LEFT, RIGHT, FULL, ON, and USING keywords) discussed in Chapter 3 was introduced in Oracle9i Database to make Oracle’s join functionality compliant with the ANSI/ISO SQL92 standard known as SQL92. Prior to Oracle9i Database, Oracle supported the join syntax defined in the SQL86 standard. In addition, also prior to Oracle9i Database, Oracle supported outer joins through a proprietary outer join operator. Even though the new SQL92 join syntax is more elegant and powerful, the old join syntax and the proprietary outer join operator are still supported in Oracle Database 10g, for backward compatibility.
If you are writing a new application, we highly recommend that you use the SQL92 join syntax. However, if you have a pre-Oracle9i Database application, you need to understand both syntaxes—the old and the new. In this appendix, we illustrate the old join syntax, and show how it relates to the new syntax. This will help you to migrate an application from the old syntax to the new syntax, and it will help you when you are faced with maintaining an older application.
The following example illustrates the older inner join syntax:
SELECT d.name, l.regional_group FROM department d, location l WHERE d.location_id = l.location_id;
The corresponding query with the new syntax is:
SELECT d.name, l.regional_group FROM department d JOIN location l ON d.location_id = l.location_id;
Following are the two differences between the old and the new inner join syntax:
The old syntax separates tables in the FROM clause using a comma.
The old syntax specifies the join condition in the WHERE clause.
Since the old syntax uses the WHERE clause to specify the join condition as well as filter conditions, it may take awhile for you to figure out which component of the WHERE clause is a join condition, and which component is a filter condition.
The old syntax of the outer
join is a bit different from that of the
inner join, because it includes a special operator called the
outer join operator.
The outer join operator is a plus sign enclosed in parentheses:
(+)
. This operator is used in a join condition in
the WHERE clause following a field name from the table that you wish
to be considered the optional table.
For example, to list all the departments even if they are not related
to any particular location, you can perform an outer join between the
department
and the location
tables as shown in the following example:
SELECT d.dept_id, d.name, l.regional_group
FROM department d, location l
WHERE d.location_id = l.location_id (+);
DEPT_ID NAME REGIONAL_GROUP ---------- -------------------- ------------------ 10 ACCOUNTING NEW YORK 20 RESEARCH DALLAS 30 SALES 40 OPERATIONS BOSTON
Notice the (+)
operator following
l.location_id
. That makes
location
the optional table in this join, in the
sense that you want to display a row from the
department
table, even though there exists no
corresponding row in the LOCATION table. A corresponding query using
the new join syntax is:
SELECT d.dept_id, d.name, l.regional_group FROM department d LEFT OUTER JOIN location l ON d.location_id = l.location_id;
In the new outer join syntax, the LEFT (or RIGHT) keyword corresponds
to the table from which you want all the rows. This example uses LEFT
to point to department, because we want all the rows from the
department
table irrespective of whether there are
coresponding rows in the location
table.
There are some rules and restrictions on how you can use the outer
join operator in a query. When you use the (+)
operator in a query, Oracle doesn’t allow you to
perform certain other operations in the same query. We discuss these
restrictions and some of the workarounds in the following list:
The outer join operator can appear on only one side of an expression in the join condition. You get an ORA-01468 error if you attempt to use it on both sides. For example:
SELECT d.dept_id, d.name, l.regional_group
FROM department d, location l
WHERE d.location_id (+) = l.location_id(+);
WHERE d.location_id (+) = l.location_id(+) * ERROR at line 3: ORA-01468: a predicate may reference only one outer-joined table
What this means is that the outer join operation using the
(+)
operator is unidirectional. You
can’t perform a bidirectional outer join (known as a
full outer join) using the (+)
operator.
If you are attempting a full outer join by placing the
(+)
operator on both sides in the join condition,
please refer to Section A.2.2, which follows this section.
If a join involves more than two tables, then one table can’t be outer joined with more than one other table in the query. Consider the following tables:
DESC employee
Name Null? Type ----------------------------------------- -------- -------------- EMP_ID NOT NULL NUMBER(5) FNAME VARCHAR2(20) LNAME VARCHAR2(20) DEPT_ID NOT NULL NUMBER(5) MANAGER_EMP_ID NUMBER(5) SALARY NUMBER(5) HIRE_DATE DATE JOB_ID NUMBER(3)DESC job
Name Null? Type ------------------------------- -------- ---- JOB_ID NOT NULL NUMBER(3) FUNCTION VARCHAR2(30)DESC department
Name Null? Type ------------------------------- -------- ---- DEPT_ID NOT NULL NUMBER(5) NAME VARCHAR2(20) LOCATION_ID NUMBER(3)
If you want to list the job function and department name of all the
employees, and you want to include all the departments and jobs that
don’t have any corresponding employees, you would
probably attempt to join the employee
table with
the job
and department
tables,
and make both the joins outer joins. However, since one table
can’t be outer-joined with more than one table you
get the following error:
SELECT e.lname, j.function, d.name
FROM employee e, job j, department d
WHERE e.job_id (+) = j.job_id
AND e.dept_id (+) = d.dept_id;
WHERE e.job_id (+) = j.job_id * ERROR at line 3: ORA-01417: a table may be outer joined to at most one other table
As a workaround, you can create a view with an outer join between two tables, and then outer join the view to the third table:
CREATE VIEW v_emp_job AS SELECT e.dept_id, e.lname, j.function FROM employee e, job j WHERE e.job_id (+) = j.job_id; SELECT v.lname, v.function, d.name FROM v_emp_job v, department d WHERE v.dept_id (+) = d.dept_id;
Instead of creating a view, you can use an inline view to achieve the same result:
SELECT v.lname, v.function, d.name FROM (SELECT e.dept_id, e.lname, j.function FROM employee e, job j WHERE e.job_id (+) = j.job_id) v, department d WHERE v.dept_id (+) = d.dept_id;
Inline views are discussed in Chapter 5.
A condition containing the (+)
operator may not
use the IN operator. For example:
SELECT e.lname, j.function
FROM employee e, job j
WHERE e.job_id (+) IN (668, 670, 667);
WHERE e.job_id (+) IN (668, 670, 667) * ERROR at line 3: ORA-01719: outer join operator (+) not allowed in operand of OR or IN
An outer join condition containing the (+)
operator may not be combined with another condition using the OR
operator. For example:
SELECT e.lname, d.name
FROM employee e, department d
WHERE e.dept_id = d.dept_id (+)
OR d.dept_id = 10;
WHERE e.dept_id = d.dept_id (+) * ERROR at line 3: ORA-01719: outer join operator (+) not allowed in operand of OR or IN
A condition containing the (+)
operator may not
involve a subquery. For example:
SELECT e.lname
FROM employee e
WHERE e.dept_id (+) =
(SELECT dept_id FROM department WHERE name = 'ACCOUNTING'),
(SELECT DEPT_ID FROM DEPARTMENT WHERE NAME = 'ACCOUNTING') * ERROR at line 4: ORA-01799: a column may not be outer-joined to a subquery
As a workaround, you can use an inline view to achieve the desired effect:
SELECT e.lname FROM employee e, (SELECT dept_id FROM department WHERE name = 'ACCOUNTING') V WHERE e.dept_id (+) = v.dept_id;
In the previous section,
you saw that a full outer join using the (+)
operator is not allowed. A UNION of two SELECT statements is a
workaround for this problem. In the following example, the first
SELECT represents an outer join in which
department
is the optional table. The second
SELECT has the location
table as the optional
table. Between the two SELECTS, you get all locations and all
departments. The UNION operation eliminates duplicate rows, and the
result is a full outer join:
SELECT d.dept_id, d.name, l.regional_group
FROM department d, location l
WHERE d.location_id (+) = l.location_id
UNION
SELECT d.dept_id, d.name, l.regional_group
FROM department d, location l
WHERE d.location_id = l.location_id (+) ;
DEPT_ID NAME REGIONAL_GROUP ---------- -------------------- ---------------- 10 ACCOUNTING NEW YORK 20 RESEARCH DALLAS 30 SALES 40 OPERATIONS BOSTON CHICAGO SAN FRANCISCO 6 rows selected.
As you can see, this UNION query includes all the rows you would expect to see in a full outer join. UNION queries are discussed in Chapter 7.
Using the ANSI/ISO-compatible join syntax introduced in Oracle9i Database you can perform a full outer join in a much more straightforward way than shown in the previous example. See Section 3.3.3 in Chapter 3.
The ANSI join syntax
represents a bit of an adjustment to
developers who are used to using Oracle’s
traditional join syntax, including the outer join operator
(+)
. However, there are several advantages to
using the syntax introduced in Oracle9i
Database:
The new join syntax follows the ANSI standard, making your code more portable.
The ON and USING clauses keep join conditions away from the filter conditions in the WHERE clause. This enhances development productivity and the maintainability of your code.
The ANSI/ISO syntax makes it possible to perform a full outer join without having to perform a UNION of two SELECT queries.
We recommend that while working with Oracle9i Database and later Oracle releases, you use the new join syntax instead of the traditional join syntax.
3.12.108.175