多表连接使用

相等连接

例7-1

SQL> SELECT empno,ename,sal,emp.deptno, loc

2 FROM emp, dept

3 WHERE emp.deptno = dept.deptno

4 ORDER BY loc;

例7-1为相等连接,即当两个表中的记录的deptno值完全相等时才进行连接。通常这种连接查询涉及到主键和外键。相等连接也叫简单连接或内连接。以下是使用连接的一些指南,这些指南不但适合于相等连接而且也适合于其他类型的连接。

■ 要连接的表都要放在FROM子句中,表名用逗号分开(如FROM emp,dept)。

■ 连接的条件放在WHERE子句中(如WHERE emp.deptno=dept.deptno)。

■ 要进行n个表的连接需要至少n-1个连接条件。

■ 如果多个表中有相同列名的列时,在这些列的前面要冠以表名来区别它们,表名

和列名之间用逗号隔开。

在列前冠以表名可以改善系统的效率,因为表名告诉Oracle服务器到哪一个表中找哪些列。

例7-2

SQL> SELECT emp.empno,emp.ename,emp.sal,

2        emp.deptno,dept.loc

3 FROM emp, dept

4 WHERE emp.deptno = dept.deptno

5 AND sal >= 1500

6 ORDER BY loc;

连接中表别名的使用

从例7-2还可以看出:如果一个表的名字很长(例如INVOICE-DETAILS),在列前冠以表名需要大量的输入。Oracle 提供了一种简便的方法,就是使用表的别名。您可以使用表的别名将例7-2查询语句修改成例7-3的查询语句。

例7-3

SQL> SELECT e.empno,e.ename,e.sal,e.deptno,d.loc

2 FROM emp e, dept d

3 WHERE e.deptno = d.deptno

4 AND e.sal >= 1500

5 ORDER BY d.loc;

以下是使用表的别名的一些指南:

表的别名在FROM子句中定义,别名放在表名之后,它们之间用空格隔开。.

别名一经定义,在整个的查询语句中就只能使用表的别名而不能再使用表名。表的别名只在所定义的查询语句中有效。

应该选择有意义的别名,表的别名最长为30个字符,但越短越好。

笛卡尔乘积(乘积连接)

如果您在例7-3的查询语句中忘记了WHERE子句,那么会得到什么样的结果呢?请看例7-4的查询语句。

例7-4

SQL> SELECT e.empno,e.ename,e.sal,e.deptno,d.loc

2 FROM emp e, dept d

3 ORDER BY d.loc;

例7-5和例7-6的结果显示emp有14条记录,dept有4条记录,因此例7-4显示的结果为14×4=56行的记录。笛卡尔乘积(乘积连接)的结果包括了所有表中的所有行的组合。

也许读者并不觉得例7-4 的查询语句会有太大的问题。但是在一个大型公司的数据库中的一些表可能非常大,如果求一个有一百万行数据的表和另一个有一万行数据的表的笛卡尔乘积,其结果就为:1,000.000×10.000=10,000.000行。这样的查询会对系统的效率产生极大的冲击,但查询的结果却几乎没什么用处。以下是笛卡尔乘积(乘积连接)形成的条件:

查询语句中漏掉了连接条件(join condition);

查询语句中两个表中的所有行都满足连接条件(join condition);查询语句中的连接条件无效。

在实际工作中要尽可能地避免产生笛卡尔乘积(乘积连接)。要达到这一目标,在多表连接查询语句的WHERE子句中,必须永远使用有效而正确的连接条件。

自连接(Self join)

例7-7

SQL> SELECT w,empno,w,ename,w.job,w.mgr,m.ename "M_Name",m.job "M_Job"

2 FROM emp w,emp m

3 WHERE w.mgr = m.empno

4 AND w.job LIKE 'ANA%';

Oracle 是通过把一个表定义了两个不同的别名的方法(即把一个表映射成两个表)来完成自连接(Self join)的。实际上我们可以不使用自连接(Self join),而通过例7-8和例7-9这两个简单的查询来得到与例7-7完全相同的结果。

