SQL Fundamentals || 多表查询(内连接,外连接(LEFT|RIGHT|FULL OUTER JOIN),自身关联,ON,USING,集合运算UNION)

SQL Fundamentals || Oracle SQL语言

一、多表查询基本语法

  • 在进行多表连接查询的时候,由于数据库内部的处理机制,会产生一些“无用”的数据,而这些数据就称为笛卡尔积.
  • 多表查询时可以利用等值关联字段消除笛卡尔积
  • 多表查询之中,每当增加一个关联表都需要设置消除笛卡尔积的条件
  • 分析过程很重要:
    • 确定所需要的数据表
    • 确定已知的关联字段:
    • 按照SQL语句的执行步骤编写:FROM,WHERE,SELECT,ORDER BY

(由于SELECT是在WHERE子句之后执行,所以SELECT子句所定义的别名WHERE不可以直接使用)

(由于SELECT是在ORDER BY子句之前执行,所以SELECT子句所定义的别名ORDER BY可以直接使用)

二、表的连接操作

  • 内连接、等值连接、连接、普通连接、自然连接
  • 外连接(左外连接,右外连接),外连接可以通过“(+)”符号进行控制。

三、自身关联

自身关联属于一张表自己关联自己的情况,此时依然会产生笛卡尔积

四:SQL:1999语法

交叉连接的:交叉连接会产生笛卡尔积;

自然连接:自然连接可以自动匹配关联字段消除笛卡尔积;

ON子句

USING子句

全外连接:如果要实现全外连接只能够依靠SQL:1999语法。LEFT|RIGHT|FULL OUTER JOIN

五、数据的集合运算

数据的集合操作:UNION、UNION ALL、INTERSECT、MINUS

集合操作时,各个查询语句返回的结构要求一致

开发之中建议使用UNION来代替OR操作

一、多表查询基本语法

1、多表查询的语法:

多表查询就是在一条查询语句中,从多张表里一起取出所需要的数据,如果要想进行多表查询,直接在FROM子句之后跟上多个表即可,此时的语法如下:

SELECT [DISTINCT] * | 列名称 [AS] [列别名] , 列名称 [AS] [列别名] ,...

FROM 表名称1 [表别名1] , 表名称2 [表别名2] ….

[WHERE 条件(s) ]

[ORDER BY 排序的字段1 ASC|DESC ,排序的字段2 ASC | DESC ..];

2、笛卡尔积:

在进行多表连接查询的时候,由于数据库内部的处理机制,会产生一些“无用”的数据,而这些数据就称为笛卡尔积。

通过之前的查询可以发现,笛卡尔积返回的56条查询结果正好是 14 * 4(emp表数据量 * dept表数据量)的运算结果,即,同一条数据重复显示了N次。

  • 查询emp表中的数据量 —— 14条数据

SELECT COUNT(*) FROM emp ;

  • 查询dept表中的数据量 —— 4条数据

SELECT COUNT(*) FROM dept ;

  • 现在查询所有的雇员和部门的全部详细信息

SELECT * FROM emp,dept ;

3、消除笛卡尔积:

多表查询会产生笛卡尔积,所以性能较差;

多表查询时可以利用等值关联字段消除笛卡尔积。

SELECT * FROM emp,dept WHERE emp.deptno=dept.deptno ;

SELECT * FROM emp e , dept d WHERE e.deptno=d.deptno;

4、举例:查询每个雇员的编号、姓名、职位、基本工资、部门名称、部门位置信息

分析过程:

  • 确定所需要的数据表
    • emp表
    • dept表
  • 确定已知的关联字段:
    • 部门和雇员的关联:emp.deptno=dept.depno
  • 按照SQL语句的执行步骤编写:FROM,WHERE,SELECT

SELECT emp.empno,emp.ename,emp.job,emp.sal,dept.dname,dept.loc

FROM emp,dept

WHERE emp.deptno=dept.deptno ;

5、给表设置别名,查询雇员的编号、姓名、职位、基本工资、部门名称、部门位置

SELECT e.empno,e.ename,e.job,e.sal,d.dname,d.loc

FROM emp e,dept d

WHERE e.deptno=d.deptno ;

6、BETWEEN AND查询出每个雇员的编号、姓名、雇佣日期、基本工资、工资等级

SELECT e.empno,e.ename,e.hiredate,e.sal,s.grade

