Oracle 11g R1(11.1) Joins表连接

本文内容

  • 概述
  • 本文使用的表和其数据
  • Oracle 11g R1 表连接
  •     连接条件
  •     等值连接(Equijoin)
  •     自连接(Self Join)
  •     笛卡尔积(Cartesian Products)
  •     内连接(Inner Join)
  •     外连接(Outer Join)
  •     反连接(Antijoins)
  •     半连接(Semijoins)
  • 参考资料
  • 修改记录

 

概述

Oracle 8i 之前的表连接:

  • 等值连接(Equijoin)。
  • 自连接(Self Join)。
  • 外连接(Outer Join)。包括左外连接和右外连接。

Oracle 9 之后的表连接:

  • 等值连接(Equijoin)。
  • 自连接(Self Join)。
  • 内连接(Inner Join)和交叉连接(Cross Join)。
  • 外连接(Outer Join)。包括左外连接、右外连接和全外连接,以及对它们进行分区。
  • 自然连接(Natural Join)。
  • 还可以使用  USING 关键字和 ON 关键字建立连接。

 

本文使用的表和其数据

  • 部门表 DEPT

1

  • 员工表 EMP

2011-10-17_132258

注意:

  • 员工表中没有部门为 "40" 的员工。
  • 员工编号 "7839" 为职位最高的人,它没有上级。
  • 员工编号为 "7654"、"7876"、"7934" 没有所属的部门。

 

Oracle 11g R1 表连接(Joins)

“连接(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 开发人员指南

 

等值连接(Equijoins)

“等值连接”是在连接条件中包含 "=" 操作符的连接。“等值连接”合并具有相等值的、指定列的行。

根据内部算法,优化器选择执行的连接,一个单表等值连接的列的总大小被限制在一个数据块内,以减少开销。数据块的大小是由初始化参数 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

结果:

1

说明:

  • 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

结果:

1

 

自连接(Self Joins)

“自连接”是一个表连接自己的连接。这个表在 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

结果:

1

 

上边的连接只返回满足连接条件的数据行,但是有时还需要返回表中不满足连接条件的那些行。此时,就需要“外连接”。

笛卡尔积(Cartesian Products)

若连接两个表时,没有连接条件,则 Oracle 会返回它们的笛卡尔积。把一个表的每行与另一个表的每行合并(积)。笛卡尔积会产生很多行,很少使用。如两个 100 行的表的笛卡尔积有 100×100=10,000 行。除非你需要笛卡尔积,否则最好有连接条件。如果一个查询要连接三个或更多的表,并且,你没有规定连接条件,那么优化器会选择一个连接顺序,以避免产生中间结果的笛卡尔积。

示例4:演示笛卡儿积。

select * from emp cross join dept order by emp.empno asc

执行结果:

笛卡儿积

 

内连接(Inner Joins)

“内连接”,有时也称为“简单连接”是一个连接两个或多个表,只返回满足连接条件的那些数据行。

示例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

结果:

1

说明:

  • 相当于“等值连接”。

 

外连接(Outer Joins)

“外连接”扩展“简单连接(内连接)”。“外连接”,除了返回所有满足条件的行,也返回那些满足一个表的行,而不满足其他表的连接条件的行。

  • 执行表 A 和 B 的外连接(左外连接),返回所有表 A 和 B 中满足连接条件的行,以及表 A 中不满足连接条件的行。
  • 执行表 A 和 B 的右连接(右外连接),返回所有表 A 和 B 中满足连接条件的行,以及表 B 中不满足连接条件的行。
  • 执行表 A 和 B 的全外连接,返回表 A 和 B 中满足连接条件的行,和表 A 中不满足连接条件的行,以及表 B 中不满足连接条件的行。

无论指定什么形式,都不能在 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

结果:

1

说明:

  1. 在 FROM 子句使用 LEFT [ OUTER ] JOIN 语法,或在 WHERE 子句的连接条件中,对表 B 的所有列,应用外连接运算符(+ )。
  2. 在 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

结果:

1

说明:

  1. 在 FROM 子句使用 RIGHT [ OUTER ] JOIN 语法,或在 WHERE 子句的连接条件中,对表 A 的所有列,应用外连接运算符(+ )。
  2. 在 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

说明:

  1. 1,在 FROM 子句应用 FULL [OUTER] JOIN 语法。
  2. 2,全外连接是左外连接和右外连接的扩展,对于不满足连接条件的行,返回 null。如图,第 5、11、14、15 行。

 

参考:

Oracle 推荐使用 FROM 子句 OUTER JOIN 语法,而不是连接运算符(+)。使用连接运算符(+)进行外连接查询会遵循以下规则和限制,FROM 子句的 OUTER JOIN 语法则不会:

  • 不能在查询块里,既指定连接运算符(+),又包含 FROM 子句的连接语法。
  • 连接运算符(+)只能出现在 WHERE 子句,或在 FROM 子句左相关(当规定 TABLE 子句)的环境下,并且只能应用于表或视图的某列。
  • 如果 A 和 B 通过多个连接条件进行外连接,那么,你必须在连接条件中使用连接运算符(+),否则,Oracle 数据库将只返回简单连接的结果,不会显示警告或是错误信息提示,你没有得到一个外连接的结果。
  • 如果你在外连接查询中规定一个表,而在内部查询是另一个表,那么连接运算符(+)不会产生一个外连接结果。
  • 不能使用连接运算符(+)外连接一个表跟他自己,虽然自连接是有效的。例如,下面语句是无效的:
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 条件不能与其他使用 OR 逻辑运算符的条件一起使用。
  • 一个 WHERE 条件不能使用 IN 比较条件,来用表达式与由连接运算符(+)标记的列进行比较。

如果 WHERE 子句中包含表 B 的列与一个常量进行比较的条件,那么连接运算符(+)必须要应用于这个列,以便 Oracle 返回表 A 的行,这些行,对于该列,会产生null。否则,Oracle 只返回一个简单连接的结果。

在执行多个表的外连接查询时,一个单一的表对于其他表可以生成一个空表。因此,你可以在连接 A 和 B 的连接条件上,,并且,B 和 C 的连接条件上,对 B 的列不使用连接运算符(+)。请参阅 SELECT 外部连接语法。

 

反连接(Antijoins)

“反连接”返回谓词(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

结果:

1

 

半连接(Semijoins)

“半连接”返回匹配 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

结果:

1

 

参考资料

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)

 

修改记录

  • 第一次 2012-3-26 [UPDATE][ADD]
posted @ 2011-10-23 17:20  船长&CAP  阅读(1013)  评论(0编辑  收藏  举报
免费流量统计软件