例7-11

SQL> SELECT w.empno,w.ename,w.job,w.mgr,m.ename "M_Name",m.job "M_Job"

2 FROM emp w,manager m

3 WHERE w.mgr = m.empno

4 AND w.job LIKE 'ANA%';

尽管例7-11的查询结果与例7-7自连接(Selfjoin)的查询结果完全一样,但这样做需要多创建一个表manager,而表 manager 的内容全部来自表 emp。也就是说,表 emp 中任何记录的修改都有可能引起表manager中相应记录的修改。因此这样的系统是很难维护的

例7-12

SQL> SELECT w.empno "W_Number",w.ename"W_Name",w,job "W_Job",w.sal "W_Salary"

2        ,m.empno "M_Number",m.ename "M_Name",d.loc "Location"

3 FROM emp w,manager m,dept d

4 WHERE w.mgr = m.empno

5 AND m.deptno = d.deptno

6 AND w.job IN('CLERK','ANALYST')

7 ORDER BY w.job,w.sal;

例7-12查询的思路是这样的:

■ 在员工表(emp)中找到员工经理号w.mgr。

■ 利用员工经理号w.mgr在经理表(manager)中找到经理的信息。

■ 再利用经理的部门号(deptno)在部门表(dept)找到经理所在部门的信息。

把员工的职位(job)不是文员(CLERK)或分析员(ANALYST)的员工排斥在查询结果以外。

把查询结果按员工的职位(job)和工资(sal)由小到大排序并显示。

不等连接

例7-15

SQL> SELECT e.empno,e.ename,e.job,e.sal,s.grade

2 FROM emp e,salgrade s

3 WHERE e.sal BETWEEN s.losal AND s.hisal

4 AND s.grade>2;

外连接

例7-17

SQL> SELECT empno, ename, sal, emp.deptno, dept.deptno, loc

2 FROM emp, dept

3 WHERE emp.deptno(+)= dept.deptno;

外连接的连接运算符为(+)。该连接运算符既可以放在等号的左面也可以放在等号的右面。但一定要放在缺少相应信息的那一面。如放在 emp.deptno 所在的一方。我们可以把例7-17的查询语句改写成例7-18的查询语句。

例7-18

SQL> SELECT empno, ename, sal, emp.deptno, dept.deptno, loc

2 FROM emp, dept

3 WHERE dept.deptno = emp.deptno(+);

SQL:1999语法的连接

Oracle9i 对多表连接的语法进行了扩充,它开始支持美国国家标准化组织(ANSI)的SQL 标准"SQL:1999"的语法。不过SQL:1999语法连接语句并没有提供效率方面的好处。

SQL:1999语法的自然连接

例7-19的查询语句是使用SQL:1999语法的一个自然连接的例子。例7-19

SQL> SELECT e.empno,e.ename,e.sal,e.deptno,d.loc

2 FROM emp e

3 CROSS JOIN dept d

4 ORDER BY d.loc;

例7-19也是一个笛卡尔乘积(乘积连接),它所产生的结果与例7-4的完全相同。在例7-19中阴影部分为SQL:1999语法所使用的关键字。本章以下各节还将沿用这一约定。

使用USING子句的连接

例7-20的查询语句是一个使用USING子句的连接。例7-20

SQL> SELECT e.empno,e.ename,e.sal,deptno,d.loc

2 FROM emp e

3 JOIN dept d

4 USING (deptno)

5 ORDER BY d.loc;

例7-20所显示的结果与例7-1的相等连接的结果完全相同。在使用USING子句的连接时要注意以下的约定。

NATURAL JOIN 子句和USING子句是互斥的,即两个子句只能使用一个。在所引用的列中不能使用表名或列名(如例7-20中的deptno)。

当有多列匹配时,使用USING子句只匹配其中的一列。

使用ON子句的连接

例7-21的查询语句是一个使用ON子句的连接。例7-21