FROM emp e,salgrade s

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

7、DECODE为了更加清楚的显示出工资等级的信息,现在希望可以按如下格式进行替换显示:

  • grade=1:显示为“E等工资”
  • grade=2:显示为“D等工资”
  • grade=3:显示为“C等工资”
  • grade=4:显示为“B等工资”
  • grade=5:显示为“A等工资”

SELECT e.empno,e.ename,e.hiredate,e.sal,

DECODE(s.grade,1,'E等工资',2,'D等工资',3,'C等工资',4,'B等工资',5,'A等工资') grade

FROM emp e,salgrade s

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

8、查询出每个雇员的姓名、职位、基本工资、部门名称、工资所在公司的工资等级;

SELECT e.ename,e.job,e.sal,d.dname,s.grade ,

DECODE(s.grade,1,'E等工资',2,'D等工资',3,'C等工资',4,'B等工资',5,'A等工资') grade

FROM emp e,dept d,salgrade s

WHERE e.deptno=d.deptno AND e.sal BETWEEN s.losal AND s.hisal ;

二、表的连接操作

对于数据表的连接操作在数据库之中一共定义了两种:

内连接

等值连接

连接

普通连接

自然连接

是最早的一种连接方式,

内连接是从结果表中删除与其他被连接表中没有匹配行的所有元组,所以当匹配条件不满足时内连接可能会丢失信息。

在之前所使用的连接方式都属于内连接,而在WHERE子句之中设置的消除笛卡尔积的条件就采用了等值判断的方式进行的;

举例:现在将emp和dept表联合查询,使用内连接(等值连接)

SELECT *

FROM emp e,dept d

WHERE e.deptno=d.deptno ;

外连接

内连接中只能够显示等值满足的条件,如果不满足的条件则无法显示,

如果现在希望特定表中的数据可以全部显示,就利用外连接,

外连接分为三种:

左外连接(简称:左连接)

右外连接(简称:右连接)

全外连接(简称:全连接)

在Oracle中可以利用其提供的“(+)”进行左外连接或右外连接的实现,使用如下:

  • 左关系属性=右关系属性(+):“(+)”放在了等号的右边,所以此时表示的是左连接;
  • 左关系属性(+)=右关系属性:“(+)”放在了等号的左边,所以此时表示的是右连接;

使用左外连接,

SELECT *

FROM emp e,dept d

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

增加右外连接,显示部门40的信息

SELECT *

FROM emp e,dept d

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

三、自身关联

1、举例:

查询出每个雇员的编号、姓名及其上级领导的编号、姓名,

只需要用到一个emp表中的两个字段,将emp表分别别名为e和m

SQL> SELECT ename,empno,mgr FROM emp;

ENAME           EMPNO        MGR

---------- ---------- ----------

SMITH            7369       7902

FORD             7902       7566

SQL> SELECT e.empno eno, e.ename ename,m.empno mno,m.ename mname

2 FROM emp e,emp m

3 WHERE e.mgr=m.empno;

ENO ENAME             MNO MNAME

7369 SMITH            7902 FORD

SELECT e.empno eno ,e.ename ename,m.empno mno,m.ename mname

FROM emp e,emp m

WHERE e.mgr=m.empno(+) ;

2、举例:

查询出在1981年雇佣的全部雇员的编号、姓名、雇佣日期(按照年-月-日显示)、工作、领导姓名、雇员月工资、雇员年工资(基本工资+奖金),雇员工资等级、部门编号、部门名称、部门位置,并且要求这些雇员的月基本工资在1500~3500之间,将最后的结果按照年工资的降序排列,如果年工资相等,则按照工作进行排序

步骤一:查询emp表中的信息(全部雇员的编号、姓名、雇佣日期(按照年-月-日显示),月基本工资在1500~3500之间)

SELECT e.empno,e.ename,e.hiredate,e.sal,(e.sal+NVL(e.comm,0))*12 income

FROM emp e

WHERE   TO_CHAR(e.hiredate,'yyyy')='1981' AND e.sal BETWEEN 1500 AND 3500

步骤二:emp表使用自身关联,加入领导的信息,使用别名设置emp表的别名为m,使用关联条件e.mgr=m.empno(+) 消除笛卡尔积

SELECT e.empno,e.ename,e.hiredate,e.sal,(e.sal+NVL(e.comm,0))*12 income , m.ename mname

FROM emp e ,em m

