1.
JOIN的基本概念:
A join is a SQL query that extracts information from two or more tables or views. When you specify multiple tables or views in the FROM clause of a query, Oracle performs a join, linking rows from multiple tables together. There are several types of joins to be aware of:
A.
Inner joins
Inner joins are the regular joins. An inner join returns the rows that satisfy the join condition. Each row returned by an inner join contains data from all tables involved in the join.
B.
Outer joins
Outer joins are an extension to the inner joins. An outer join returns the rows that satisfy the join condition and also the rows from one table for which no corresponding rows exist in the other table.
C.
Self joins
A self join is a join of a table to itself.
2.笛卡儿积:
If you don't specify the join condition while joining two tables, Oracle combines each row from the first table with each row of the second table. This type of result set is called as a Cartesian product.
The number of rows in a Cartesian product is the product of the number of rows in each table.
3.
JOIN的条件:
Usually the join condition is specified on the foreign key columns of one table and the primary key or unique key columns of another table. However, you can specify other columns as well. Each join condition involves columns that relate two tables.
A join condition may involve more than one column. This is usually the case when a foreign key constraint consists of multiple columns.
A join condition must involve columns with compatible datatypes. Note that the datatype of the columns involved in a join condition need to be compatible, not the same.
Oracle performs automatic datatype conversion between the join columns, if required
4.外连接的语法:
The 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, i.e., (+).
This operator is used in the join condition in the WHERE clause following a field name from the table that you wish to be considered the optional table.(
如果表A中某条记录在表B中没有对应的记录存在,而又想列出表A中所有的记录,此时采用内连接将无法达到目的。可以采用外连接的方法,在WHERE子句中,表B相应字段名的右方添加符号:(+),则Oracle在连接时则会自动生成一条空记录和表A的记录进行连接)
5.外连接的约束:
A.
The outer join operator can appear on only one side of an expression in the join condition. You get an ORA-1468 error if you attempt to use it on both sides.
B.
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.
Wrong:
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;
Correct:
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;
Correct Also:
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;
C.
An outer join condition containing the (+) operator may not use the IN operator.
D.
An outer join condition containing the OR operator may not be combined with another condition using the OR operator.
SELECT E.LNAME, D.NAME
FROM EMPLOYEE E, DEPARTMENT D
WHERE E.DEPT_ID = D.DEPT_ID (+)
OR D.DEPT_ID = 10;
E.
A condition containing the (+) operator may not involve a subquery
Wrong:
SELECT E.LNAME
FROM EMPLOYEE E
WHERE E.DEPT_ID (+) = (SELECT DEPT_ID
FROM DEPARTMENT WHERE NAME = ACCOUNTING');
Correct:
SELECT E.LNAME
FROM EMPLOYEE E,
(SELECT DEPT_ID FROM DEPARTMENT WHERE NAME = 'ACCOUNTING') V
WHERE E.DEPT_ID (+) = V.DEPT_ID;
6. 完全外连接
(Full Outer Join):
There are situations when you may want a bidirectional outer join, i.e., you want to include all the rows from A and B that are:
1.
From the result of the inner join.
2.
From A that don't have corresponding rows in B.
3.
From B that don't have corresponding rows in A.
A UNION of two SELECT statements is a work around for this problem. The UNION operation eliminates duplicate rows, and the result is a full outer join
Example:
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 (+) ;
7.自连接
(Self-Join):
There are situations in which one row of a table is related to another row of the same table.Such as:
CREATE TABLE EMPLOYEE (
EMP_ID
NUMBER (4) NOT NULL PRIMARY KEY,
FNAME
VARCHAR2 (15),
LNAME
VARCHAR2 (15),
DEPT_ID
NUMBER (2),
MANAGER_EMP_ID NUMBER (4) REFERENCES EMPLOYEE(EMP_ID),
SALARY
NUMBER (7,2),
HIRE_DATE
DATE,
JOB_ID
NUMBER (3));
To get information about an employee and his manager, you have to join the EMPLOYEE table with itself.
SELECT E.NAME EMPLOYEE, M.NAME MANAGER
FROM EMPLOYEE E, EMPLOYEE M
WHERE E.MANAGER_EMP_ID = M.EMP_ID;
Even though the EMPLOYEE table has 14 rows, the previous query returned only 13 rows. This is because there is an employee without a MANAGER_EMP_ID. Oracle excludes this row from the result set while performing the self inner join. To include the employee(s) without a MANAGER_EMP_ID, you need an outer join:
SELECT E.LNAME EMPLOYEE, M.LNAME MANAGER
FROM EMPLOYEE E, EMPLOYEE M
WHERE E.MANAGER_EMP_ID = M.EMP_ID (+);
8.不相等条件的自连接
(Self Non-Equi-Joins):
assume that you are in charge of organizing interdepartmental basket ball competition within your company. It is your responsibility to draw the teams and schedule the competition.
SELECT NAME FROM DEPARTMENT;
NAME
--------------
ACCOUNTING
RESEARCH
SALES
OPERATIONS
Wrong:
SELECT D1.NAME TEAM1, D2.NAME TEAM2
FROM DEPARTMENT D1, DEPARTMENT D2
WHERE D1.DEPT_ID != D2.DEPT_ID;
TEAM1
TEAM2
-------------- --------------
RESEARCH ACCOUNTING
SALES
ACCOUNTING
OPERATIONS
ACCOUNTING
ACCOUNTING RESEARCH
SALES
RESEARCH
OPERATIONS
RESEARCH
ACCOUNTING
SALES
RESEARCH
SALES
OPERATIONS
SALES
ACCOUNTING
OPERATIONS
RESEARCH
OPERATIONS
SALES
OPERATIONS
In this result set, you have permutations such as (RESEARCH, ACCOUNTING) and (ACCOUNTING, RESEARCH), and so on. Therefore, each team plays against the others twice. You need to remove these permutations, which you rightly consider to be duplicates. You think about using DISTINCT. DISTINCT will not help here, because the row (RESEARCH, ACCOUNTING) is different from the row (ACCOUNTING, RESEARCH) from the viewpoint of DISTINCT;
(在这个结果集中,我们对诸如
(RESEARCH,ACCOUNTING)和(ACCOUNTING,RESEARCH)的记录进行了位置调换,所以每个队都和其它的队伍进行了两次的比赛。我们必须把那些重复的记录去掉,也许我们会考虑使用DISTINCT,但是在这里DISTINCT不会起作用,因为像(RESEARCH,ACCOUNTING)和(ACCOUNTING,RESEARCH)这样的记录以DISTINCT的观点来看是两条不同的记录)
Correct:
SELECT D1.NAME TEAM1, D2.NAME TEAM2
FROM DEPARTMENT D1, DEPARTMENT D2
WHERE D1.DEPT_ID < D2.DEPT_ID;
TEAM1
TEAM2
-------------- --------------
ACCOUNTING
RESEARCH
ACCOUNTING
SALES
RESEARCH
SALES
ACCOUNTING
OPERATIONS
RESEARCH
OPERATIONS
SALES
OPERATIONS
Conceptually, when Oracle executes this query, a Cartesian product is first formed with 16 rows. Then the less-than (<) operator in the join condition restricts the result set to those rows in which the DEPT_ID of Team 1 is less than the DEPT_ID of Team 2. The less-than (<) operator eliminates the duplicates, because for any given permutation of two departments this condition is satisfied for only one. Using greater-than (>) instead of less-than (<) will also give you the required result
(理论上来说,当
Oracle执行这个查询的时候,首先会产生一个包含了16条记录的笛卡儿积,然后连接条件中的小于号会对返回的记录集进行筛选:返回的记录中Team 1的DEPT_ID必须比Team 2的DEPT_ID小。因为对于诸如(RESEARCH,ACCOUTNING)和(ACCOUTING,RESEARCH)的记录,总会有一条记录满足以上的条件,所以可以去掉重复的记录。使用大于号同样会返回你想要的记录,只不过记录中的队伍顺序调换过来了而已)
9.
Oracle 9i的JOIN新语法:
Oracle9i introduced new join syntax that is compliant to the ANSI SQL standard defined for SQL/92. Prior to Oracle9i, Oracle supported the join syntax defined in the SQL/86 standard. In addition, Oracle supported outer joins through the proprietary outer join operator (+), discussed earlier in this chapter. The old join syntax and the proprietary outer join operator are still supported in Oracle9i.
With the new syntax in Oracle9i, you specify the join type with the JOIN keyword in the FROM clause. For example, to perform an inner join between tables DEPARTMENT and LOCATION, you specify:
FROM DEPARTMENT D INNER JOIN LOCATION L
In the traditional join syntax, the join condition is specified in the WHERE clause. With the new syntax in Oracle9i, the purpose of the WHERE clause is for filtering only.
The join condition is separated from the WHERE clause and put in a new ON clause, which appears as part of the FROM clause. The join condition of the previous example will be specified using the new syntax as:
ON D.LOCATION_ID = L.LOCATION_ID;
The complete join, using the new syntax, will be:
SELECT L.LOCATION_ID, D.NAME, L.REGIONAL_GROUP
FROM DEPARTMENT D
INNER JOIN LOCATION L
ON D.LOCATION_ID = L.LOCATION_ID;
10.在
JOIN中使用USING子句:
Specifying the join condition is further simplified if:
- You use equi-joins, and
- The column names are identical in both the tables.
If these two conditions are satisfied, you can apply the new USING clause to specify the join condition. In the previous example, we used an equi-join. Also, the column involved in the join condition (LOCATION_ID) is named identically in both the tables. Therefore, this join condition can also be written as:
FROM DEPARTMENT D INNER JOIN LOCATION L USING (LOCATION_ID);
The USING clause tells Oracle that the tables in the join have identical names for the column in the USING clause.
Now, Oracle merges those two columns and recognizes only one such column. If you have included the join column in the SELECT list, Oracle doesn't allow you to qualify the column with a table name (or table alias). Our SELECT clause, then, needs to appear as follows: The complete syntax with the USING clause will be:
SELECT LOCATION_ID, D.NAME, L.REGIONAL_GROUP
FROM DEPARTMENT D INNER JOIN LOCATION L
USING (LOCATION_ID);
The behavior of USING contrasts with the traditional join syntax, in which you must qualify the identical column names with the table name or table alias
If a join condition consists of multiple columns, you need to specify all the column conditions in the ON clause separated by AND. For example, if tables A and B are joined based on columns c1 and c2, the join condition would be:
SELECT ...
FROM A INNER JOIN B
ON A.c1 = B.c1 AND A.c2 = B.c2
If the column names are identical in the two tables, you can use the USING clause and specify all the columns in one USING clause, separated by commas. The previous join condition can be rewritten as:
SELECT ...
FROM A INNER JOIN B
USING (c1, c2)
11.交叉连接
(Cross Join):
An advantage of the new join syntax is that you can't accidentally generate a Cartesian product by omitting join conditions. But what if you really do want a Cartesian product?
SELECT *
FROM A CROSS JOIN B;
The advantage of this new syntax is that it makes your request for a cross join (or Cartesian product) explicit。
The new join syntax doesn't allow you to accidentally forget the join condition while performing a join, and thereby helps prevent you from accidentally generating a Cartesian product. When you specify any of the new join keywords in the FROM clause, you tell Oracle that you are going to perform a JOIN, and Oracle insists that you specify the join condition in an ON or USING clause.
12.
ANSI外连接语法:
The ANSI outer join syntax doesn't use the outer join operator (+) in the join condition; rather, it specifies the join type in the FROM clause. The syntax of ANSI outer join is:
FROM table1 { LEFT | RIGHT | FULL } [OUTER] JOIN table2
The syntax elements are:
table1, table2
Specifies the tables on which you are performing the outer join.
LEFT
Specifies that the results be generated using all rows from table1. For those rows in table1 that don't have corresponding rows in table2, NULLs are returned in the result set for the table2 columns. This is the equivalent of specifying (+) on the table2 side of the join condition in the traditional syntax.
RIGHT
Specifies that the results be generated using all rows from table2. For those rows in table2 that don't have corresponding rows in table1, NULLs are returned in the result set for the table1 columns. This is the equivalent of specifying (+) on the table1 side of the join condition in the traditional syntax.
FULL
Specifies that the results be generated using all rows from table1 and table2. For those rows in table1 that don't have corresponding rows in table2, NULLs are returned in the result set for the table2 columns. Additionally, for those rows in table2 that don't have corresponding rows in table1, NULLs are returned in the result set for the table1 columns. There is no equivalent in the traditional syntax for a FULL OUTER JOIN.
OUTER
Specifies that you are performing an OUTER join. This keyword is optional.
If you use LEFT, RIGHT, or FULL, Oracle automatically assumes an outer join. The OUTER is for completeness sake, and complements the INNER keyword.
13.使用新的
JOIN语法的好处:
The new 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 of using the new syntax:
A.
The new join syntax follows the ANSI standard and therefore makes your code more portable.
B.
The new ON and USING clauses help in separating the join conditions from other filter conditions in the WHERE clause. This enhances development productivity and maintainability of your code.
C.
The new syntax makes it possible to perform a full outer join without having to perform a UNION of two SELECT queries.