SQL> SELECT e.empno,e.ename,e.sal,e.deptno,d.loc

2 FROM emp e

3 JOIN dept d

4 ON (e.deptno = d.deptno)

5 ORDER BY d.loc;

例7-21所显示的结果与例7-1的相等连接的结果完全相同。在使用ON子句的连接时要注意以下的约定。

在所引用的列中要使用表名或列名(如例7-21中的e.deptno和d.deptno)相等连接条件放在ON子句中。

使用ON子句的多表连接和附加条件

例7-22

SQL> SELECT w.empno "W_Number",w.ename"W_Name",w.job "W_Job",w.sal "W_Salary"

2        ,m.empno "M_Number",m.ename "M_Name",d.loc "Location"

3 FROM emp w

4 JOIN manager m

5 ON w.mgr = m.empno

6 JOIN dept d

7 ON m.deptno = d.deptno

8 WHERE w.job IN('CLERK','ANALYST')

9 ORDER BY w.job,w.sal;

例7-22的查询语句是用SQL:1999语法的一个多表连接,它所显示的结果与例7-12 的相等连接的结果完全相同。

例7-22的查询中包含了一个附加条件,其附加条件放在WHERE子句中。我们还可以直接在查询语句中用AND加入附加条件,如例7-23的查询语句。

例7-23

SQL>SELECT w.empno "W_Number",w.ename"W_Name",w.job "w_Job"w.sal "W_Salary"

2        ,m.empno "M_Number",m.ename "M_Name",d.loc "Location"

3 FROM emp w

4 JOIN manager m

5 ON w.mgr = m.empno

6 JOIN dept d

7 ON m.deptno = d.deptno

8 AND w.job IN('CLERK','ANALYST')

9 ORDER BY w.job,w.sal;

显然,例7-23显示的结果与例7-22的完全一样,查询语句中只要把例7-22的关键字WHERE换成了AND就行了。

以上我们讨论的连接是属于内连接。下面我们将讨论外连接。

左外连接

例7-24的查询语句是一个左外连接的例子。

例7-24

SQL> SELECT empno, ename, sal, emp.deptno, dept.deptno, loc

2 FROM dept

3 LEFT OUTER JOIN emp

4 ON(emp.deptno = dept.deptno);

例7-24所显示的结果与例7-17的外连接的结果完全相同,只不过它使用的是SQL:1999语法而已。

7.23 右外连接

例7-25的查询语句是一个右外连接的例子。例7-25

SQL> SELECT e.empno,e.ename,e.sal,e.deptno,d.deptno,d.loc

2 FROM emp e

3 RIGHT OUTER JOIN dept d

4 ON (e.deptno = d.deptno);

很显然,例7-25的结果与例7-17的结果也是完全相同的,只是写法不同而已。实际上例7-25相当于例7-26的查询语句。

例7-26

SQL> SELECT e.empno,e.ename,e.sal,e.deptno,d.deptno,d.loc

2 FROM emp e, dept d

3 WHERE d.deptno = e.deptno(+);

例7-29的查询语句是使用表manager和表dept的一个左外连接的例子。例7-29

SQL> SELECT empno, ename, sal, manager.deptno, dept.deptno, loc

2 FROM manager 3 LEFT OUTER JOIN dept

4 ON (manager.deptno = dept.deptno);

例7-31的查询语句是使用表manager和表dept的一个右外连接的例子。例7-31

SQL> SELECT empno, ename, sal, manager,deptno, depc.deptno, loc

2 FROM manager

3 RIGHT OUTER JOIN dept

4 ON (manager.deptno = dept.deptno);

例7-33的查询语句是使用表manager和表dept的一个全外连接的例子。例7-33

SQL> SELECT empno, ename, sal, manager.deptno, dept.deptno, loc

2 FROM manager

3 FULL OUTER JOIN dept

4 ON (manager.deptno = dept.deptno);

你可能感兴趣的:(sql,sql,数据库,mysql)