WHERE   TO_CHAR(e.hiredate,'yyyy')='1981' AND e.sal BETWEEN 1500 AND 3500

AND e.mgr=m.empno(+)

步骤三:dept表加入部门信息,使用外连接 e.mgr=m.empno(+),使用关联条件 e.deptno=d.deptno 消除笛卡尔积

SELECT e.empno,e.ename,e.hiredate,e.sal,(e.sal+NVL(e.comm,0))*12 income , m.ename mname ,d.deptno,d.dname,d.loc

FROM emp e ,em m , dept d

WHERE   TO_CHAR(e.hiredate,'yyyy')='1981' AND e.sal BETWEEN 1500 AND 3500

AND e.mgr=m.empno(+)

AND e.deptno=d.deptno

步骤四:salgrade表查询工资等级,使用关联条件 e.sal BETWEEN s.losal AND s.hisal 消除笛卡尔积

SELECT e.empno,e.ename,e.hiredate,e.sal,(e.sal+NVL(e.comm,0))*12 income , m.ename mname ,

d.deptno,d.dname,d.loc ,

s.grade, DECODE(s.grade,1,'E等工资',2,'D等工资',3,'C等工资',4,'B等工资',5,'A等工资') 工资等级

FROM emp e , emp m , dept d , salgrade s

WHERE   TO_CHAR(e.hiredate,'yyyy')='1981' AND e.sal BETWEEN 1500 AND 3500

AND e.mgr=m.empno(+)

AND e.deptno=d.deptno

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

步骤五:进行排序,

由于SELECT是在ORDER BY子句之前执行,所以SELECT子句所定义的别名ORDER BY可以直接使用

SELECT e.empno,e.ename,e.hiredate,e.sal,(e.sal+NVL(e.comm,0))*12 income , m.ename mname ,

d.deptno,d.dname,d.loc ,

s.grade, DECODE(s.grade,1,'E等工资',2,'D等工资',3,'C等工资',4,'B等工资',5,'A等工资') 工资等级

FROM emp e , emp m , dept d , salgrade s

WHERE   TO_CHAR(e.hiredate,'yyyy')='1981' AND e.sal BETWEEN 1500 AND 3500

AND e.mgr=m.empno(+)

AND e.deptno=d.deptno

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

ORDER BY income DESC , e.job ;

四:SQL:1999语法

SQL:1999语法

SELECT [DISTINCT] * | 列名称 [AS] [列别名] , 列名称 [AS] [列别名] ,...

FROM 表1 表别名1 [CROSS JOIN 表2 表别名2]|

[NATURAL JOIN 表2 表别名2]|

[JOIN 表2 USING(关联列名称)]|

[JOIN 表2 ON(关联条件)]|

[LEFT|RIGHT|FULL OUTER JOIN 表2 ON(关联条件)]

[WHERE 条件(s)]

[ORDER BY 排序的字段1 ASC|DESC ,排序的字段2 ASC | DESC ..];

交叉连接(CROSS JOIN)

作用于两个关系上,并且第一个关系的每个元组与第二个关系的所有元组进行连接,这样的操作形式与笛卡尔积是完全相同的,

交叉连接的语法:

SELECT [DISTINCT] * | 列名称 [AS] [列别名] , 列名称 [AS] [列别名] ,...

]|

[WHERE 条件(s)]

[ORDER BY 排序的字段1 ASC|DESC ,排序的字段2 ASC | DESC ..];

使用交叉连接(CROSS JOIN),产生笛卡尔积

SELECT * FROM emp CROSS JOIN dept ;

使用自然连接(NATION JOIN)

自然连接(NATURAL JOIN)运算作用于两个关系,最终会通过两个关系产生出一个关系作为结果。

与交叉连接(笛卡尔积)不同的是, 自然连接只考虑那些在两个关系模式中都出现的属性上取值相同的元组对。

自然连接的操作语法:

SELECT [DISTINCT] * | 列名称 [AS] [列别名] , 列名称 [AS] [列别名] ,...

[NATURAL JOIN 表2 表别名2]|

[WHERE 条件(s)]

[ORDER BY 排序的字段1 ASC|DESC ,排序的字段2 ASC | DESC ..];

SELECT * FROM emp NATURAL JOIN dept ;

USING字句

通过自然连接可以直接使用关联字段消除掉笛卡尔积,

