Oracle系列《二》:多表复杂查询和事务处理
多表查询应该注意去除笛卡尔积,一般多个表时会为表起个别名
【1】要求查询雇员的编号、姓名、部门编号、部门名称及部门位置
SQL> SELECT e.empno,e.ename,d.deptno,d.dname,d.loc FROM emp e,dept d
WHERE e.deptno = d.deptno;
【2】要求查询每个雇员的姓名、工作、雇员的直接上级领导的姓名(表自关联)
SQL> SELECT e.ename,e.job,m.ename FROM emp e,emp m
WHERE e.mgr = m.empno;
【3】对【2】进行扩充,将雇员所在部门名称同时列出
SQL> SELECT e.ename,e.job,m.ename,d.dname FROM emp e,emp m,dept d
WHERE e.mgr = m.empno AND e.deptno=d.deptno;
【4】查询每个雇员的姓名、工资、部门名称,工资在公司的等级(salgrade),及其领导的姓名所在公司的等级
<1>先确定工资等级表的内容
SQL> SELECT * FROM salgrade;
<2>查询每个雇员的姓名、工资、部门名称和工资在公司的等级
SQL> SELECT e.ename,e.sal,d.dname,s.grade FROM emp e,dept d,salgrade s
WHERE e.deptno=d.deptno AND e.sal BETWEEN s.losal AND s.hisal;
<3>查询其领导姓名及工资所在公司的等级
SQL> SELECT
e.ename,e.sal,d.dname,s.grade,m.ename,m.sal,ms.grade FROM emp e,dept d,salgrade s,emp m,salgrade ms
WHERE e.deptno = d.deptno
AND e.sal BETWEEN s.losal AND s.hisal
AND e.mgr = m.empno
AND m.sal BETWEEN ms.losal AND ms.hisal;
【5】左连接与右连接的概念,"+"在等号左边表示右连接,反之,左连接
查询雇员的编号、姓名及其领导的编号、姓名
SQL> SELECT e.empno,e.ename,m.empno,m.ename FROM emp e,emp m
WHERE e.mgr = m.empno(+); 就发现将KING的那条记录也连过来了
SQL1999语法中有如下几种连接(了解)
1、交叉连接CROSS JOIN,产生笛卡尔积
SQL> SELECT * FROM emp CROSS JOIN dept;
2、自然连接NATURAL JOIN,自动进行关联字段的匹配
SQL> SELECT * FROM emp NATURAL JOIN dept;
3、使用USING子句,直接关联操作列
SQL> SELECT * FROM emp JOIN dept USING(deptno) WHERE deptno=30;
4、使用ON子句,用户自己编写的条件
SQL> SELECT * FORM emp JOIN dept ON(emp.deptno = dept.deptno) WHERE deptno=30;
5、左连接(左外连接、LEFT (OUTER) JOIN)、右连接(右外连接、RIGHT (OUTER) JOIN)
组函数及分组统计
1、COUNT():求出全部记录数
2、MAX():求出一组中最大值
3、MIN():求出最小值
4、AVG():求出平均值
5、SUM():求和
【1】求出每个部门的雇员数量
SQL> SELECT deptno,count(empno) FROM emp
GROUP BY deptno;
【2】按部门分组,并显示部门的名称,及每个部门的员工数
SQL> SELECT d.dname,COUNT(e.empno) FROM emp e,dept d
WHERE e.deptno=d.deptno GROUP BY d.dname;
【3】要求显示平均工资大于2000的部门编号和平均工资
SQL> SELECT deptno,AVG(sal) FROM emp
WHERE AVG(sal)>2000 GROUP BY deptno;
出错,WHERE子句中不能出现分组函数的条件,要使用HAVING子句 上述语句应该改为如下
SQL> SELECT deptno,AVG(sal) FROM emp
GROUP BY deptno
HAVING AVG(sal)>2000
【4】显示非销售人员工作名称以及从事同一工作雇员的月工资总和,
并且要求从事同一工作的雇员月工资合计大于$5000, 输出结果按月工资的合计升序排序
<1>按工作分组,求出非销售人员的月工资总和
SQL> SELECT job,SUM(sal) FROM emp
WHERE job<>'SALESMAN' GROUP BY job;
<2>对分组条件进行限制,然后进行排序,HAVING子句不能使用别名
SQL> SELECT job,SUM(sal) totalSal FROM emp
WHERE job<>'SALESMAN' GROUP BY job
HAVING SUM(sal) > 5000 ORDER BY totalSal;
【5】分组函数可以嵌套使用,但是在SELECT列中就不能再出现该分组条件的列名了
SQL> SELECT deptno,MAX(AVG(sal)) FROM emp
GROUP BY deptno;
出错!修改如下
SQL> SELECT MAX(AVG(sal)) FROM emp
GROUP BY deptno;
【6】查询出比7654工资要高的全部雇员的信息
<1>首先要查询雇员编号7654的工资
SQL> SELECT sal FROM emp WHERE empno=7654;
<2>以上述条件的结果最后后续查询的依据
SQL> SELECT * FROM emp
WHERE sal>(SELECT sal FROM emp WHERE empno=7654);
子查询在操作中分为以下三类:
1、单列子查询:返回的结果是一列的内容
2、单行子查询:返回多个列,也可能是一条记录
3、多行子查询:返回多个记录
【1】要求查询工资比7654高,同时与7788从事相同工作的全部雇员
SQL> SELECT * FROM emp
WHERE sal>(SELECT sal FROM emp WHERE empno=7654)
AND job=(SELECT job FROM emp WHERE empno=7788);
【2】要求查询 部门名称、部门员工数、部门平均工资,部门的最低收入雇员的姓名
<1>查询部门员工数、部门平均工资
SQL> SELECT deptno,COUNT(empno),AVG(sal) FROM emp
GROUP BY deptno;
<2>查询部门的名称,及最低收入雇员姓名,要进行表关联(子查询)
SQL> SELECT d.dname,ed.c,ed.a,e.ename FROM dept d,(
SELECT deptno,COUNT(empno) c,AVG(sal) a,MIN(sal) min FROM emp
GROUP BY deptno) ed, emp e
WHERE d.deptno=ed.deptno AND e.sal = ed.min;
若上述存在两个最低工资的情况,则会出错,在子查询中存在以下3种查询的操作符号
IN:指定一个查询范围,例如查询每个部门的最低工资(返回值有多个)
SQL> SELECT * FROM emp
WHERE sal IN (SELECT MIN(sal) FROM emp GROUP BY deptno);
ANY:=ANY(与IN操作一样)、>ANY(比最小大)、<ANY(比最大小)
SQL> SELECT * FROM emp
WHERE sal <ANY(SELECT MIN(sal) FROM emp GROUP BY deptno);
ALL: >ALL(比最大要大)、<ALL(比最小的小),SQL语句类似上面
多行子查询
显示和10号部门从事相同岗位的雇员信息
SQL>select * from emp where job in (select job from emp where deptno=10);
数据库更新操作INSERT、UPDATE、DELETE
【1】复制一张表,例如复制EMP表为MYEMP
SQL> CREATE TABLE MYTEMP AS SELECT * FROM emp;
【2】将编号为7899的雇员的领导取消
SQL> UPDATE myemp SET mgr=null WHERE empno=7899;
【3】更新时,一定要注意不能批量更新(加上WHERE子句),多列更新例子如下
SQL> UPDATE myemp SET mgr=null,comm=null WHERE empno IN(7369,8899);
【4】删除掉全部领取奖金的雇员
SQL> DELECT FROM emp WHERE comm is NOT NULL;
事务处理 ACID
A:Atomicity 原子性:事务中的操作或者都完成,或者都取消
C:Consistency 一致性:事务中的操作保证数据库中的数据不会出现逻辑上不一致的情况
I:Isolation 隔离性:当前的事务与其他未完成的事务是隔离的
D:Durability 持久性:在COMMIT之后,数据永久保存在数据库中,在此之前,事务的操作都可以回滚
验证事务过程:
<1>创建一张临时表,只包含部门10
SQL> CREATE TABLE emp10 AS SELECT * FROM emp WHERE empno=10;
<2>删除emp10中的7782雇员
SQL> DELETE FROM emp10 WHERE empno=7782;
再打开另一个窗口,发现数据还存在,此时如果可以使用以下的两种命令进行事务处理
COMMIT 和 ROLLBACK 提交事务和回滚事务
SQL查询练习
【1】列出至少一个员工的所有部门
SQL> SELECT d.*,ed.cou FROM dept d,(
SELECT deptno,COUNT(empno) cou FROM emp GROUP BY deptno
HAVING COUNT(empno) > 1
) ed
WHERE d.deptno=ed.deptno;
【2】列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门
SQL> SELECT d.deptno,d.dname,e.empno,e.ename
FROM dept d,emp e WHERE d.deptno = e.deptno(+);
【3】列出所有"CLERK"(办事员)的姓名及其部门名称,部门的人数
<1>关联dept表
SQL> SELECT e.ename,d.dname FROM emp e,dept d
WHERE e.deptno=d.deptno and e.job='CLERK';
<2>使用GROUP BY 完成部门分组人数
SQL> SELECT e.ename,d.dname,ed.cou FROM emp e,dept d,
( SELECT deptno,COUNT(empno) cou FROM emp GROUP BY deptno) ed
WHERE job='CLERK' AND e.deptno=d.deptno AND ed.deptno=e.deptno;