需要从多个数据表里取出数据,那么就属于多表查询,在FROM子句后面要设置多张数据表。
SELECT [DISTINCT] * | 列名称 [别名],列名称 [别名],... FROM 表名称[别名],表名称[别名] [WHERE 过滤条件(s)] [ORDER BY 字段 [ASC | DESC],字段 [ASC | DESC],...];
实例1、显示每个雇员的编号、姓名、职位、工资、部门名称、部门位置
SELECT e.empno,e.ename,e.job,e.sal,d.dame,d.loc FROM emp e, dept d WHERE e.deptno=d.deptno;
实例2、查询每个雇员的编号、姓名、职位、工资、工资等级、部门名称
SELECT e.empno,e.ename,e.job,e.sal,s.grade,d.dname FROM emp e,salgrade s,dept d WHERE e.sal BETWEEN losal AND hisal AND e.deptno=d.deptno;
在连接条件中使用等于号(=)运算符比较被连接列的列值,其查询结果中列出被连接表中的所有列,包括其中的重复列
实例1、查询部门编号为30的员工编号、姓名、部门名称SELECT e.empno, e.ename, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno and e.deptno = 30;2、非等值连接在连接条件使用除等于运算符以外的其它比较运算符比较被连接的列的列值。这些运算符包括>、>=、<=、<、!>、!<和<>
SELECT DISTINCT d.dname, d.loc FROM emp e, dept d WHERE e.deptno = d.deptno and e.sal >1500;
3、自然连接
在连接条件中使用等于(=)运算符比较被连接列的列值,但它使用选择列表指出查询结果集合中所包括的列,并删除连接表中的重复列。简言之,基于两个表的同名的一个或多个列
【注意】自然连接是根据两个表中同名的列而进行连接的,当列不同名时,自然连接将失去意义
实例1、查询所有员工的员工编号、员工姓名、部门编号、部门名称
Select e.empno, e.ename, e.deptno, d.dname From emp e NATURAL JOIN dept d;
用于检索一个表的所有记录和另一个表中的匹配行。
(+)号的作用:+号可以理解为补充的意思,加在那个表的列上就代表这个表的列为补充。加在右表的列上代表右表为补充,为左连接。加在左表的列上代表左表为补充,为右连接。注意:完全外连接中不能使用+号。(+)为Oracle特有。
创建两张实验表
CREATE TABLE t_A ( id number, name VARCHAR2(10) ); CREATE TABLE t_B ( id number, name VARCHAR2(10) ); INSERT INTO t_A VALUES(1,'A'); INSERT INTO t_A VALUES(2,'B'); INSERT INTO t_A VALUES(3,'C'); INSERT INTO t_A VALUES(4,'D'); INSERT INTO t_A VALUES(5,'E'); INSERT INTO t_B VALUES(1,'AA'); INSERT INTO t_B VALUES(1,'BB'); INSERT INTO t_B VALUES(2,'CC'); INSERT INTO t_B VALUES(1,'DD'); INSERT INTO t_B VALUES(7,'GG');
1、左外连接
左外连接就是在结果中除了满足连接条件之外的行,还包括LEFT OUTER JOIN左侧表的所有行。
代码实现
SELECT * FROM t_a a,t_b b WHERE a.id=b.id(+);
2、右外连接
与左外连接同理,无限满足右表,即根据右表中数据去左表搜索,如果没有匹配数据,填入null
代码实现
SELECT * FROM t_a a,t_b b WHERE a.id(+)=b.id;
3、全连接
左右表都不加限制。即右外连接的结果为:左右表匹配的数据+左表没有匹配到的数据+右表没有匹配到的数据
代码实现
SELECT * FROM t_a a FULL JOIN t_b b on a.id=b.id;4、关于内外连接图解
交叉连接不带WHERE子句,它返回被连接的两个表所有数据行的笛卡尔积,返回结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。
实例1、求emp表和dept表的笛卡尔积
SELECT * FROM emp, dept;
自连接(self join)是SQL语句中经常要用的连接方式,使用自连接可以将自身表的一个镜像当作另一个表来对待,从而能够得到一些特殊的数据。
实例1、显示所有员工的上级领导的姓名
SELECT worker.ename, boss.ename FROM emp worker, emp boss WHERE worker.mgr = boss.empno;
SELECT [DISTINCT] 分组字段 [别名],... | 统计函数 FROM 表名称[别名] [WHERE 过滤条件(s)] [ORDER BY 字段 [ASC|DESC]];
实例1、查询所有雇员之中最高和最低工资
SELECT MAX(sal),MIN(sal) FROM emp;
实例2、统计出所有雇员的总工资以及平均工资
SELECT SUM(sal),AVG(sal) FROM emp;
SELECT [DISTINCT] 分组字段 [别名],... | 统计函数 FROM 表名称[别名] [WHERE 过滤条件(s)] [GROUP BY 分组字段,分组字段,分组字段,...] [ORDER BY 字段 [ASC|DESC]];
2.4.2 实例
实例1、按照职位分组,统计出每个职位的名称、人数、平均工资
SELECT job,COUNT(*),AVG(sal) FROM emp GROUP BY job;
实例2、查询每个部门的名称、人数、平均工资
SELECT d.dname,COUNT(e.empno),AVG(e.sal) FROM emp e,dept d WHERE e.deptno(+)=d.deptno GROUP BY d.dname;
实例3、查询出平均工资高于2000的职位名称以及平均工资。
SELECT job,AVG(sal) FROM emp GROUP BY job HAVING AVG(sal)>2000;
WHERE发生在GROUP BY操作之前,属于分组前的数据筛选,即:从所有的数据之中筛选出可以分组的数据,WHERE子句不允许使用统计函数;
HAVING发生在GROUP BY操作之后,是针对于分组后的数据进行筛选,HAVING子句可以使用统计函数;
SELECT [DISTINCT] * | 列名称 [别名],列名称 [别名],... FROM 表名称[别名] [WHERE 过滤条件(SELECT [DISTINCT] * | 列名称 [别名],列名称 [别名],... FROM 表名称[别名] [WHERE 过滤条件(s)] )]
SELECT * FROM emp WHERE deptno = (SELECT deptno FROM emp WHERE ename = 'SMITH');
SELECT ename, job, sal, deptno FROM emp WHERE job IN(SELECT DISTINCT job FROM emp WHERE deptno = 10);
1、在多行子查询中使用all操作符
实例显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号
SELECT ename, sal, deptno FROM emp WHERE sal > ALL(SELECT sal FROM emp WHERE deptno = 30);方法二 使用聚合函数,(执行效率最高)
SELECT ename, sal, deptno FROM emp WHERE sal > (SELCT MAX(sal) FROM emp WHERE deptno = 30);
2、在多行子查询中使用any操作符
实例显示工资比部门30的任意一个员工的工资高的员工姓名、工资和部门号
SELECT ename, sal, deptno FROM emp WHERE sal > ANY (SELECT sal FROM emp WHERE deptno = 30);方法二使用聚合函数,(执行效率最高)
SELECT ename, sal, deptno FROM emp WHERE sal > (SELECT MIN(sal) FROM emp WHERE deptno = 30);
SELECT * FROM emp WHERE(deptno, job) =(SELECT deptno, job FROM emp WHERE ename='SMITH');
SELECT e.ename, e.sal, e.deptno,temp.avgsal FROM emp e, (SELECT deptno, AVG(sal) avgsal FROM emp GROUP BY deptno) temp WHERE e.deptno = temp.deptno AND e.sal >temp.avgsal;
SELECT ename, sal, job FROM emp WHERE sal >2500 UNION SELECT ename, sal, job ROM emp WHERE job = 'MANAGER';实例2、 查询工资在2500以上且工作是经理的员工的姓名、工资、工作
SELECT ename, sal, job FROM emp WHERE sal >2500 INTERSECT SELECT ename, sal, job ROM emp WHERE job = 'MANAGER';实例3、 查询工资在2500以上且工作不是经理的员工的姓名、工资、工作
SELECT ename, sal, job FROM emp WHERE sal >2500 MINUS SELECT ename, sal, job ROM emp WHERE job = 'MANAGER';
伪列就像Oracle中的一个表列,但实际上它并未存储在表中。伪列可以从表中查询,但是不能插入、更新或删除它们的值。
常用的伪列:rowid和rownum。
ROWID是一种数据类型,它使用基于64为编码的18个字符来唯一标识一条记录物理位置的一个ID,类似于Java中一个对象的哈希码,都是为了唯一标识对应对象的物理位置,需要注意的是ROWID虽然可以在表中进行查询,但是其值并未存储在表中,所以不支持增删改操作
实例一、 观察rowid 和 rownum
SELECT ROWNUM,ROWID,empno,ename,job FROM emp WHERE ROWNUM <= 5;
数据对象编号 |
文件编号 |
块编号 |
行编号 |
OOOOOO |
FFF |
BBBBBB |
RRR |
可以用ROWID用来唯一标识表中数据(物理地址唯一)
应用 可以用来删除表中重复数据
DELETE FROM 表名 WHERE ROWID NOT IN( SELECT MIN(ROWID) FROM表名GROUP BY DEPTNO);
在查询的结果集中,ROWNUM为结果集中每一行标识一个行号,第一行返回1,第二行返回2,以此类推。通过ROWNUM伪列可以限制查询结果集中返回的行数。
ROWNUM与ROWID不同,ROWID是插入记录时生成,ROWNUM是查询数据时生成。ROWID标识的是行的物理地址。ROWNUM标识的是查询结果中的行的次序。
实例1、 查询前5名员工的姓名,工作,工资
SELECT ROWNUM rn,ename, job, sal FROM emp WHERE rn<=5;
实例2、查询5~10号员工的姓名,工作,工资
SELECT * FROM (SELECT ROWNUM rn, ename,job, sal FROM emp) WHERE rn > 5 AND rn <= 10;