Oracle 8i 之前的表连接:
Oracle 9 之后的表连接:
注意:
- 员工表中没有部门为 "40" 的员工。
- 员工编号 "7839" 为职位最高的人,它没有上级。
- 员工编号为 "7654"、"7876"、"7934" 没有所属的部门。
“连接(Join )”是一个查询,把两个或多个表(table)、视图(view)或物化视图(materialized view)的数据行合并。
无论何时,当多个表出现在 FROM 子句,Oracle 数据库都会执行一个连接。select 列出所有表的所有列。如下所示:
select * from emp, dept
如果任何两个表有同名的列,那么你必须用表名限定所有引用的列,避免歧义。
select emp.empno,
emp.ename,
emp.job,
emp.mgr,
emp.hiredate,
emp.sal,
emp.comm,
emp.deptno,
dept.deptno,
dept.dname,
dept.loc
from emp, dept
大多数连接查询至少包含一个连接条件(或是在 FROM 子句,或是 WHERE 子句)。连接条件在每个不同的表中比较两个列。执行一个连接时,Oracle 合并每个表的每行,以计算连接条件是否为 TRUE。连接条件中的列不是必须出现在 SELECT 子句中。
若要执行三个,或更多个表的连接,Oracle 先根据连接条件,比较前两个表的列,连接前两个表,再基于连接条件,把该连接结果与另一个表连接。Oracle 继续这一过程,直到所有的表都被连接到结果中。优化器基于连接条件、表的索引,以及表的统计信息决定连接的顺序。
包含连接条件的 WHERE 子句也可以包含其他条件,这些条件可以进一步限制连接返回的行,如表中的某列。
注意:若 WHERE 子句有连接条件,则不能在 WHERE 子句中指定 LOB 列。WHERE 子句中使用 LOB 也会受到其他限制。参阅:Oracle Database SecureFiles 和 Large Objects 开发人员指南。
“等值连接”是在连接条件中包含 "=" 操作符的连接。“等值连接”合并具有相等值的、指定列的行。
根据内部算法,优化器选择执行的连接,一个单表等值连接的列的总大小被限制在一个数据块内,以减少开销。数据块的大小是由初始化参数 DB_BLOCK_SIZE 指定。
示例1:演示返回所有员工的编号和名字,以及所在的部门编号和名称。
select emp.empno, emp.ename, dept.deptno, dept.dname
from emp, dept
where emp.deptno = dept.deptno
order by emp.empno asc
结果:
说明:
- EMP 表共有14个员工,其中3个员工没有部门。因此,结果只包含有所属部门的员工,没有无部门的员工。
示例2:演示返回职位为“经理”员工的编号和名字,以及所在的部门编号和名称。
select emp.empno, emp.ename, dept.deptno, dept.dname
from emp, dept
where emp.deptno = dept.deptno
and emp.job = 'MANAGER'
order by emp.empno asc
结果:
“自连接”是一个表连接自己的连接。这个表在 FROM 子句中出现两次,并加上表别名,以便在连接条件中限定列名。执行一个自连接时,Oracle 数据库合并,并返回所有满足连接条件的行。
示例3:演示返回员工的直接上级。
select '<' || e2.ename || '> works for <' || e1.ename || '>'
from emp e1, emp e2
where e1.empno = e2.mgr
order by e1.empno asc
结果:
上边的连接只返回满足连接条件的数据行,但是有时还需要返回表中不满足连接条件的那些行。此时,就需要“外连接”。
若连接两个表时,没有连接条件,则 Oracle 会返回它们的笛卡尔积。把一个表的每行与另一个表的每行合并(积)。笛卡尔积会产生很多行,很少使用。如两个 100 行的表的笛卡尔积有 100×100=10,000 行。除非你需要笛卡尔积,否则最好有连接条件。如果一个查询要连接三个或更多的表,并且,你没有规定连接条件,那么优化器会选择一个连接顺序,以避免产生中间结果的笛卡尔积。
示例4:演示笛卡儿积。
select * from emp cross join dept order by emp.empno asc
执行结果:
“内连接”,有时也称为“简单连接”是一个连接两个或多个表,只返回满足连接条件的那些数据行。
示例5:演示返回员工部门编号对应的部门信息。没有部门编号的员工,则不返回。
select emp.empno, emp.ename, dept.deptno, dept.dname
from emp
inner join dept on emp.deptno = dept.deptno
order by emp.empno asc
结果:
说明:
- 相当于“等值连接”。
“外连接”扩展“简单连接(内连接)”。“外连接”,除了返回所有满足条件的行,也返回那些满足一个表的行,而不满足其他表的连接条件的行。
无论指定什么形式,都不能在 WHERE 子句,包含“外连接”的子查询里比较一个列。
你可以使用“外连接”填充稀疏数据(sparse data,也许类似稀疏矩阵)的差距。这种连接称为“分区外连接”,使用 query_partition_clause join_clause 语法。稀疏数据是一维、没有所有可能值的行,如时间、部门等。例如,销售数据,在一个给定日期段内,通常只包含部分售出产品的数据(实际情况也是,在给定日期内,产品不可能都卖出)。在进行数据离散复杂分析(data sparsity complicates analytic computation),或是直接查询稀疏数据,可能会缺失一些数据,这种情况下,填充数据的间隙将很有用。
示例6:左外连接。演示返回所有员工对应的部门信息。
select emp.*, dept.*
from emp
left outer join dept on emp.deptno = dept.deptno
order by emp.empno asc
等价于
select emp.*, dept.*
from emp, dept
where emp.deptno = dept.deptno(+)
order by emp.empno asc
结果:
说明:
- 在 FROM 子句使用 LEFT [ OUTER ] JOIN 语法,或在 WHERE 子句的连接条件中,对表 B 的所有列,应用外连接运算符(+ )。
- 在 A 中没有匹配 B 的那些行,对 select 表达式包含的 B 的列,Oracle 数据库返回 null。如上图,第5、11、14 行。
示例7:右外连接。演示返回所有部门下的员工信息。
select emp.*, dept.*
from emp
right outer join dept on emp.deptno = dept.deptno
order by emp.empno asc
等价于
select emp.*, dept.*
from emp, dept
where emp.deptno(+) = dept.deptno
order by emp.empno asc
结果:
说明:
- 在 FROM 子句使用 RIGHT [ OUTER ] JOIN 语法,或在 WHERE 子句的连接条件中,对表 A 的所有列,应用外连接运算符(+ )。
- 在 B 中没有匹配 A 的那些行,对 select 表达式包含的 A 的列,Oracle 数据库返回 null。如上图,第 12 行。
示例8:全外连接。演示返回所有员工和所有部门的对应信息。员工可能相应的部门信息,部门可能是临时组建还没有员工。
select emp.*, dept.*
from emp
full outer join dept on emp.deptno = dept.deptno
order by emp.empno asc
结果:
说明:
- 1,在 FROM 子句应用 FULL [OUTER] JOIN 语法。
- 2,全外连接是左外连接和右外连接的扩展,对于不满足连接条件的行,返回 null。如图,第 5、11、14、15 行。
参考:
- join_clause for more information about using outer joins to fill gaps in sparse data
- Oracle Database Data Warehousing 指南 for a complete discussion of group outer joins and filling gaps in sparse data
Oracle 推荐使用 FROM 子句 OUTER JOIN 语法,而不是连接运算符(+)。使用连接运算符(+)进行外连接查询会遵循以下规则和限制,FROM 子句的 OUTER JOIN 语法则不会:
SELECT employee_id, manager_id
FROM employees
WHERE employees.manager_id(+) = employees.employee_id;
但是,下面的自连接是有效的:
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;
如果 WHERE 子句中包含表 B 的列与一个常量进行比较的条件,那么连接运算符(+)必须要应用于这个列,以便 Oracle 返回表 A 的行,这些行,对于该列,会产生null。否则,Oracle 只返回一个简单连接的结果。
在执行多个表的外连接查询时,一个单一的表对于其他表可以生成一个空表。因此,你可以在连接 A 和 B 的连接条件上,,并且,B 和 C 的连接条件上,对 B 的列不使用连接运算符(+)。请参阅 SELECT 外部连接语法。
“反连接”返回谓词(predicate )左边的行,这些行不满足谓词右边。它返回不匹配(NOT IN)右边子查询的行。
示例9:演示返回部门不在 DALLAS 和 CHICAGO 的员工信息。
select *
from emp
where emp.deptno not in (select dept.deptno
from dept
where dept.loc = 'DALLAS'
or dept.loc = 'CHICAGO')
order by emp.empno asc
结果:
“半连接”返回匹配 EXISTS 子查询,而不用复制谓词左边的行,当右边的多个行满足子查询时。
如果子查询在 WHERE 子句的 OR 分支,那么“半连接”和“反连接”不能转换。
示例10:
SELECT *
FROM dept
WHERE EXISTS (SELECT *
FROM emp
WHERE dept.deptno = emp.deptno
AND emp.sal > 2000)
ORDER BY dept.dname
结果:
Oracle 11g R1 Language Reference http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/queries006.htm
MySQL 5.0 Reference Manual http://download.oracle.com/docs/cd/E17952_01/refman-5.0-en/index.html
Join (SQL) http://en.wikipedia.org/wiki/Join(SQL)