如果现在的两张表中没有存在这种关联字段的话,就可以通过USING子句完成笛卡尔积的消除,

USING子句的语法如下所示:

SELECT [DISTINCT] * | 列名称 [AS] [列别名] , 列名称 [AS] [列别名] ,...

FROM 表1 表别名 [JOIN 表2 USING(关联列名称)]|

[WHERE 条件(s)]

[ORDER BY 排序的字段1 ASC|DESC ,排序的字段2 ASC | DESC ..];

USING子句,直接使用JOIN进行连接,同时指定关联的列

  • SELECT * FROM emp JOIN dept USING(deptno) ;

on字句

在之前编写等值连接时,采用了关联字段进行笛卡尔积的消除,那么用户在SQL:1999语法之中通过ON子句就可以由用户手工设置一个关联条件,ON子句语法:

SELECT [DISTINCT] * | 列名称 [AS] [列别名] , 列名称 [AS] [列别名] ,...

FROM 表1 表别名1 [JOIN 表2 ON(关联条件)]|

[WHERE 条件(s)]

[ORDER BY 排序的字段1 ASC|DESC ,排序的字段2 ASC | DESC ..];

ON子句,直接编写条件

  • SELECT * FROM emp e JOIN salgrade s

ON(e.sal BETWEEN s.losal AND s.hisal) ;

外连接

在数据的查询操作中数据的外连接一共分为三种形式:左外连接、右外连接、全外连接,而此时连接的语法如下:

SELECT [DISTINCT] * | 列名称 [AS] [列别名] , 列名称 [AS] [列别名] ,...

FROM 表1 表别名1 [LEFT|RIGHT|FULL OUTER JOIN 表2 ON(关联条件)]

[WHERE 条件(s)]

[ORDER BY 排序的字段1 ASC|DESC ,排序的字段2 ASC | DESC ..];

使用SQL:1999语法实现左外连接

  • SELECT *
  • FROM emp e LEFT OUTER JOIN dept d
  • ON (e.deptno=d.deptno) ;

使用SQL:1999语法实现右外连接

  • SELECT *
  • FROM emp e RIGHT OUTER JOIN dept d
  • ON (e.deptno=d.deptno) ;

使用SQL:1999语法实现全外连接

  • SELECT *

FROM emp e FULL OUTER JOIN dept d

ON (e.deptno=d.deptno) ;

五、数据的集合运算

数据的集合操作:UNION、UNION ALL、INTERSECT、MINUS

集合操作时,各个查询语句返回的结构要求一致

开发之中建议使用UNION来代替OR操作

SELECT * FROM emp WHERE job='SAL' OR job='CL';

SELECT * FROM emp WHERE job IN ('SAL' ,'CL');

SELECT * FROM emp WHERE job='SAL'

UNION

SELECT * FROM emp WHERE;OR job='CL';

集合运算是一种二目运算符,一共包括四种运算符:并、差、交、笛卡尔积

操作集合的语法如下所示:

查询语句

[UNION | UNION ALL | INTERSECT | MINUS]

查询语句

....

要实现集合的运算,主要使用四种运算符:

并操作是将多个查询的结果连接到一起,而对于并操作提供了两种操作符:UNION(不显示重复)、UNION ALL(显示重复)。

UNION(并集)

(不显示重复)

返回若干个查询结果的全部内容,但是重复元组不显示;

      • 将两个查询结果连接
        • 查询dept表的全部记录:SELECT * FROM dept ;
        • 查询10部门的详细记录:SELECT * FROM dept WHERE deptno=10 ;
      • UNION操作:
        • SELECT * FROM dept

UNION

SELECT * FROM dept WHERE deptno=10 ;

UNION ALL(并集)

(显示重复)

返回若干个查询结果的全部内容,重复元组也会显示;

      • UNION ALL操作:
        • SELECT * FROM dept

UNION ALL

SELECT * FROM dept WHERE deptno=10 ;

MINUS(差集):

返回若干个查询结果中的不同部分;

使用MINUS执行差集操作

  • SELECT * FROM dept

MINUS

SELECT * FROM dept WHERE deptno=10 ;

INTERSECT(交集):

返回若干个查询结果中的相同部分。

使用INTERSECT执行交集操作

  • SELECT * FROM dept

INTERSECT

SELECT * FROM dept WHERE deptno=10 ;

上一篇:Inversions


下一篇:SQL:多表查询