第2章 编写简单的查询语句
练习1
1.使用两种方式查询所有员工(EMP)信息。
SELECT *
FROM emp;
SELECT empno,ename,job,mgr,hiredate,sal,comm,deptno
FROM emp;
2.查询(EMP)员工编号、员工姓名、员工职位、员工月薪、工作部门编号。
SELECT empno,ename,job,sal,deptno
FROM emp;
练习2
1.员工转正后,月薪上调20%,请查询出所有员工转正后的月薪。
SELECT ename,sal*(1+0.2)
FROM emp;
2.员工试用期6个月,转正后月薪上调20%,请查询出所有员工工作第一年的年薪所得(不考虑奖金部分,年薪的试用期6个月的月薪+转正后6个月的月薪)
SELECT empno,sal*(1+0.2)*6+sal*6
FROM emp;
练习3
1.员工试用期6个月,转正后月薪上调20%,请查询出所有员工工作一年的所有收入(需考虑奖金部分),要求显示列标题为员工姓名,工资收入,奖金收入,总收入。
SELECT ename 员工姓名,sal*(1+0.2)*6+sal*6 工资收入,comm 奖金收 入,sal*(1+0.2)*6+sal*6+nvl(comm*12,0) 总收入
FROM emp;
练习4
1.员工试用期6个月,转正后月薪上调20%,请查询出所有员工工作第一年的所有收入(需考虑奖金部分),要求显示格式为:XXX的第一年总收入为XXX。
SELECT ename || '的第一年总收入为' || (sal*(1+0.2)*6+sal*6+nvl(comm*12,0))
FROM emp;
2.查询员工表中一共有哪几种岗位类型。
SELECT DISTINCT deptno
FROM emp;
课后作业
1.分别选择员工表、部门表、薪资等级表中的所有数据。
SELECT *
FROM emp;
SELECT *
FROM dept;
SELECT *
FROM salgrade;
2.分别查看员工表、部门表、薪资等级表结构。
DESC emp;
DESC dept;
DESC salgrade;
第3章 限制数据和对数据排序
练习1
1.查询职位为SALESMAN的员工编号、职位、入职日期。
SELECT empno,job,hiredate
FROM emp
WHERE job='SALESMAN';
2.查询1985年12月31日之前入职的员工姓名及入职日期。
SELECT empno,hiredate
FROM emp
WHERE hiredate<'31-12月1985';
3.查询部门标号不在10部门的员工姓名、部门编号。
SELECT ename,deptno
FROM emp
WHERE deptno<>10;
练习2
1.查询入职日期造82年至85年员工姓名,入职日期。
SELECT ename,hiredate
FROM emp
WHERE hiredate BETWEEN '01-1月-82' AND '01-1月-85';
SELECT ename,hiredate
FROM emp
WHERE hiredate BETWEEN TO_DATE('1982-01-01','YYYY-MM-DD')
AND TO_DATE('1985-01-01','YYYY-MM-DD');
2.查询月薪在3000到5000的员工姓名,月薪。
SELECT ename,sal
FROM emp
WHERE sal BETWEEN 3000 AND 5000;
3.查询部门编号为10或者20的员工姓名,部门编号。
SELECT ename,deptno
FROM emp
WHERE deptno=10 OR deptno=20;
4.查询经理编号为7709,7566,7788的员工姓名,经理编号。
SELECT ename,mgr
FROM emp
WHERE mgr IN(7709,7756,778);
练习3
1.查询员工姓名以W开头的员工姓名。
SELECT ename
FROM emp
WHERE ename LIKE 'W%';
SELECT ename
FROM emp
WHERE INSTR(ename,'W')=1;
2.查询员工姓名倒数第2个字符为T的员工姓名。
SELECT ename
FROM emp
WHERE ename LIKE '%T_';
SELECT ename
FROM emp
WHERE SUBSTR(ename,-2,1)=‘T’;
3.查询奖金为空的员工姓名,奖金。
SELECT ename,comm
FROM emp
WHERE comm IS NULL;
练习4
1.查询工资超过2000并且职位是WANAGER,或者职位是SALESMAN的员工姓名、职位、工资。
SELECT ename,job,sal
FROM emp
WHERE (sal>2000 AND job='MANAGER') OR job='SALESMAN';
2 .查询工资超过2000并且职位是WANAGER或SALESMAN的员工姓名、职位、工资。
SELECT ename,job,sal
FROM emp
WHERE (sal>2000 AND job='MANAGER') OR job='SALESMAN';
3.查询部门在10或者20,并且工资在3000到5000之间的员工姓名、部门、工资。
SELECT ename,deptno,sal
FROM emp
WHERE (deptno=10 OR deptno=20) AND sal BETWEEN 3000 AND 5000;
4.查询入职日期在81年,并且职位不是SALES开头的员工姓名、入职日期、职位。
SELECT ename,hiredate,job
FROM emp
WHERE (hiredate BETWEEN '01-1月-81' AND '31-12月-81') AND job NOT LIKE 'SALES%';
SELECT ename,hiredate,job
FROM emp
WHERE (hiredate BETWEEN '01-1月-81' AND '31-12月-81')
AND SUBSTR(job,0,5)<>'SALES';
5.查询职位为SALESMAN或MANAGER,部门编号为10或者20,姓名包含A的员工姓名、职位、部门编号。
SELECT ename,job,deptno
FROM emp
WHERE (job='SALESMAN' OR job='MANAGER') AND (deptno=10 OR deptno=20) AND ename LIKE '%A%';
SELECT ename,job,deptno
FROM emp
WHERE (job='SALESMAN' OR job='MANAGER')
AND (deptno=10 OR deptno=20)
AND INSTR(ename,'A')>0;
练习5
1.查询部门在20或30的员工姓名,部门编号,并按照工资升序排序。
SELECT ename,deptno,sal
FROM emp
WHERE deptno=20 OR deptno=30
ORDER BY sal;
2.查询工资在2000-3000之间,部门不在10号的员工姓名,部门编号,工资,并按照部门升序,工资降序排序。
SELECT ename,deptno, sal
FROM emp
WHERE (sal BETWEEN 2000 AND 3000) AND deptno<>10
ORDER BY deptno,sal DESC;
3.查询入职日期在82年至83年之间,职位以SALES或者MAN开头的员工姓名,入职日期,职位,并按照入职日期降序排序。
–3.查询入职日期在82年至83年之间,职位以SALES或者MAN开头的员工姓名,入职日期,职位,并按照入职日期降序排序。
SELECT ename,hiredate,job
FROM emp
WHERE (hiredate BETWEEN '01-1月-82' AND '01-1月-83')
AND (job LIKE 'SALES%' OR job LIKE 'MAN%')
ORDER BY hiredate DESC;
课后作业
1.查询入职时间在1982-7-9之后,并且不从事SALESMAN工作的员工姓名、入职时间、职位。
SELECT ename,hiredate,job
FROM emp
WHERE hiredate>'09-7月-1982' AND job<>'SALESMAN';
2.查询员工姓名的第三个字母是a的员工姓名。
SELECT ename
FROM emp
WHERE SUBSTR(ename,3,1)='a';
SELECT ename
FROM emp
WHERE ename LIKE '__a%';
3.查询除了10、20号部门以外的员工姓名、部门编号。
SELECT ename,deptno
FROM emp
WHERE deptno NOT IN(10,20);
4.查询部门号为30号员工的信息,先按工资降序排序,再按姓名升序排序。
SELECT *
FROM emp
WHERE deptno=30
ORDER BY sal DESC,ename;
5.查询没有上级的员工(经理号为空)的员工姓名。
SELECT ename
FROM emp
WHERE mgr IS NULL;
6.查询工资大于等于4500并且部门为10或者20的员工的姓名,工资,部门编号。
SELECT ename,sal,deptno
FROM emp
WHERE sal>=4500 AND deptno IN(10,20);
第4章 单行函数
练习1
1.写一个查询,用首字母大写,其他字母小写显示雇员的ename,显示名字的长度,并给每列一个适当的标签,条件是满足所有雇员名字的开始字母是J、A或M的雇员,并对查询结果按雇员的ename升序排序。(提示:使用initcap、length、substr)
SELECT INITCAP(ename) 雇员姓名,LENGTH(ename) 姓名长度
FROM emp
WHERE ename LIKE 'J%' OR ename LIKE 'A%' OR ename LIKE 'M%'
ORDER BY ename;
练习2
1.查询员工姓名中包含大写或小写字母A的员工姓名。
SELECT ename
FROM emp
WHERE SUBSTR(ename,1,1)=‘A’ OR SUBSTR(ename,1,1)=‘a’;
2.查询部门编号为10或20,入职日期在81年5月1日之后,并且姓名中包含大写字母A的员工姓名,员工姓名长度。(提示:要求使用INSTR函数)
SELECT ename 员工姓名,LENGTH(ename) 姓名长度
FROM emp
WHERE (deptno=10 OR deptno=20)
AND hiredate>'01-5月-81'
AND SUBSTR(ename,1,1)='A';
3.查询每个职工的编号,姓名,工资
-要求将查询到的数据按照一定的格式合并成一个字符串
-前10位:编号,不足部分用*填充,左对齐
-中间10位:姓名,不足部分用*填充,左对齐
-后10位:工资,不足部分用*填充,右对齐
SELECT CONCAT(CONCAT(LPAD(empno,10,'*'),LPAD(ename,10,'*')),RPAD(sal,10,'*'))
FROM emp;
练习3
1.写一个查询,分别计算100.456四舍五入到小数点后第2位,第1位,整数位的值。
SELECT ROUND(100.456,2)
FROM dual;
SELECT ROUND(100.456,1)
FROM dual;
SELECT ROUND(100.456,-1)
FROM dual;
2.写一个查询,分别计算100.456从小数点后第2位,第1位,整数位截断的值。
SELECT TRUNC(100.456,2)
FROM dual;
SELECT TRUNC(100.456,1)
FROM dual;
SELECT TRUNC(100.456,-1)
FROM dual;
练习4
1.查询每个员工截止到现在一共入职多少天?
SELECT empno,SYSDATE-hiredate 入职天数
FROM emp
2.当前日期为2015年,指定日期格式DD-MON-RR,指定日期为01-1月-01,该日期实际所代表的日期为?
2001-01-01
-
当前日期为2015年,指定日期格式DD-MON-RR,指定日期为01-1月-95,该日期实际所代表的日期为?
1995-01-01
4.当前日期为1998年,指定日期格式DD-MON-RR,指定日期为01-1月-01,该日期实际所代表的日期为?
2001-01-01
5.当前日期为1998年,指定日期格式DD-MON-RR,指定日期为01-1月-95,该日期实际所代表的日期为?
1995-01-01
6.当前日期为1998年,指定日期格式DD-MON-YY,指定日期为01-1月-01,该日期实际所代表的日期为?
1901-01-01
7.当前日期为1998年,指定日期格式DD-MON-YY,指定日期为01-1月-95,该日期实际所代表的日期为?
1995-01-01
练习5
1.查询服务器当前时间。
SELECT SYSDATE
FROM dual;
2.查询部门10,20的员工截止到2000年1月1日,工作了多少个月,入职的月份。(使用months_between, extract)
SELECT MONTHS_BETWEEN('01-1月-2000',hiredate) 工作月份,
EXTRACT(MONTH FROM DATE '2000-01-01') 入职月份
FROM emp
WHERE deptno=10 OR deptno=20;
3.如果员工使用期6个月,查询职位不是MANAGER员工姓名,入职日期,转正日期,入职日期后的第一个星期一,入职当前月的最后一天日期。(使用add_months, next_day, last_day)
SELECT ename,hiredate,
ADD_MONTHS(hiredate,6) 转正日期,
NEXT_DAY(hiredate,'星期一') 入职日期后的第一个星期一,
LAST_DAY(hiredate) 入职当前月的最后一天日期
FROM emp
WHERE job<>'MANAGER';
练习6
1.显示服务器系统当前时间,格式为2007-10-12 17:11:11。(用to_char函数)
SELECT to_char(SYSDATE,'YYYY-MM-DD HH24:MI:SS')
FROM dual;
2.显示ename,hiredate和雇员开始工作日是星期几,列标签DAY。(用to_char函数)
SELECT ename,hiredate,
to_char(hiredate,'DAY') DAY
FROM emp;
3.查询员工姓名,工资,格式化的工资(¥999,999.99)。(用to_char函数)
SELECT ename,sal,
to_char(sal,'$999,999.99') 格式化的工资
FROM emp;
4.把字符串2015-3月-18 13:13:13转换成日期格式,并计算和系统当前时间间隔多少天。(用to_char函数)
SELECT TO_DATE('2015-3月-18 13:13:13','YYYY-MM"月"-DD HH24:MI:SS'),
SYSDATE-TO_DATE('2015-3月-18 13:13:13','YYYY-MM"月"-DD HH24:MI:SS')
FROM dual;
课后作业
1.计算2000年1月1日到现在又多少月,多少周(四舍五入)。
SELECT ROUND(MONTHS_BETWEEN(SYSDATE,'01-1月-2000')),
ROUND(ROUND(SYSDATE-TO_DATE('2000-01-01','YYYY-MM-DD'))/7)
FROM dual;
2.查询员工ename的第三个字母是A的员工信息(使用两个函数)。
SELECT *
FROM emp
WHERE SUBSTR(ename,3,1)='A';
SELECT *
FROM emp
WHERE INSTR(ename,'A',3)=3;
3.使用trim函数将字符串‘hello’,‘Hello’,‘bllb’,‘hello’分别处理得以下字符串ello、Hello、ll、hello。
SELECT TRIM('h' FROM 'hello'),
TRIM(' ' FROM 'Hello '),
TRIM('b' FROM 'bllb'),
TRIM(' ' FROM 'hello ')
FROM dual;
4.将员工工资按如下格式显示:123,234.00 RMB。
SELECT empno,to_char(sal,'999,999.99') || 'RMB'
FROM emp;
5.查询员工的姓名及其经理编号,要求对于没有经理的显示“No Manager”字符串。
SELECT ename,NVL(to_char(mgr),'No Manager')
FROM emp;
6.将员工的参加工作日期按照如此啊格式显示:月份/年份
SELECT empno,to_char(hiredate,'MM/YYYY')
FROM emp;
7.在员工表中查询除员工的工资,并计算应交税款:如果工资小于1000,税率为0,如果工资大于等于1000并小于2000,税率为10%,如果工资大于等于2000并小于3000,税率为15%,如果工资大于等于3000,税率为20%。
SELECT empno,sal,
(CASE
WHEN sal>=0 AND sal<1000 THEN sal*0
WHEN sal>=1000 AND sal<2000 THEN sal*0.1
WHEN sal>=2000 AND sal<3000 THEN sal*0.15
WHEN sal>=3000 THEN sal*0.1
ELSE 0 END) 税率
FROM emp;
8.创建一个查询显示所有雇员的ename和sal。格式化sal围殴15个字符长度,用$左填充,列标签SALARY。
SELECT ename,LPAD(sal,15,'$') SALARY
FROM emp;
第5章 多表连接
练习1
1.写一个查询,显示所有员工姓名,部门编号,部门姓名。
SELECT ename,emp.deptno,dname
FROM emp,dept
WHERE emp.deptno=dept.deptno;
2.写一个查询,显示所有工作在CHICAGO并且奖金不为空的员工姓名,工作地点,奖金。
SELECT ename,loc,comm
FROM emp,dept
WHERE emp.deptno=dept.deptno AND comm IS NOT NULL;
3.写一个查询,显示所有姓名中含有A字符的员工姓名,工作地点。
SELECT ename,loc
FROM emp,dept
WHERE emp.deptno=dept.deptno AND ename LIKE '%A%';
练习2
1.查询每个员工的编号,姓名,工资,工资等级,所在工作城市,按照工资等级进行升序排序。
SELECT e.deptno,ename,sal,grade,loc
FROM emp e,dept d,salgrade s
WHERE e.deptno=d.deptno
AND (e.sal BETWEEN s.losal AND s.hisal)
ORDER BY grade;
练习3.
1.查询所有工作在NEW YORK和CHICAGO的员工姓名,员工编号,以及他们的经理姓名,经理编号。
SELECT e.ename 员工姓名,e.empno 员工编号,
m.ename 经理姓名,m.empno 经理编号
FROM emp e,emp m
WHERE e.mgr=m.empno;
2.在上一题的基础上,添加没有经理的员工King,并按照员工编号排序。
SELECT e.ename 员工姓名,e.empno 员工编号,
m.ename 经理姓名,m.empno 经理编号
FROM emp e,emp m
WHERE e.mgr=m.empno(+)
ORDER BY e.empno;
3.查询所有员工编号,姓名,部门名称,包括没有部门的员工也要显示出来。
SELECT emp.empno,ename,dname
FROM emp,dept
WHERE emp.deptno=dept.deptno(+);
练习4
使用SQL-99写法,完成如下练习
1.创建一个员工表和部门表的交叉连接。
SELECT *
FROM emp
CROSS JOIN dept;
2.使用自然连接,显示入职日期在80年5月1日之后的员工姓名,部门名称,入职日期。
SELECT ename,dname,hiredate
FROM emp
NATURAL JOIN dept
WHERE hiredate>'01-5月-80';
3.使用USING子句,显示工作在CHICAGO的员工姓名,部门名称,工作地点。
SELECT ename,dname,loc
FROM emp
JOIN dept USING(deptno)
WHERE loc='CHICAGO';
4.使用ON子句,显示工作在CHICAGO的员工姓名,本门名称,工作地点,薪资等级。
SELECT ename,dname,loc,grade
FROM emp e
JOIN dept d
ON e.deptno=d.deptno AND loc='CHICAGO'
JOIN salgrade s
ON sal BETWEEN losal AND hisal;
5.使用左连接,查询每个员工的姓名,经理姓名,没有经理的King也要显示出来。
SELECT e.ename 员工姓名,m.ename 经理姓名
FROM emp e
OUTER JOIN emp m
ON e.mgr=m.empno;
6.使用右外连接,查询每个员工的姓名,经理姓名,没有经理的King也要显示出来。
SELECT e.ename 员工姓名,m.ename 经理姓名
FROM emp m
RIGHT OUTER JOIN emp e
ON e.mgr=m.empno;
课后作业
1.显示员工SMITH的姓名,部门名称,直接上级名称。
SELECT e.ename,dname,m.ename 直接上级名称
FROM emp e,emp m,dept d
WHERE e.mgr=m.empno AND e.deptno=d.deptno AND e.ename='SMITH';
2.显示员工姓名,部门名称,工资,工资级别,要求工资级别大于4级。
SELECT ename,dname,sal,grade
FROM emp e,dept d,salgrade s
WHERE e.deptno=d.deptno
AND (sal BETWEEN losal AND hisal)
AND grade>4;
3.显示员工KING和FORD管理的员工姓名及其经理姓名。
SELECT e.ename 员工姓名,m.ename 经理姓名
FROM emp e,emp m
WHERE e.mgr=m.empno
AND m.ename IN('KING','FORD');
4.显示员工姓名,参加工作时间,经理名,参加工作时间,要求参加时间比经理早。
SELECT e.ename,e.hiredate,m.ename,m.hiredate
FROM emp e,emp m
WHERE e.mgr=m.empno AND e.hiredate>m.hiredate;
第6章 分组函数
练习1
1.查询部门20的员工,每月的工资总和及平均工资。
SELECT SUM(sal),AVG(sal)
FROM emp
WHERE deptno=20;
2.查询工作在CHICAGO的员工人数,最高工资及最低工资。
SELECT COUNT(*),MIN(sal),MAX(sal)
FROM emp e,dept d
WHERE e.deptno=d.deptno AND loc='CHICAGO';
3.查询员工表中一共有几种岗位类型。
SELECT COUNT(DISTINCT job)
FROM emp;
练习2
1.查询每个部门的部门编号,部门名称,部门人数,最高工资,最低工资,工资总和,平均工资。
SELECT d.deptno,dname,COUNT(e.deptno),MIN(sal),MAX(sal),SUM(sal),AVG(sal)
FROM emp e,dept d
WHERE e.deptno(+)=d.deptno
GROUP BY d.deptno,dname,loc;
2.查询每个部门,每个岗位的部门编号,部门名称,岗位名称,部门人数,最高工资,最低工资,工资总和,平均工资。
SELECT d.deptno,dname,job,COUNT(e.empno),MAX(sal),MIN(sal),SUM(sal),AVG(sal)
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY d.deptno,dname,e.job;
3.查询每个经理所管理的人数,经理编号,经理姓名,要求包括没有经理的人员信息。
SELECT COUNT(e.empno),m.empno,m.ename
FROM emp e,emp m
WHERE e.mgr=m.empno(+)
GROUP BY m.empno,m.ename;
练习3
1.查询部门人数大于2的部门编号,部门名称,部门人数。
SELECT d.deptno,dname,COUNT(empno)
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY d.deptno,dname
HAVING COUNT(empno)>2;
2.查询部门平均工资大于2000,且人数大于2的部门编号,部门名称,部门人数,
部门平均工资,并按照部门人数升序排序。
SELECT d.deptno,dname,COUNT(empno),AVG(sal)
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY d.deptno,dname
HAVING AVG(sal)>2000 AND COUNT(empno)>2
ORDER BY COUNT(empno);
课后作业
1.查询部门平均工资在2500元以上的部门名称及平均工资。
SELECT dname,AVG(sal)
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY dname
HAVING AVG(sal)>2500;
2.查询员工岗位中不是以“SA”开头并且平均工资在2500员以上的岗位及平均工资,并按平均工资降序排序。
SELECT job,AVG(sal)
FROM emp
WHERE job NOT LIKE 'SA%'
GROUP BY job
HAVING AVG(sal)>2500
ORDER BY AVG(sal) DESC;
3.查询部门人数在2人以上的部门名称,最低工资,最高工资,并对要求的工资进行四舍五入到整数位。
SELECT dname,ROUND(MIN(sal),-1) 最低工资,
ROUND(MAX(sal),-1) 最高工资
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY dname
HAVING COUNT(empno)>2;
4.查询岗位不为SALESMSMAN,工资和大于等于2500的岗位及每种岗位的工资和。
SELECT job,SUM(sal)
FROM emp
WHERE job<>'SALESMSMAN'
GROUP BY job
HAVING SUM(sal)>2500;
5.显示经理编号和经理姓名,这个经理所管理员工的最低工资,没有经理的KING也要显示,不包括最低工资小于3000的,按最低工资由高到低排序。
SELECT m.empno,m.ename,MIN(e.sal)
FROM emp e,emp m
WHERE e.mgr=m.empno(+)
GROUP BY m.empno,m.ename
HAVING MIN(e.sal)>=3000
ORDER BY MIN(e.sal) DESC;
6.写一个查询,显示每个部门最高工资和最低工资的差额。
SELECT deptno,MAX(sal)-MIN(sal)
FROM emp
GROUP BY deptno;
第7章 子查询
练习1
1.查询入职日期最早的员工姓名,入职日期。
--最早的入职日期
SELECT MIN(hiredate)
FROM emp;
SELECT ename,hiredate
FROM emp
WHERE hiredate=
(SELECT MIN(hiredate)
FROM emp);
2.查询工资比SMITH工资高并且工作地点在CHICAGO的员工姓名,工资,部门名称。
--SMITH的工资
SELECT sal
FROM emp
WHERE ename='SMITH';
SELECT ename,sal,dname
FROM emp e,dept d
WHERE sal>
(SELECT sal
FROM emp
WHERE ename='SMITH')
AND loc='CHICAGO';
3.查询入职日期比20部门入职日期最早的员工还早的员工姓名,入职日期。
--20部门员工的最早入职日期
SELECT MIN(hiredate)
FROM emp
WHERE deptno=20;
SELECT ename,hiredate
FROM emp
WHERE hiredate<
(SELECT MIN(hiredate)
FROM emp
WHERE deptno=20);
4.查询部门人数大于所有部门平均人数的部门编号,部门名称,部门人数。
--所有部门平均人数
SELECT AVG(COUNT(empno))
FROM emp
GROUP BY deptno;
SELECT d.deptno,dname,COUNT(empno)
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY d.deptno,dname
HAVING COUNT(empno)>
(SELECT AVG(COUNT(empno))
FROM emp
GROUP BY deptno);
练习2
1.查询入职日期比10部门任意一个员工晚的员工姓名,入职日期,不包括10部门员工。
--10部门员工的最早入职日期
SELECT MIN(hiredate)
FROM emp
WHERE deptno=10;
SELECT ename,hiredate
FROM emp
WHERE hiredate>
(SELECT MIN(hiredate)
FROM emp
WHERE deptno=10)
AND deptno<>10;
2.查询入职日期比10部门所有员工晚的员工姓名,入职日期,不包括10部门员工。
--10部门最晚的员工入职日期
SELECT MAX(hiredate)
FROM emp
WHERE deptno=10;
SELECT ename,hiredate
FROM emp
WHERE hiredate>
(SELECT MAX(hiredate)
FROM emp
WHERE deptno=10)
AND deptno<>10;
3.查询职位和10部门人员一个员工职位相同的员工姓名,职位,不包括10部门员工。
--10部门员工职位
SELECT job
FROM emp
WHERE deptno=10;
SELECT ename,job
FROM emp
WHERE job IN
(SELECT job
FROM emp
WHERE deptno=10)
AND deptno<>10;
练习3
1.查询职位及经理和10部门任意一个员工职位及经理相同的员工姓名,职位,不包括10部门员工。
--10部门的全部员工职位及经理
SELECT job,mgr
FROM emp
WHERE deptno=10;
SELECT ename,job
FROM emp
WHERE (job,mgr) IN
(SELECT job,mgr
FROM emp
WHERE deptno=10)
AND deptno<>10;
2.查询职位及经理和10部门任意一个员工职位或经理相同的员工姓名,职位,不包括10部门员工。
SELECT ename,job
FROM emp
WHERE (job IN
(SELECT job
FROM emp
WHERE deptno=10)
AND deptno<>10)
OR (mgr IN
(SELECT mgr
FROM emp
WHERE deptno=10)
AND deptno<>10);
练习4
1.查询比自己职位平均工资高的员姓名,职位,部门名称,职位平均工资。
--查询每个职位的平均工资
SELECT job,AVG(sal) avgsal
FROM emp
GROUP BY job;
SELECT ename,e.job,dname,a.avgsal
FROM emp e,dept d,
(SELECT job,AVG(sal) avgsal
FROM emp
GROUP BY job) a
WHERE e.deptno=d.deptno
AND e.job=a.job
AND e.sal>a.avgsal;
2.查询职位和经理同员工SCOTT或BLAKE完全相同的员工姓名,职位,不包括SCOTT和BLAKE本人。
--员工SCOTT或BLAKE的职位和经理
SELECT job,mgr
FROM emp
WHERE ename='SCOTT'
OR ename='BLAKE';
SELECT ename,job
FROM emp
WHERE (job,mgr) IN
(SELECT job,mgr
FROM emp
WHERE ename='SCOTT'
OR ename='BLAKE');
3.查询不是经理的员工姓名。
SELECT ename
FROM emp
WHERE job<>'MANAGER';
练习5
1.查询入职日期最早的前5名员姓名,入职日期。
SELECT ROWNUM,ename,hiredate
FROM emp
WHERE ROWNUM<=5
ORDER BY hiredate;
2.查询工作在CHICAGO并且入职日期最早的前2名员工姓名,入职日期。
SELECT ROWNUM,ename,hiredate
FROM emp e,dept d
WHERE e.deptno=d.deptno
AND loc='CHICAGO'
AND ROWNUM<=2
ORDER BY hiredate;
练习6
1.按照每页显示5条记录,分别查询第1页,第2页,第3页信息,要求显示员工姓名,入职日期,部门名称。
SELECT ROWNUM rn,ename,hiredate,dname
FROM emp e,dept d
WHERE e.deptno=d.deptno
--第一页
SELECT a.*
FROM (SELECT ROWNUM rn,ename,hiredate,dname
FROM emp e,dept d
WHERE e.deptno=d.deptno) a
WHERE rn<=5*1 AND rn>5*0;
--第二页
SELECT a.*
FROM (SELECT ROWNUM rn,ename,hiredate,dname
FROM emp e,dept d
WHERE e.deptno=d.deptno) a
WHERE rn<=5*2 AND rn>5*1;
--第三页
SELECT a.*
FROM (SELECT ROWNUM rn,ename,hiredate,dname
FROM emp e,dept d
WHERE e.deptno=d.deptno) a
WHERE rn<=5*3 AND rn>5*2;
练习7
1.按照每页显示5条记录,分别查询工资最高的第1页,第2页,第3页信息,要求显示员工姓名,入职日期,部门名称,工资。
SELECT ROWNUM rn,ename,hiredate,dname,sal
FROM emp e,dept d
WHERE e.deptno=d.deptno
ORDER BY sal DESC
--第一页
SELECT a.*
FROM (SELECT ROWNUM rn,ename,hiredate,dname,sal
FROM emp e,dept d
WHERE e.deptno=d.deptno
ORDER BY sal DESC) a
WHERE rn<=5*1 AND rn>5*0;
--第二页
SELECT a.*
FROM (SELECT ROWNUM rn,ename,hiredate,dname,sal
FROM emp e,dept d
WHERE e.deptno=d.deptno
ORDER BY sal DESC) a
WHERE rn<=5*2 AND rn>5*1;
--第三页
SELECT a.*
FROM (SELECT ROWNUM rn,ename,hiredate,dname,sal
FROM emp e,dept d
WHERE e.deptno=d.deptno
ORDER BY sal DESC) a
WHERE rn<=5*3 AND rn>5*2;
课后作业
1.查询工资高于编号为7782的员工工资,并且和7369号员工从事相同工作的员工的编号,姓名及工资。
--编号为7782的员工工资
SELECT sal
FROM emp
WHERE empno='7782';
--7369号员工从事的工作
SELECT job
FROM emp
WHERE empno='7369';
SELECT empno,ename,sal
FROM emp
WHERE sal>
(SELECT sal
FROM emp
WHERE empno='7782')
AND job=
(SELECT job
FROM emp
WHERE empno='7369');
2.查询工资最高的员工姓名和工资。
SELECT ename,sal
FROM emp
WHERE sal=
(SELECT MAX(sal)
FROM emp);
-
查询部门最低工资高于10号部门最低工资的部门的编号、名称及部门最低工资。
--10号部门最低工资 SELECT MIN(sal) FROM emp WHERE deptno=10; SELECT e.deptno,dname,MIN(sal) FROM emp e,dept d WHERE e.deptno=d.deptno
GROUP BY e.deptno,dname
HAVING MIN(sal)< (SELECT MIN(sal) FROM emp WHERE deptno=10);
4.查询员工工资为其部门最低工资的员工的编号和姓名及工资。
–部门最低工资的员工
SELECT deptno,MIN(sal)
FROM emp
GROUP BY deptno;
SELECT empno,ename,sal
FROM emp e,(SELECT deptno,MIN(sal) minsal
FROM emp
GROUP BY deptno) d
WHERE e.deptno=d.deptno
AND sal=minsal;
5.显示经理是KING的员工姓名,工资。
SELECT ename,sal
FROM emp
WHERE mgr=
(SELECT empno
FROM emp
WHERE ename='KING');
6.显示比员工SMITH参加工作时间晚的员工姓名,工资,参加工作时间。
SELECT ename,sal,hiredate
FROM emp
WHERE hiredate>
(SELECT hiredate
FROM emp
WHERE ename='SMITH');
7.使用子查询的方式查询哪些职员在NEW YORK工作。
SELECT *
FROM emp
WHERE deptno=
(SELECT deptno
FROM dept
WHERE loc='NEW YORK');
8.写一个查询显示和员工SMITH工作在同一个部门的员工姓名,雇用日期,查询结果中排除SMITH。
SELECT ename,hiredate
FROM emp
WHERE deptno=
(SELECT deptno
FROM emp
WHERE ename='SMITH')
AND ename<>‘SMITH’;
9.写一个查询显示其工资比全体职员平均工资高的员工编号、姓名。
SELECT empno,ename
FROM emp
WHERE sal>
(SELECT AVG(sal)
FROM emp);
10.写一个查询显示其上级领导是King的员工姓名、工资。
SELECT ename,sal
FROM emp
WHERE mgr=
(SELECT empno
FROM emp
WHERE ename='KING');
11.显示所有工作在RESEARCH部门的员工姓名,职位。
SELECT ename,job
FROM emp
WHERE deptno=
(SELECT deptno
FROM dept
WHERE dname='RESEARCH');
12.查询每个部门的部门编号、平均工资,要求部门的平均工资高于部门20的平均工资。
SELECT deptno,AVG(sal)
FROM emp
GROUP BY deptno
HAVING AVG(sal)>
(SELECT AVG(sal)
FROM emp
WHERE deptno=20);
13.查询大于自己部门平均工资的员工姓名,工资,所在部门平均工资,高于部门平均工资的额度。
SELECT ename,sal,avgsal,sal-avgsal
FROM emp e,(SELECT deptno,AVG(sal) avgsal
FROM emp
GROUP BY deptno) d
WHERE e.deptno=d.deptno AND sal>avgsal;
14.列出至少有一个雇员的所有部门。
SELECT *
FROM dept
WHERE deptno IN
(SELECT deptno
FROM emp
GROUP BY deptno
HAVING COUNT(*)>0);
15.列出薪金比"SMITH"多的所有雇员。
SELECT *
FROM emp
WHERE sal>
(SELECT sal
FROM emp
WHERE ename='SMITH');
16.列出入职日期早于其直接上级的所有雇员。
SELECT *
FROM emp e
WHERE hiredate<
(SELECT m.hiredate
FROM emp m
WHERE e.mgr=m.empno);
SELECT DISTINCT *
FROM emp a,(SELECT e.mgr mno,m.hiredate mdate
FROM emp e,emp m
WHERE e.mgr=m.empno) b
WHERE a.mgr=b.mno
AND hiredate<b.mdate;
17.找员工姓名和直接上级的名字。
SELECT e.ename ,m.ename
FROM emp e,emp m
WHERE e.mgr=m.empno(+);
18.显示部门名称和人数。
SELECT dname,COUNT(empno)
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY dname;
19.显示每个部门的最高工资的员工。
SELECT *
FROM emp
WHERE (deptno,sal) IN
(SELECT deptno,MAX(sal)
FROM emp
GROUP BY deptno);
20.显示出和员工号7369部门相同的员工姓名,工资。
SELECT ename,sal
FROM emp
WHERE deptno=
(SELECT deptno
FROM emp
WHERE empno='7369');
21.显示出和姓名中包含"W"的员工相同部门的员工姓名。
SELECT ename
FROM emp
WHERE deptno=
(SELECT deptno
FROM emp
WHERE ename LIKE '%W%');
22.显示出工资大于平均工资的员工姓名,工资。
SELECT ename,sal
FROM emp
WHERE sal>
(SELECT AVG(sal)
FROM emp);
23.显示出工资大于本部门平均工资的员工姓名,工资。
SELECT ename,sal
FROM emp e,(SELECT deptno,AVG(sal) avgsal
FROM emp
GROUP BY deptno) a
WHERE e.deptno=a.deptno
AND sal>avgsal;
24.显示每位经理管理员工的最低工资,及最低工资者的姓名。
SELECT sal,ename
FROM emp
WHERE (mgr,sal) IN
(SELECT mgr,min(sal)
FROM emp
GROUP BY mgr);
25.显示比工资最高的员工参加工作时间晚的员工姓名,参加工作时间
SELECT ename,hiredate
FROM emp
WHERE hiredate>
(SELECT hiredate
FROM emp
WHERE sal=
(SELECT MAX(sal)
FROM emp));
26.显示出平均工资最高的的部门平均工资及部门名称
SELECT *
FROM (SELECT AVG(sal),dname
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY dname
ORDER BY AVG(sal) DESC)
WHERE ROWNUM<=1;
第8章 集合运算
练习1
1.分别使用联合运算及完全联合运算完成,按照时间升序顺序,查询员工7839的工作岗位列表。
--集合运算
SELECT hiredate,job
FROM emp
WHERE empno= 7839
UNION
SELECT begindate,job
FROM emp_jobhistory
WHERE empno =7839;
–完全联合运算
SELECT job,hiredate
FROM emp
WHERE empno=7839
UNION ALL
SELECT job,begindate
FROM emp_jobhistory
WHERE empno=7839
ORDER BY hiredate;
2.使用多表连接,查询每个部门的部门编号,部门人数,没有人数的部门显示0。
SELECT d.deptno,COUNT(empno)
FROM emp e,dept d
WHERE e.deptno(+)=d.deptno
GROUP BY d.deptno;
3.使用联合运算,查询每个部门的部门编号,部门人数,没有人数的部门显示0。
SELECT d.deptno,COUNT(empno)
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY d.deptno
UNION
SELECT d.deptno,COUNT(empno)
FROM emp e,dept d
WHERE e.deptno(+)=d.deptno
GROUP BY d.deptno
HAVING COUNT(empno)=0;
4.使用联合运算,查询10号部门及20号部门的员工姓名,部门编号。
SELECT ename,deptno
FROM emp
WHERE deptno=10
UNION
SELECT ename,deptno
FROM emp
WHERE deptno=20;
- 使用集合运算,输出如下效果?
部门 工作地点 员工姓名 入职日期
10 NEW YORK
10 CLARK 1981/6/9
10 KING 1981/11/17
10 MILLER 1982/1/23
20 DALLAS
20 ADAMS 1987/5/23
20 FORD 1981/12/3
20 JONES 1981/4/2
20 SCOTT 1987/4/19
20 SMITH 1980/12/17
30 CHICAGO
30 ALLEN 1981/2/20
30 BLAKE 1981/5/1
30 JAMES 1981/12/3
30 MARTIN 1981/9/28
30 TURNER 1981/9/8
30 WARD 1981/2/22
40 BOSTON
SELECT deptno 部门,NULL 工作地点,ename 员工姓名,hiredate 入职日期
FROM emp
UNION
SELECT deptno,loc,NULL,NULL
FROM dept
WHERE loc IN (‘NEW YORK’,‘DALLAS’,‘CHICAGO’,‘BOSTON’);
课后作业
1.用集合运算,列出不包含job为SALESMAN的部门的部门号。
SELECT deptno
FROM dept
MINUS
SELECT deptno
FROM emp
WHERE job=‘SALESMAN’;
2.写一个联合查询,列出下面的信息:
EMP表中所有雇员的名字和部门编号,不管他们是否属于任何部门。
DEPT表中的所有部门编号和部门名称,不管他们是否有员工。
SELECT ename,deptno,NULL
FROM emp
UNION
SELECT NULL,deptno,dname
FROM dept
ORDER BY deptno,ename DESC;
3.用集合运算查询出职位为SALESMAN和部门编号为10的
人员编号、姓名、职位,不排除重复结果。
SELECT empno,ename,job
FROM emp
WHERE job=‘SALESMAN’
UNION ALL
SELECT empno,ename,job
FROM emp
WHERE deptno=10;
4.用集合查询出部门为10和20的所有人员编号、姓名、所在部门名称。
SELECT empno,ename,dname
FROM emp e,dept d
WHERE e.deptno=d.deptno AND e.deptno=10
UNION
SELECT empno,ename,job
FROM emp e,dept d
WHERE e.deptno=d.deptno AND e.deptno=20;
第9章 高级子查询
练习1
如下练习,使用相关子查询完成
1.查询比所在职位平均工资高的员工姓名,职位
SELECT ename,job
FROM emp e
WHERE sal>
(SELECT AVG(sal)
FROM emp
WHERE job=e.job);
2.查询工资为其部门最低工资的员工编号,姓名 ,工资。
SELECT empno,ename,sal
FROM emp e
WHERE sal=
(SELECT MIN(sal)
FROM emp
WHERE deptno=e.deptno);
练习2
如下练习,用相关子查询完成
1.查询所有雇员编号,名字和部门名字。
SELECT empno,ename,
(SELECT dname
FROM dept
WHERE e.deptno=deptno) 部门名字
FROM emp e;
2.查询哪些员工是经理?
SELECT *
FROM emp e
WHERE EXISTS
(SELECT '1'
FROM emp
WHERE mgr=e.empno);
3.查询哪些员工不是经理?
SELECT *
FROM emp e
WHERE NOT EXISTS
(SELECT '1'
FROM emp
WHERE mgr=e.empno);
4.查询每个部门工资最低的两个员工编号,姓名,工资。
SELECT empno,ename,sal
FROM emp e
WHERE 1>=
(SELECT COUNT(empno)
FROM emp
WHERE deptno=e.deptno
AND sal<e.sal)
练习3
如下练习,用exists或not exists完成
1.列出至少有一个雇员的所有部门名称。
SELECT dname
FROM dept d
WHERE EXISTS
(SELECT '1'
FROM emp
WHERE deptno=d.deptno);
2.列出一个雇员都没有的所有部门名称。
SELECT dname
FROM dept d
WHERE NOT EXISTS
(SELECT '1'
FROM emp
WHERE deptno=d.deptno);
课后作业 :
如下练习,使用相关子查询完成。
1.查询薪水多于他所在部门平均薪水的雇员名字 ,部门号。
SELECT ename,deptno
FROM emp e
WHERE sal>
(SELECT AVG(sal)
FROM emp
WHERE job=e.job);
2.查询员工姓名和直接上级的名字。
SELECT ename,
(SELECT ename
FROM emp
WHERE e.mgr=empno) 直接上级名字
FROM emp e;
3.查询每个部门工资最高的员工姓名,工资。
SELECT ename,sal
FROM emp e
WHERE sal=
(SELECT MAX(sal)
FROM emp
WHERE deptno=e.deptno);
4.查询每个部门工资前两名高的员工姓名,工资。
SELECT empno,ename,sal
FROM emp e
WHERE 1>=
(SELECT COUNT(empno)
FROM emp
WHERE deptno=e.deptno
AND sal>e.sal)
第10章 层次查询
课后作业
1.产生一个报告显示 BLAKE的所有下级(包括直接和间接下级)雇员的名字、薪水和部门号。
SELECT ename,sal,deptno
FROM emp
START WITH ename=‘BLAKE’
CONNECT BY PRIOR empno=mgr;
2.创建一个报告显示对于雇员 SMITH 经理的层次,包括级别和姓名,首先显示他的直接经理。
SELECT LEVEL,ename
FROM emp
WHERE ename<>‘SMITH’
START WITH ename=‘SMITH’
CONNECT BY PRIOR mgr=empno;
3.创建一个缩进报告显示经理层次,从名字为 KING的雇员开始,显示雇员的名字、经理ID和部门ID。
SELECT LPAD(ename, LENGTH(ename)+(LEVEL-1)2,’’) ename,mgr,deptno
FROM emp
START WITH ename=‘KING’
CONNECT BY PRIOR empno=mgr;
4.产生一个公司组织图表显示经理层次。从最顶级的人开始,排除所有job为CLERK的人,还要排除FORD和那些对FORD报告的雇员。
SELECT LPAD(ename, LENGTH(ename)+(LEVEL-1)2,’’) ename,mgr,deptno
FROM emp
WHERE job<>‘CLERK’
START WITH ename=‘KING’
CONNECT BY PRIOR empno=mgr
AND ename<>'FORD';
第11章 数据操作与事务控制
练习1
1.向部门表新增一个部门,部门编号为50,部门名称为HR,工作地点为SY。
INSERT INTO dept
VALUES(50,‘HR’,‘SY’);
2.向部门表新增一个部门,部门编号为60,部门名称为MARKET。
INSERT INTO dept(deptno,dname)
VALUES(‘60’,‘MARKET’);
练习2
1.向员工表中新增一个员工,员工编号为8888,姓名为BOB,岗位为CLERK,经理为号7788,入职日期为1985-03-03,薪资3000,奖金和部门为空。
INSERT INTO emp
VALUES(8888,‘BOB’,‘CLERK’,‘7788’,‘03-3月-1985’,3000,NULL,null);
练习3
1.使用CREATE TABLE emp_back as
SELECT * FROM EMP WHERE 1=0,创建 emp_back表,拷贝下来即可。
CREATE TABLE emp_back
as
SELECT *
FROM EMP
WHERE 1=0;
2.把emp表中入职日期大于1982年1月1日之前的员 工信息复制到emp_back表中。
INSERT INTO emp_back
SELECT *
FROM emp
WHERE hiredate>=‘01-1月-82’;
练习4
1.修改部门20的员工信息,把82年之后入职的员工入职日期向后调整10天
UPDATE emp
SET hiredate=hiredate+10
WHERE deptno=20
AND hiredate>‘31-12月-81’;
2.修改奖金为null的员工,奖金设置为0
UPDATE emp
SET comm=0
WHERE comm IS NULL;
3.修改工作地点在NEW YORK或CHICAGO的员工工资,工资增加500
UPDATE emp
SET sal=sal+500
WHERE deptno IN
(SELECT deptno
FROM dept
WHERE loc
IN ('CHICAGO','NEW YORK'));
练习5
1.重复做一下刚才的案例。
ALTER TABLE emp_back
ADD(dname varchar2(14));
UPDATE emp_back e
SET dname =
(SELECT dname
FROM dept d
WHERE deptno=e.deptno);
练习6
1.删除经理编号为7566的员工记录
DELETE FROM emp
WHERE mgr=7566;
2.删除工作在NEW YORK的员工记录
DELETE FROM emp
WHERE deptno IN
(SELECT deptno
FROM dept
WHERE loc='NEW YORK');
3.删除工资大于所在部门平均工资的员工记录
DELETE FROM emp
WHERE sal>
(SELECT AVG(sal)
FROM emp
WHERE deptno=e.deptno);
练习7
分析如下语句序列,哪些语句会结束事务?
INSERT…
UPDATE…
INSERT
ROLLBACK;
DELETE…
DELETE…
SELECT…
COMMIT…
INSERT…
INSERT…
DELETE…
GRANT…
INSERT…
SELECT;
练习8
1.test表为空表,分析如下语句操作后,最后test表的状态。
INSERT INTO test(id,name) values(1, ‘a’);
INSERT INTO test(id,name) values(2, ‘b’);
SAVEPOINT s1;
INSERT INTO test(id,name) values(3, ‘c’);
INSERT INTO test(id,name) values(4, ‘d’);
DELETE FROM test WHERE id in (1,3);
ROLLBACK TO s1; --回滚到保存点s1,后两条数据插入无效
DELETE FROM test WHERE id in (2,4);
COMMIT; --将所有修改写入数据库
ROLLBACK; --所有操作已经提交,不能回滚
课后作业
1.使用如下语句,创建学生表student和班级表class
create table student ( --学生表
xh char(4),--学号
xm varchar2(10),--姓名
sex char(2),--性别
birthday date,--出生日期
sal number(7,2), --奖学金
studentcid number(2) --学生班级号
)
Create table class ( --班级表
classid number(2), --班级编号
cname varchar2(20),--班级名称
ccount number(3) --班级人数
)
2.基于上述学生表和班级表,完成如下问题
(1)添加三个班级信息为:1,JAVA1班,null
2,JAVA2班,null
3,JAVA3班,null
INSERT INTO class(classid,cname,ccount)
VALUES(1,‘java1班’,NULL);
INSERT INTO class(classid,cname,ccount)
VALUES(2,‘java2班’,NULL);
INSERT INTO class(classid,cname,ccount)
VALUES(3,‘java3班’,NULL);
(2)添加学生信息如下:‘A001’,‘张三’,‘男’,‘01-5月-05’,100,1
INSERT INTO student
VALUES(‘A001’,‘张三’,‘男’,‘01-5月-05’,100,1);
(3)添加学生信息如下:‘A002’,‘MIKE’,‘男’,‘1905-05-06’,10
INSERT INTO student
VALUES(‘A002’,‘MIKE’,‘男’,TO_DATE(‘1905-05-06’,‘YYYY-MM-DD’),10,NULL);
(4)插入部分学生信息: ‘A003’,‘JOHN’,‘女’
INSERT INTO student(xh,xm,sex)
VALUES(‘A003’,‘JOHN’,‘女’);
(5)将A001学生性别修改为’女’
UPDATE student
SET sex='女'
WHERE xh=‘A001’;
(6)将A001学生信息修改如下:性别为男,生日设置为1980-04-01
UPDATE student
SET sex='男',birthday=TO_DATE('1980-04-01','YYYY-MM-DD')
WHERE xh=‘A001’;
(7)将生日为空的学生班级修改为java3班
UPDATE student
SET studentcid=
(SELECT classid
FROM class
WHERE cname='java3班')
WHERE birthday IS NULL;
(8)请使用一条SQL语句,使用子查询,更新班级表中每个班级的人数字段
UPDATE CLASS c
SET ccount=
(SELECT COUNT(*)
FROM student s
WHERE c.classid= s.studentcid);
3.使用如下语句,建立以下表
CREATE TABLE copy_emp (
empno number(4),
ename varchar2(20),
hiredate date default sysdate ,
deptno number(2),
sal number(8,2))
4.在第三题表的基础上,完成下列问题
(1)在表copy_emp中插入数据,要求sal字段插入空值,部门号50,参加工作时间为2000年1月1日,其他字段随意
INSERT INTO copy_emp
VALUES(1,‘张三’,‘01-1月-2000’,50,NULL);
(2)在表copy_emp中插入数据,要求把emp表中部门号为10号部门
的员工信息插入
INSERT INTO copy_emp
SELECT empno,ename,hiredate,deptno,sal
FROM emp
WHERE deptno=10;
(3)修改copy_emp表中数据,要求10号部门所有员工涨20%的工资
UPDATE copy_emp
SET sal=sal*1.2
WHERE deptno=10;
(4)修改copy_emp表中sal为空的记录,工资修改为平均工资
UPDATE copy_emp
SET sal=
(SELECT AVG(sal)
FROM copy_emp)
WHERE sal IS NULL;
(5)把工资为平均工资的员工,工资修改为空
UPDATE copy_emp
SET sal=NULL,hiredate=default
WHERE sal=
(SELECT AVG(sal)
FROM copy_emp);
(6)另外打开窗口2查看以上修改
修改无效
(7)执行commit,窗口2中再次查看以上信息
COMMIT;
修改有效
(8)删除工资为空的员工信息
DELETE FROM copy_emp
WHERE sal IS NULL;
(9)执行rollback
ROLLBACK;
第13章 创建和维护表
练习1
1.学校想做一个选课系统,其中涉及到课程表,学生表,请分别创建这两个表,自己思考表中应有的列及数据类型。
CREATE TABLE student(
xh CHAR(4),
xm VARCHAR(10),
sex CHAR(2),
birth DATE,
classid BUMBER(2));
CREATE TABLE course(
courseno NUMBER(4),
coursename CHAR(30),
teacher CHAR(10),);
练习2
1.通过子查询的方式创建一个表dept10,该表保存10号部门的员工数据。
CREATE TABLE dept10
AS
SELECT *
FROM emp
WHERE deptno=10;
练习3
1.在员工表中添加一个性别列,列名为gender,类型为char(2),默认值为“男”
ALTER TABLE emp
ADD gender CHAR(2)
DEFAULT ‘男’;
2.修改员工表中性别列的数据类型为char(4)
ALTER TABLE emp
MODIFY gender CHAR(4);
3.修改员工表中性别列的默认值为“女”
ALTER TABLE emp
MODIFY gender CHAR(4) DEFAULT’女’ ;
4.删除员工表中的性别列
ALTER TABLE emp
DROP (gender);
课后作业
1.请分析按照以下要求都需要建立什么类型的字段?
– (1)最大2000个字节定长字符串
CHAR(2000)
– (2)如果输入‘张三’ 后添空格6个
CHAR(10)
– (3)性别输入’男’或’女’
CHAR(2)
– (4)最大4000个字节变长字符串
VARCHAR2
– (5)如果在数据库中输入’张三’则显示数据’张三’
NVARCHAR2
– (6)表示数字范围为- 10的125次方到10的126次方, 可以表示小数 也可以表示整数 NUMBER
– (7)最大表示4位整数 -9999 到 9999
NUMBER(4)
– (8)表示5位有效数字 2位小数的 一个小数 -999.99 到 999.99
NUMBER(5,2)
– (9)包含年月日和时分秒
DATE(yyyymmddhhmiss)
– (10)包含年月日和时分秒毫秒
DATE(yyyymmddhhmissms)
– (11)二进制大对象图像/声音
BLOB
2.创建表date_test,包含列d,类型为date型。试向date_test表中插入两条记录,一条当前系统日期记录,一条记录为“1998-08-18”。
CREATE TABLE date_test(
d DATE
);
INSERT INTO date_test
VALUES(sysdate);
INSERT INTO date_test
VALUES(TO_DATE(‘1998-08-18’,‘yyyy-mm_dd’));
3.创建与dept表相同表结构的表dtest,将dept表中部门编号在40之前的信息插入该表
CREATE TABLE dtest
AS
SELECT *
FROM dept
WHERE deptno<40;
4.创建与emp表结构相同的表empl,并将其部门编号为前30号的员工信息复制到empl表。
CREATE TABLE emp1
AS
SELECT *
FROM emp
WHERE deptno<30;
5.试为学生表student增加一列学生性别gender 默认值 “女”。
ALTER TABLE student
ADD(gender CHAR(2) DEFAULT’女’);
6.试修改学生姓名列数据类型为定长字符型10位。
ALTER TABLE student
MODIFY(xm CHAR(10));
第14章 约束
课后作业
1.简述5种约束的含义。
(1)NOT NULL约束 :也叫非空约束,确保被约束列的所有行记录都不能为空值。
(2) UNIQUE约束:也叫唯一约束,用来确保表中的某一列或者某几列组合的所有行数据必须唯一,定义UNIQUE约束的列 (或列组合) 被称为唯一键。
(3) PRIMARY KEY约束:主键约束,用来确保表中的某一列或者某几列组合的所有行数据必须唯一,并且确保作为主键一部分的列不能包含空值;
(4)FOREIGN KEY,也叫外键约束,外键确保了相关联的两个字段的关系:
(5)CHECK约束,也叫检查性约束,确保某个列的所有行数据都必须满足的条件
2.创建学生关系sc,包括属性名:
– 选课流水号 数值型 主键;
– 学生编号 非空 外键
– 课程编号 非空 外键;
– 成绩 0-100之间;
CREATE TABLE sc(
selectno NUMBER PRIMARY KEY,
studentno VARCHAR(10) NOT NULL
CONSTRAINT student_studentno_fk REFERENCES student(studentno),
courseno VARCHAR(10) NOT NULL
CONSTRAINT course_courseno_fk REFERENCES course(courseno),
grade NUMBER
CONSTRAINT sc_grade_ck CHECK(grade between 0 and 100));
3.创建copy_emp,要求格式同emp表完全一样,不包含数据。
CREATE TABLE copy_emp
AS
SELECT *
FROM emp
WHERE 1=2;
4.创建copy_dept,要求格式同dept表完全一样,不包含数据。
CREATE TABLE copy_dept
AS
SELECT *
FROM dept
WHERE 1=2;
5.设置copy_emp 表中外键deptno,参照copy_dept中deptno,语句能否成功,为什么?
ALTER TABLE copy_emp
ADD CONSTRAINT pk_deptno PRIMARY KEY(deptno) REFERENCES copy_dept(deptno);
不能,因为已经关联了dept中的外键。
6.追加copy_dept表中主键deptno
ALTER TABLE copy_dept
ADD CONSTRAINT pk_depno PRIMARY KEY(deptno)
第15章 视图
练习1
1.创建一个视图,通过该视图可以查询到工资在2000-5000内并且姓名中包含有A的员工编号,姓名,工资。
CREATE VIEW empv
AS
SELECT empno, ename, sal
FROM emp
WHERE sal BETWEEN 2000 AND 5000
AND ename LIKE ‘%A%’;
2.通过上述创建的视图查询数据
SELECT *
FROM empv;
练习2
1.创建一个视图,通过该视图可以查询到工作在NEW YORK和CHICAGO的员工编号,姓名,部门编号,入职日期。
CREATE VIEW ncemp
AS
SELECT empno,ename,e.deptno,hiredate
FROM emp e
JOIN dept d
ON e.deptno=d.deptno
AND loc IN(‘NEW YORK’,‘CHICAGO’);
2.创建一个视图,通过该视图可以查询到每个部门的部门名称及最低工资。
CREATE VIEW empv2
AS
SELECT dname,min(e.sal) min_sal
FROM emp e
JOIN dept d
ON e.deptno=d.deptno
GROUP BY dname;
3.通过如上视图,查询每个部门工资最低的员工姓名及部门名称
SELECT e.ename, v.dname
FROM empv2 v
JOIN dept d
ON v.dname=d.dname
JOIN emp e
ON d.deptno=e.deptno
WHERE sal=v.min_sal;
课后作业
1.创建视图v_emp_20,包含20号部门的员工编号,姓名,年薪列(年薪=12*(工资+奖金);
CREATE VIEW v_emp_20
AS
SELECT empno,ename,12*(sal+nvl(comm,0)) income
FROM emp;
2.从视图v_emp_20中查询年薪大于1万元员工的信息;
SELECT *
FROM v_emp_20
WHERE income>10000;
3.请为工资大于2000的员工创建视图,要求显示员工的部门信息,职位信息,工作地点;
CREATE VIEW empsal2000
AS
SELECT e.deptno,job,loc
FROM emp e
JOIN dept d
ON e.deptno=d.deptno
WHERE e.sal>2000;
4.针对以上视图执行insert,update,delete,语句能否成功,为什么?
在简单视图上可以执行 DML 操作;
(1)可以通过视图删除基表中数据,只要视图中不出现以下情况:
Group 函数;
GROUP BY 子句;
DISTINCT 关键字;
(2)可以通过视图修改基表中数据,只要视图中不出现以下情况:
GROUP函数、GROUP BY子句,DISTINCT关键字;
使用表达式定义的列;
ROWNUM 伪列;
(3)可以通过视图向基表插入数据,只要视图中不出现以下情况:
GROUP函数、GROUP BY子句,DISTINCT关键字;
使用表达式定义的列;
ROWNUM 伪列;
基表中未在视图中选择的其它列定义为非空并且没有默认值;
第16章 序列、索引、同义词
练习1
1.创建一个序列,该序列起始值从1开始,无最大值,增量是1,不循环。
CREATE SEQUENCE asd_seq;
2.查询序列的当前值及下一个值
SELECT asd_seq.currval
FROM DUAL;
SELECT asd_seq.nextval
FROM DUAL;
3.使用第1题所建的序列,向部门表中插入两条记录,部门编号使用序列值,部门名称分别 为:Education、Market,城市分别为:DALLAS、WASHTON
INSERT INTO dept
VALUES(asd_seq.nextval,‘education’,‘dallas’);
INSERT INTO dept
VALUES(asd_seq.nextval,‘maeket’,‘washton’);
练习2
1.使用子查询的方式,创建test表。
CREATE TABLE test
AS
SELECT *
FROM emp;
2.快速复制test表中的数据,复制到100w条左右
INSERT INTO test
SELECT *
FROM emp;
3.更新test表中的empno字段为rownum
UPDATE test
SET empno=rownum;
4.查询test中empno为800000的记录值,记录查询执行时间。
SELECT *
FROM test
WHERE empno=800000;
5.在test表的empno字段上创建索引
CREATE INDEX IDX_TEST_EMPNO
ON test(empno);
6.重新执行第4题,对比查询时间
SELECT *
FROM TEST
WHERE empno=800000;
练习3
1.有如下关系模式,
– student(sno,sname,gender,birthday,email);–学生
– course(cno,cname,type,credit);–课程
– sc(sno,cno,grade);–选课
– 试分析哪些列上适合创建索引?
student:sno
course:cno
course:sno
课后作业
1.创建序列,起始位1,自增为1,最小值为1,最大值为9999
CREATE SEQUENCE test_seq2
START WITH 1
INCREMENT BY 1
MINVALUE 1
MAXVALUE 9999
CYCLE
CACHE 10;
2.创建序列,起始值为50,每次增加5;
CREATE SEQUENCE test_seq3
START WITH 50
INCREMENT BY 5
MINVALUE 50
NOCYCLE
CACHE 10;
3.在表copy_dept中插入记录,其中部门号码采用上一步中创建的序列生成;
INSERT INTO copy_dept(deptno,dname,loc)
VALUES(test_seq2.nextval,‘dd’,‘dd’);
4.请为工资创建索引,比较<10000,>1000,与round(sal)>10000,哪个索引有效,哪个索引无效;
CREATE INDEX indexsal
ON emp(sal);
SELECT sal
FROM emp
WHERE sal<10000; --速度较慢
SELECT sal
FROM emp
WHERE sal>1000; --速度较快
SELECT sal
FROM emp
WHERE round(sal)>10000; --有效
5.创建表,采用“create table copy_emp_index as select * from emp”,生成500万条数据,把其中的“员工号”字段修改为唯一;
CREATE TABLE copy_emp_index
AS
SELECT *
FROM emp;
ALTER TABLE copy_emp_index
ADD CONSTRAINT copy_emp_index_tb UNIQUE (empno);
6.查询表copy_emp_index表中员工号为200001的员工姓名,工资,记录执行时间;
SELECT ename,sal
FROM copy_emp_index
WHERE empno=200001;
7.在copy_emp_index表的empno字段上创建索引,再次执行第6题语句,记录执行时间并做对比;
CREATE SEQUENCE test_seq
START WITH 1
INCREMENT BY 1
MAXVALUE 1000000000000
MINVALUE 1
CYCLE
CACHE 100;
SELECT ename,sal
FROM copy_emp_index
WHERE empno=200001;
第1章 PLSQL基础知识
练习1
1.创建一个匿名块,在屏幕输出‘hello world’
DECLARE
v_hello varchar2(20) :='Hello World';
BEGIN
dbms_output.put_line(v_hello);
END;
练习2
1.写一个块,查询最大的部门编号,并在屏幕上输出该部门编号。
DECLARE
v_deptno dept.deptno%TYPE;
BEGIN
SELECT MAX(dept.deptno)
INTO v_deptno
FROM dept;
dbms_output.put_line(v_deptno);
END;
练习3
1.写一个块,用来向10号部门入职一名新员工,员工编号为当前最大员工编号加1,员工姓名为JAMES,岗位为CLERK,入职日期为当前日期,工资为4000,上级为SMITH,奖金为null
DECLARE
v_empno emp.empno%TYPE;--最大员工编号
v_mgr emp.mgr%TYPE;--上级编号
BEGIN
SELECT MAX(emp.empno)
INTO v_empno
FROM emp;
SELECT empno
INTO v_mgr
FROM emp
WHERE ename='SMITH';
INSERT INTO emp
VALUES(v_empno+1,'JAMES','CLERK',v_mgr,SYSDATE,4000,NULL,10);
COMMIT;
END;
课后作业
1、创建一个匿名块,查询emp表,显示雇员名是’SCOTT‘的薪水,通过DBMS_OUTPUT包来显示。
DECLARE
v_sal emp.sal%TYPE;
BEGIN
SELECT sal
INTO v_sal
FROM emp
WHERE ename='SCOTT';
dbms_output.put_line(v_sal);
END;
2、创建一个匿名块,使用 SQL*Plus的替代变量emp_num (雇员编号),查询emp表,通过外部变量显示对应的雇员名
SELECT *
FROM emp
WHERE empno=&emp_num;
3、创建和emp表结构一样的test表,不要求有数据
CREATE TABLE test
AS
SELECT *
FROM emp
WHERE 1=2;
4、创建pl/sql块,将emp表中最高薪水员工的信息插入到test表中
BEGIN
INSERT INTO test
SELECT *
FROM emp e
WHERE 1>
(SELECT COUNT(*)
FROM emp
WHERE sal>e.sal);
COMMIT;
END;
5、创建pl/sql块,将emp表中员工的平均薪水更新到test表中,并打印平均薪水
DECLARE
v_sal emp.sal%TYPE;
BEGIN
SELECT AVG(sal)
INTO v_sal
FROM emp;
dbms_output.put_line(v_sal);
UPDATE test
SET sal=v_sal;
COMMIT;
END;
第2章 编写控制结构
练习1
1.写SQL语句,向部门表中添加一个字段maxnumber 整型,表示部门编制人数。
ALTER TABLE dept
ADD(maxnumber INTEGER);
2.把10号部门的编制更新为5人。
UPDATE dept
SET maxnumber=5
WHERE deptno=10;
3.写一个块,用来向10号部门入职一名新员工,员工编号为当前最大员工编号加1,员工姓名为TOM,岗位为CLERK,其它字段都为null;当10号部门最大的人数不超过编制人数时,入职成功;当部门的人数超过编制人数时,提示入职失败。
DECLARE
v_empno emp.empno%TYPE;--最大员工编号
v_empnum NUMBER;--部门人数
v_maxnumber dept.maxnumber%TYPE;--编制人数
BEGIN
SELECT MAX(emp.empno)
INTO v_empno
FROM emp;
INSERT INTO emp(empno,ename,job,deptno)
VALUES(v_empno+1,'TOM','CLERK',10);
SELECT maxnumber
INTO v_maxnumber
FROM dept
WHERE deptno=10;
SELECT COUNT(empno)
INTO v_empnum
FROM emp
WHERE deptno=10;
IF v_empnum>v_maxnumber THEN
dbms_output.put_line('入职失败');
ROLLBACK;
ELSE
dbms_output.put_line('入职成功');
COMMIT;
END IF;
END;
练习2
1.使用简单循环,批量入职5名员工,员工编号分别为当前最大编号加1,部门为20号部门,姓名为zs1,zs2…,入职日期为当前日期,其它字段为null,暂时不判断人数是否超编。
DECLARE
v_empno emp.empno%TYPE;--最大员工编号
v_count NUMBER :=1;--计数器
BEGIN
SELECT MAX(emp.empno)
INTO v_empno
FROM emp;
LOOP
INSERT INTO emp(empno,deptno,ename,hiredate)
VALUES(v_empno+v_count,20,'ZS'||to_char(v_count),SYSDATE);
v_count :=v_count+1;
EXIT WHEN v_count>5;
END LOOP;
COMMIT;
END;
练习3
1.使用for循环,遍历员工信息,依次输出每个员工的姓名及部门名称。
BEGIN
FOR emp_record IN
(SELECT ename,dname
FROM emp e,dept d
WHERE e.deptno=d.deptno) LOOP
dbms_output.put_line(emp_record.ename||'的部门是'||emp_record.dname);
END LOOP;
END;
2.使用while循环,遍历员工信息,依次输出每个员工的姓名及部门名称。
DECLARE
v_ename emp.ename%TYPE;
v_dname dept.dname%TYPE;
CURSOR emp_cursor IS
SELECT ename,dname
FROM emp e,dept d
WHERE e.deptno=d.deptno;
BEGIN
OPEN emp_cursor;
FETCH emp_cursor INTO v_ename,v_dname;
WHILE emp_cursor%found LOOP
dbms_output.put_line(v_ename||'的部门是'||v_dname);
FETCH emp_cursor INTO v_ename,v_dname;
END LOOP;
END;
课后作业
1.使用外部替代变量提供雇员的ID,传递该值到PL/SQL块,查询emp表的薪水,如果薪水小于2000的,显示‘挣的不多,需努力’;如果薪水在2000到5000的,显示‘收入还可以,还需努力’;薪水大于5000的显示’挣的挺多了,歇歇吧‘。
DECLARE
v_sal emp.sal%TYPE;
BEGIN
SELECT sal
INTO v_sal
FROM emp
WHERE empno=&ID;
IF v_sal<2000 THEN
dbms_output.put_line('挣的不多,需努力');
ELSIF v_sal BETWEEN 2000 AND 5000 THEN
dbms_output.put_line('收入还可以,还需努力');
ELSIF v_sal>5000 THEN
dbms_output.put_line('挣的挺多了,歇歇吧');
END IF;
END;
2.屏幕上输出1到10(不包括6和8)
DECLARE
v_num NUMBER :=1;
BEGIN
WHILE v_num<=10 LOOP
IF v_num NOT IN(6,8) THEN
dbms_output.put_line(v_num);
END IF;
v_num :=v_num+1;
END LOOP;
END;
3.使用FOR循环和while循环,分别实现练习2的批量员工入职功能。
DECLARE
v_empno emp.empno%TYPE;--最大员工编号
v_count NUMBER :=1;--计数器
BEGIN
SELECT MAX(emp.empno)
INTO v_empno
FROM emp;
FOR v_count IN 1..5 LOOP
INSERT INTO emp(empno,deptno,ename,hiredate)
VALUES(v_empno+v_count,20,'ZS'||to_char(v_count),SYSDATE);
END LOOP;
COMMIT;
END;
DECLARE
v_empno emp.empno%TYPE;--最大员工编号
v_count NUMBER :=1;--计数器
BEGIN
SELECT MAX(emp.empno)
INTO v_empno
FROM emp;
FOR v_count <=5 LOOP
INSERT INTO emp(empno,deptno,ename,hiredate)
VALUES(v_empno+v_count,20,'ZS'||to_char(v_count),SYSDATE);
v_count :=v_count+1;
END LOOP;
COMMIT;
END;
第3章 游标
练习1
读程序,写结果:
1.假设10号部门有3名员工,20号部门有5名员工,30号部门有6名员工。如下代码段执行后,
Declare
v_count Number(2);
Begin
Select Count(empno) Into v_count
From emp Where deptno=10;
IF SQL%Rowcount>0 THEN
Delete From emp Where deptno = 20;
ELSE
Delete From emp Where deptno = 30;
END IF;
dbms_output.PUT_LINE(SQL%Rowcount);
End;
程序输出为:5
2.假设部门表中没有部门编号为60的记录,执行如下代码后,
Begin
Insert Into dept(deptno,dname,loc)
Values(60,’HR’,’SY’);
If SQL%Rowcount>0 Then
dbms_output.PUT_LINE(‘插入部门成功’);
Else
dbms_output.PUT_LINE(‘插入部门失败’);
End If;
End
程序输出为:插入部门成功
BEGIN
DELETE FROM emp where deptno = 100;
dbms_output.PUT_LINE(‘游标所影响的行数:’||SQL%ROWCOUNT);
IF SQL%FOUND THEN
DBMS_output.PUT_LINE('Found为真');
ELSE
DBMS_output.PUT_LINE('Found为假');
END IF;
IF SQL%NOTFOUND then
DBMS_output.PUT_LINE('NotFound为真');
ELSE
DBMS_output.PUT_LINE('NotFound为假');
END IF;
IF SQL%ISOPEN THEN
DBMS_output.PUT_LINE('isOpen为真');
ELSE
DBMS_output.PUT_LINE('isOpen为假');
END IF;
END;
输出结果:
游标所影响的行数:0
Found为假
NotFound为真
isOpen为假
BEGIN
INSERT INTO dept VALUES(2,‘AA’,‘SY’);
dbms_output.PUT_LINE(‘游标所影响的行数:’||SQL%ROWCOUNT);
IF SQL%FOUND THEN
DBMS_output.PUT_LINE('Found为真');
ELSE
DBMS_output.PUT_LINE('Found为假');
END IF;
IF SQL%NOTFOUND then
DBMS_output.PUT_LINE('NotFound为真');
ELSE
DBMS_output.PUT_LINE('NotFound为假');
END IF;
IF SQL%ISOPEN THEN
DBMS_output.PUT_LINE('isOpen为真');
ELSE
DBMS_output.PUT_LINE('isOpen为假');
END IF;
END;
输出结果:
游标所影响的行数:1
Found为真
NotFound为假
isOpen为假
练习2
- 使用游标,完成遍历所有员工姓名和部门名称的操作。
DECLARE
v_ename emp.ename%TYPE;
v_dname dept.dname%TYPE;
v_count NUMBER;
CURSOR emp_cursor
IS
SELECT ename,dname
FROM emp e,dept d
WHERE e.deptno=d.deptno;
BEGIN
SELECT COUNT(empno)
INTO v_count
FROM emp e;
OPEN emp_cursor;
FETCH emp_cursor INTO v_ename,v_dname;
FOR i IN 1..v_count LOOP
dbms_output.put_line(v_ename||'的部门是'||v_dname);
FETCH emp_cursor INTO v_ename,v_dname;
END LOOP;
END;
练习3
1.使用游标属性,完成遍历所有员工姓名和部门名称的操作。
DECLARE
v_ename emp.ename%TYPE;
v_dname dept.dname%TYPE;
CURSOR emp_cursor IS
SELECT ename,dname
FROM emp e,dept d
WHERE e.deptno=d.deptno;
BEGIN
OPEN emp_cursor;
FETCH emp_cursor INTO v_ename,v_dname;
WHILE emp_cursor%found LOOP
dbms_output.put_line(v_ename||'的部门是'||v_dname);
FETCH emp_cursor INTO v_ename,v_dname;
END LOOP;
END;
练习4
1.使用游标和记录联合方式,完成遍历所有员工姓名和部门名称的操作。
DECLARE
CURSOR emp_cursor IS
SELECT ename,dname
FROM emp e,dept d
WHERE e.deptno=d.deptno;
emp_record emp_cursor%ROWTYPE;
BEGIN
OPEN emp_cursor;
FETCH emp_cursor INTO emp_record;
WHILE emp_cursor%found LOOP
dbms_output.put_line(emp_record.ename||'的部门是'||emp_record.dname);
FETCH emp_cursor INTO emp_record;
END LOOP;
END;
2.使用游标式的FOR循环方式,完成遍历所有员工姓名和部门名称的操作。
DECLARE
v_ename emp.ename%TYPE;
v_dname dept.dname%TYPE;
v_count NUMBER;
CURSOR emp_cursor IS
SELECT ename,dname
FROM emp e,dept d
WHERE e.deptno=d.deptno;
BEGIN
SELECT COUNT(empno)
INTO v_count
FROM emp e;
OPEN emp_cursor;
FETCH emp_cursor INTO v_ename,v_dname;
FOR i IN 1..v_count LOOP
dbms_output.put_line(v_ename||'的部门是'||v_dname);
FETCH emp_cursor INTO v_ename,v_dname;
END LOOP;
END;
3.使用不需声明的游标方式,完成遍历所有员工姓名和部门名称的操作。
BEGIN
FOR emp_record IN
(SELECT ename,dname
FROM emp e,dept d
WHERE e.deptno=d.deptno) LOOP
dbms_output.put_line(emp_record.ename||'的部门是'||emp_record.dname);
END LOOP;
END;
练习5
1.使用带参数的游标,分别遍历每个部门的员工姓名及入职日期,要求显示格式如下:
------X号部门的员工列表---------
姓名:xx,入职日期:xx
…………………….
小计:X号部门员工数为:xxx人
------X号号部门的员工列表---------
姓名:xx,入职日期:xx
…………………….
小计:x号部门员工数为:xxx人
------x号号部门的员工列表---------
姓名:xx,入职日期:xx
…………………….
小计:x号部门员工数为:xxx人
DECLARE
v_ename emp.ename%TYPE;
v_hiredate emp.hiredate%TYPE;
v_count NUMBER;
CURSOR emp_cursor1(p_deptno NUMBER) --员工信息
IS
SELECT ename,hiredate
FROM emp
WHERE deptno=p_deptno;
BEGIN
dbms_output.put_line('------10号号部门的员工列表---------');
OPEN emp_cursor1(10);
FETCH emp_cursor1 INTO v_ename,v_hiredate;
WHILE emp_cursor1%found LOOP
dbms_output.put_line('姓名:'||v_ename||',入职日期:'||v_hiredate);
FETCH emp_cursor1 INTO v_ename,v_hiredate;
END LOOP;
CLOSE emp_cursor1;
SELECT COUNT(empno)
INTO v_count
FROM emp e
WHERE deptno=10;
dbms_output.put_line('…………………….');
dbms_output.put_line('小计:10号部门员工数为:'||v_count||'人');
dbms_output.put_line('');
dbms_output.put_line('------30号号部门的员工列表---------');
OPEN emp_cursor1(30);
FETCH emp_cursor1 INTO v_ename,v_hiredate;
WHILE emp_cursor1%found LOOP
dbms_output.put_line('姓名:'||v_ename||',入职日期:'||v_hiredate);
FETCH emp_cursor1 INTO v_ename,v_hiredate;
END LOOP;
CLOSE emp_cursor1;
SELECT COUNT(empno)
INTO v_count
FROM emp e
WHERE deptno=30;
dbms_output.put_line('…………………….');
dbms_output.put_line('小计:30号部门员工数为:'||v_count||'人');
dbms_output.put_line('');
dbms_output.put_line('------没有号号部门的员工列表---------');
SELECT ename,hiredate
INTO v_ename,v_hiredate
FROM emp
WHERE deptno IS NULL;
dbms_output.put_line('姓名:'||v_ename||',入职日期:'||v_hiredate);
SELECT COUNT(empno)
INTO v_count
FROM emp e
WHERE deptno IS NULL;
dbms_output.put_line('…………………….');
dbms_output.put_line('小计:没有部门员工数为:'||v_count||'人');
dbms_output.put_line('');
END;
DECLARE
v_ename emp.ename%TYPE;
v_hiredate emp.hiredate%TYPE;
v_count NUMBER;
p_deptno emp.deptno%TYPE;
CURSOR dept_cursor --部门
IS
SELECT DISTINCT deptno
FROM dept;
CURSOR emp_cursor(p_deptno dept.deptno%Type) --员工信息
IS
SELECT ename,hiredate
FROM emp
WHERE deptno=p_deptno;
BEGIN
FOR dept_record IN dept_cursor LOOP
dbms_output.put_line('------'||dept_record.deptno||'号部门的员工列表---------');
FOR emp_record IN emp_cursor(dept_record.deptno) LOOP
dbms_output.put_line('姓名:'||emp_record.ename||',入职日期:'||emp_record.hiredate);
END LOOP;
SELECT COUNT(*)
INTO v_count
FROM emp e
WHERE deptno=dept_record.deptno;
dbms_output.put_line('…………………….');
dbms_output.put_line('小计:'||dept_record.deptno||'号部门员工数为:'||v_count||'人');
dbms_output.put_line('');
END LOOP;
END;
练习6
如下两个块代码执行后结果分别是?
DECLARE
CURSOR sal_cursor IS
SELECT sal FROM emp WHERE deptno = 30 FOR UPDATE OF sal NOWAIT;
BEGIN
FOR emp_record IN sal_cursor LOOP
UPDATE emp SET sal = emp_record.sal * 1.10;
END LOOP;
END;
执行结果:所有员工的工资都变成了30号部门最后一名员工的工资的110%。
DECLARE
CURSOR sal_cursor IS
SELECT sal FROM emp WHERE deptno = 30 FOR UPDATE OF sal NOWAIT;
BEGIN
FOR emp_record IN sal_cursor LOOP
UPDATE emp SET sal = emp_record.sal * 1.10 WHERE CURRENT OF sal_cursor;
END LOOP;
END;
执行结果: 30号部门的员工工资上升10%。
第4章 异常处理
练习1
1.编写一个块,实现员工入职功能:其中员工编号为7839,姓名为张三,工资为3000,入职日期为系统当前日期,职位为CLERK,奖金为null,所在部门为SALES ,上级经理为JONES ,要求写出所有可能发生的异常处理程序。
DECLARE
v_mgrno emp.empno%Type;
v_deptno dept.deptno%Type;
BEGIN
SELECT empno
INTO v_mgrno
FROM emp
WHERE ename='JONES';
SELECT deptno
INTO v_deptno
FROM dept
WHERE dname='SALES';
INSERT INTO emp(empno,ename,job,hiredate,mgr,sal,comm,deptno)
VALUES(7839,'张三','CLERK',SYSDATE,v_mgrno,3000,NULL,v_deptno);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
ROLLBACK;
dbms_output.put_line('员工编号重复,不能办理入职');
END;
练习2
1.编写第4章 异常处理一个匿名块,完成删除一个部门的功能,要有相应的异常处理程序。
DECLARE
e_haveempexception EXCEPTION;
PRAGMA EXCEPTION_INIT(e_haveempexception ,-02292);
BEGIN
DELETE FROM dept WHERE deptno=10;
COMMIT;
dbms_output.put_line('操作成功');
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
dbms_output.put_line('该部门下存在员工,不能删除部门');
END;
练习3
- 编写一个匿名块,分别对部门做一个查询、插入、修改、删除操作,验证这几个操作执行后的SQLCODE和SQLERRM结果。
DECLARE
v_dname dept.dname%TYPE;
BEGIN
SELECT dname
INTO v_dname
FROM dept
WHERE deptno = 10;
dbms_output.put_line('查询成功的SQLCODE:'||SQLCODE);
dbms_output.put_line('查询成功的SQLerrm:'||SQLERRM);
SELECT dname
INTO v_dname
FROM dept
WHERE deptno = 1;
INSERT INTO dept(deptno,dname,loc)
VALUES(1,'a',NULL);
dbms_output.put_line('插入成功的SQLCODE:'||SQLCODE);
dbms_output.put_line('插入成功的SQLerrm:'||SQLERRM);
INSERT INTO dept(deptno,dname,loc)
VALUES(1,'b',NULL);
UPDATE dept
SET dname = dname ;
dbms_output.put_line('更新成功的SQLCODE:'||SQLCODE);
dbms_output.put_line('更新成功的SQLerrm:'||SQLERRM);
DELETE dept SET deptno = 1 ;
dbms_output.put_line('删除成功的SQLCODE:'||SQLCODE);
dbms_output.put_line('删除成功的SQLerrm:'||SQLERRM);
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('查询失败的SQLCODE:'||SQLCODE);
dbms_output.put_line('查询失败的SQLerrm:'||SQLERRM);
END;
练习4
- 修改员工入职的功能,当入职部门的人数超编时,提示用户部门以超编,不能再录入员工。
DECLARE
v_max dept.maxnumber%TYPE;
v_current v_max%TYPE;
v_empno emp.empno%TYPE;
e_havemaxnumber EXCEPTION;
BEGIN
--查询10号部门的编制
SELECT maxnumber
INTO v_max
FROM dept
WHERE deptno = 10;
--查询10号部门的当前人数
SELECT COUNT(empno)
INTO v_current
FROM emp
WHERE deptno = 10;
IF v_max-v_current > 0 THEN
--说明有剩余编制,可以实现入职操作
SELECT MAX(empno)
INTO v_empno
FROM emp;
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno)
VALUES(v_empno+1,'TOM','CLERK',NULL,NULL,NULL,NULL,10);
COMMIT;
dbms_output.put_line('入职成功');
ELSE
RAISE e_havemaxnumber;
END IF;
EXCEPTION
WHEN e_havemaxnumber THEN
dbms_output.put_line('当前部门编制人数已满,不能继续入职操作');
END;
课后作业
1、创建表message(result varchar2(100)),存放状态信息
CREATE TABLE message(RESULT VARCHAR(100));
2、写PL/SQL块,传递不同的sal值到块中,根据传递的sal值进行查询:
当emp表中没有该sal值时,引发异常,在异常部分将‘没有雇员挣sal的薪水’信息插入到message表中,并显示该信息;
当emp表中有多于一个sal值时,引发异常,在异常部分将‘太多的雇员挣sal的薪水’信息插入到message表中,并显示该信息;
当只有一个雇员具有该工资时,则输出雇员名和工资。
DECLARE
e_noequal EXCEPTION;
e_toomanyupper EXCEPTION;
v_ename emp.ename%TYPE;
v_count NUMBER;
BEGIN
SELECT COUNT(empno)
INTO v_count
FROM emp
WHERE sal = &sal;
IF v_count = 0 THEN
RAISE e_noequal;
ELSIF v_count >1 THEN
RAISE e_toomanyupper;
ELSE
SELECT ename INTO v_ename FROM emp WHERE sal = &sal;
dbms_output.put_line(v_ename ||','|| &sal);
END IF;
EXCEPTION
WHEN e_noequal THEN
INSERT INTO message
VALUES('没有雇员挣sal的薪水');
COMMIT;
dbms_output.put_line('没有雇员挣sal的薪水');
WHEN e_toomanyupper THEN
INSERT INTO message
VALUES('太多的雇员挣sal的薪水');
COMMIT;
dbms_output.put_line('太多的雇员挣sal的薪水');
END;
3、根据员工号,获得员工到目前为止参加工作年限(保留到整数),员工号不存在时提示“此员工号不存在”
DECLARE
v_year NUMBER(3);
BEGIN
SELECT ROUND(months_between(SYSDATE,hiredate)/12)
INTO v_year
FROM emp WHERE empno = &empno;
dbms_output.put_line(v_year);
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('此员工号不存在') ;
END;
4、编写PL/SQL块,使用SELECT语句将管理者编号为空的员工的姓名及工作编号显示出来,如果符合条件的员工多于一人,则返回字符串“最高管理者人员过多!”字符串,如果找到没有符合条件的记录,则返回字符串“没有最高管理者,请指定”
DECLARE
v_ename emp.ename%TYPE;
v_job emp.job%TYPE;
BEGIN
SELECT ename,job
INTO v_ename,v_job
FROM emp
WHERE mgr IS NULL;
dbms_output.put_line(v_ename || ',' || v_job);
EXCEPTION
WHEN too_many_rows THEN
dbms_output.put_line('最高管理者人员过多');
WHEN no_data_found THEN
dbms_output.put_line('没有最高管理者,请指定');
END;
5、获得每个部门的平均工资,如果平均工资大于15000,视为用户定义的异常,提示“该部门的平均工资过高”
DECLARE
e_high_sal EXCEPTION;
BEGIN
FOR v_count IN
(SELECT deptno,AVG(sal) avgsal
FROM emp
GROUP BY deptno) LOOP
IF v_count.avgsal>15000 THEN
RAISE e_high_sal;
dbms_output.put_line(v_count.deptno);
END IF;
END LOOP;
EXCEPTION
WHEN e_high_sal THEN
dbms_output.put_line('该部门的平均工资过高');
END;
6、统计大于平均薪水的员工数量,如果数量大于5,触发e_too_many异常,显示’大于平均工资的人数不少’;如果数量小于等于5,触发e_too_low异常,显示’大于平均工资的人数太少
DECLARE
v_count_empno NUMBER;
v_avg_sal emp.sal%TYPE;
e_too_many EXCEPTION;
e_too_low EXCEPTION;
BEGIN
SELECT AVG(sal)
INTO v_avg_sal
FROM emp;
SELECT COUNT(empno)
INTO v_count_empno
FROM emp
WHERE sal>v_avg_sal;
IF v_count_empno<=5 THEN
RAISE e_too_low;
ELSIF v_count_empno>5 THEN
RAISE e_too_many;
END IF;
EXCEPTION
WHEN e_too_many THEN
dbms_output.put_line('大于平均工资的人数太少');
WHEN e_too_low THEN
dbms_output.put_line('大于平均工资的人数不少');
END;
第5章 存储过程
练习1
1.写一个存储过程getAllDept,遍历所有部门。
CREATE OR REPLACE PROCEDURE getAllDept
IS
CURSOR dept_cursor
IS
SELECT deptno,dname ,loc
FROM dept;
BEGIN
FOR dept_record IN dept_cursor LOOP
dbms_output.put_line('编号为'||dept_record.deptno ||'部门的名称为:'||dept_record.dname);
END LOOP;
END;
–调用
BEGIN
getAllDept;
END;
练习2
1.写一个存储过程addDept,实现添加一个部门功能,部门编号为当前最大部门编号加1,其它信息通过in模式参数传入。
CREATE OR REPLACE PROCEDURE addDept(p_dname dept.dname%TYPE,
p_loc dept.loc%TYPE)
IS
v_deptno dept.deptno%TYPE;
BEGIN
SELECT MAX(deptno)
INTO v_deptno from dept;
INSERT INTO dept(deptno,dname,loc)
VALUES(v_deptno+1,p_dname,p_loc);
IF SQL%ROWCOUNT>0 THEN
COMMIT;
dbms_output.put_line('新建部门成功');
ELSE
ROLLBACK;
dbms_output.put_line('新建部门失败'||SQLERRM);
END IF;
END;
–调用
BEGIN
addDept('AAA','AAA');
END;
3.写一个存储过程updateDept,实现根据编号修改部门功能。
CREATE OR REPLACE PROCEDURE updateDept(p_deptno IN dept.deptno%TYPE,
p_dname IN dept.dname%TYPE,
p_loc IN dept.loc%TYPE)
IS
v_count NUMBER(2);
BEGIN
SELECT COUNT(deptno)
INTO v_count
FROM dept
WHERE deptno=p_deptno;
IF v_count>0 THEN
UPDATE dept
SET dname=p_dname,loc=p_loc
WHERE deptno=p_deptno;
IF SQL%ROWCOUNT>0 THEN
COMMIT;
dbms_output.put_line('修改部门成功');
ELSE
ROLLBACK;
dbms_output.put_line('修改部门失败'||SQLERRM);
END IF;
ELSE
dbms_output.put_line(p_deptno||'是一个无效的部门编号');
END IF;
END;
–调用
BEGIN
updateDept(81,'BBB','BBB');
END;
SELECT * FROM dept;
2.写一个存储过程getDeptByID,实现根据编号读取部门信息功能。
CREATE OR REPLACE PROCEDURE getDeptByID(p_deptno IN OUT dept.deptno%TYPE,
p_dname OUT dept.dname%TYPE,
p_loc OUT dept.loc%TYPE)
IS
BEGIN
SELECT dname,loc
INTO p_dname,p_loc
FROM dept
WHERE deptno=p_deptno;
dbms_output.put_line('部门号:'||p_deptno||' 名称:'||p_dname||' 地点:'||p_loc);
END;
–调用
DECLARE
p_deptno dept.deptno%TYPE :=10;
p_dname dept.dname%TYPE;
p_loc dept.loc%TYPE;
BEGIN
getDeptByID(p_deptno,p_dname,p_loc);
END;
4.写一个存储过程delDept,实现根据部门编号删除部门功能,当部门中存在员工时,提示该部门不能删除。
CREATE OR REPLACE PROCEDURE delDept(p_deptno IN dept.deptno%TYPE)
IS
v_count NUMBER(2);
BEGIN
SELECT COUNT(empno)
INTO V_count
FROM emp
WHERE deptno=p_deptno;
IF v_count >0 THEN
dbms_output.put_line('该部门下存在员工,不能删除');
ELSE
DELETE FROM dept WHERE deptno=p_deptno;
IF SQL%ROWCOUNT >0 THEN
COMMIT;
dbms_output.put_line('删除部门成功');
ELSE
ROLLBACK;
dbms_output.put_line('删除部门失败'||SQLERRM);
END IF;
END IF;
END;
–调用
BEGIN
delDept(10);
END;
5.写一个存储过程getAllEmpByID,实现根据部门编号查询部门所有员工信息功能,要求带分页功能。
CREATE OR REPLACE PROCEDURE getAllEmpByID(p_deptno IN dept.deptno%TYPE,
p_pageNo IN NUMBER,
p_pageCount IN NUMBER)
IS
CURSOR emp_cur
IS
SELECT b.*
FROM (SELECT ROWNUM rn,ename,dname
FROM emp e,dept d
WHERE e.deptno=d.deptno
AND e.deptno=p_deptno
AND ROWNUM<=p_pageNo*p_pageCount) b
WHERE rn>(p_pageNo-1)*p_pageCOunt;
BEGIN
FOR emp_record IN emp_cur LOOP
dbms_output.put_line(p_deptno||'号部门员工为:'||emp_record.ename);
END LOOP;
END;
–调用
BEGIN
getAllEmpByID(10,3,1);
END;
6.写一个块,分别调用上述过程。
BEGIN
addDept('AAA','AAA');
END;
BEGIN
updateDept(81,'BBB','BBB');
END;
DECLARE
p_deptno dept.deptno%TYPE :=10;
p_dname dept.dname%TYPE;
p_loc dept.loc%TYPE;
BEGIN
getDeptByID(p_deptno,p_dname,p_loc);
END;
BEGIN
delDept(10);
END;
BEGIN
getAllEmpByID(10,3,1);
END;
练习3
1.写一个存储过程changeDept,实现部门调转功能,传入参数:员工编号、调入部门编号;传出参数:调转是否成功,成功返回ture,否则返回flase。实现该功能时,需要判断传入的员工编号及部门编号是否是有效的;同时修改emp表的deptno字段,并且在员工历史岗位表中插入一条新记录。
CREATE OR REPLACE PROCEDURE chageDept(p_empno IN emp.empno%type,
p_olddeptno IN emp.deptno%TYPE,
p_newdeptno IN emp.deptno%TYPE,
p_date IN emp_jobhistory.chagedate%TYPE,
p_type IN emp_jobhistory.chagetype%TYPE,
p_res IN emp_jobhistory.chagereason%TYPE,
p_flag OUT BOOLEAN)
IS
v_ecount NUMBER(2);
v_dcount NUMBER(2);
v_maxid emp_jobhistory.id%TYPE;
BEGIN
p_flag := FALSE;
--判断传入的员工编号和部门编号是否有效
SELECT COUNT(empno)
INTO v_ecount
FROM emp
WHERE empno=p_empno AND deptno=p_olddeptno;
IF v_ecount<=0THEN
dbms_output.put_line('员工编号或部门编号无效');
RETURN;
END IF;
--判断新部门编号是否有效
SELECT COUNT(deptno)
INTO v_dcount
FROM dept
WHERE deptno=p_newdeptno;
IF v_dcount<=0THEN
dbms_output.put_line('要调入的部门编号无效');
RETURN;
END IF;
--修改员工当前部门编号
UPDATE emp
SET deptno = p_newdeptno
WHERE empno = p_empno;
IF SQL%ROWCOUNT<=0 THEN
ROLLBACK;
dbms_output.put_line('调转失败');
RETURN;
END IF;
--读取最大ID
SELECT MAX(ID)
INTO v_maxid
FROM emp_jobhistory;
IF v_maxid IS NULL THEN
v_maxid :=0;
END IF;
--向历史岗位表中插入一条记录
INSERT INTO emp_jobhistory
VALUES(v_maxid+1,p_empno,p_olddeptno,p_newdeptno,p_date,p_type,p_res);
IF SQL%ROWCOUNT>0 THEN
COMMIT;
dbms_output.put_line('调转成功');
p_flag :=TRUE;
ELSE
ROLLBACK;
dbms_output.put_line('调转失败');
END IF;
END;
2.写一个块,分别按照三种调用方式,调用上述过程。
DECLARE
p_flag BOOLEAN;
BEGIN
chageDept(7900,20,30,SYSDATE,‘被动调转’,‘薪资太高’,p_flag);
END;
SELECT * FROM emp_jobhistory;
SELECT * FROM emp;
CREATE TABLE emp_jobhistory(
id NUMBER(4) PRIMARY KEY,
empno NUMBER(4),
olddeptno NUMBER(2),
p_newdeptno NUMBER(2),
chagedate DATE,
chagetype VARCHAR2(100),
chagereason VARCHAR2(100));
课后作业
1.创建一个员工离职表:dimission,包括如下字段:
流水号:数值型
员工编号:数值型
离职时所在部门编号:数值型
离职日期:日期型
离职原因:变长字符
离职去向:变长字符
CREATE TABLE dimission(
id NUMBER(6) PRIMARY KEY,
empno NUMBER(4) ,
deptno NUMBER(2),
dimdate date,
dimres VARCHAR2(100),
dimto VARCHAR2(100));
2.修改员工表emp结构,添加员工状态字段status,整型,默认值为1,表示正常状态。
ALTER TABLE emp
ADD status NUMBER(2) DEFAULT 1;
3.写一个存储过程addDim,实现员工离职功能,办理成功返回ture,失败返回false,仔细分析传入及传出参数,
办理离职时,修改员工表的员工状态字段status为2,
并且向dimission表中插入1条记录。
CREATE OR REPLACE PROCEDURE addDim(p_empno IN emp.empno%TYPE,
p_deptno IN emp.deptno%TYPE,
p_date IN DATE,
p_res IN dimission.dimres%TYPE,
p_to IN dimission.dimto%TYPE,
p_flag OUT BOOLEAN)
IS
v_maxid NUMBER(6);
BEGIN
p_flag :=FALSE;
--更新员工当前状态
UPDATE emp
SET status=2
WHERE empno=p_empno;
IF SQL%ROWCOUNT<=0THEN
ROLLBACK;
dbms_output.put_line('离职失败 :'||SQLERRM);
RETURN ;
END IF;
--读取当前最大ID
SELECT MAX(ID)
INTO v_maxid
FROM dimission;
IF v_maxid IS NULL THEN
v_maxid :=0;
END IF;
--向离职表中插入一条信息
INSERT INTO dimission(id,empno,deptno,dimdate,dimres,dimto)
VALUES(v_maxid+1,p_empno,p_deptno,p_date,p_res,p_to);
IF SQL%ROWCOUNT>0 THEN
COMMIT;
p_flag :=TRUE;
dbms_output.put_line('办理离职成功');
ELSE
ROLLBACK;
dbms_output.put_line('办理离职失败'||SQLERRM);
END IF;
END;
4.写一个存储过程searchDim,实现遍历指定时间段办理入职的员工姓名。
CREATE OR REPLACE PROCEDURE searchDim(p_begindate DATE,
p_enddate DATE)
IS
CURSOR emp_cur IS
SELECT ename,dimdate from dimission d,emp e
WHERE d.empno=e.empno
AND dimdate>=p_begindate
AND dimdate<p_enddate;
BEGIN
FOR emp_rec IN emp_cur LOOP
dbms_output.put_line(emp_rec.ename || ','||emp_rec.dimdate);
END LOOP;
END;
5.写一个块,调用3,4过程。
DECLARE
P_flag BOOLEAN;
BEGIN
addDim(8891,10,SYSDATE,'赚够钱咯','环游世界',P_flag);
END;
SELECT * FROM emp;
SELECT * FROM dimission;
BEGIN
searchDim('01-1月-18','01-1月-18');
END;
第6章 函数
练习1
1.编写一个函数,计算员工应交个人所得税,1000元以下的员工,不交税,1000-2000元的按照5%缴纳,2000以上的10%缴纳。
CREATE OR REPLACE FUNCTION calculateTax(p_empno emp.empno%TYPE)
RETURN NUMBER
IS
v_tax NUMBER;
v_sal emp.sal%TYPE;
BEGIN
SELECT sal
INTO v_sal
FROM emp
WHERE empno=p_empno;
IF v_sal<1000 THEN
v_tax :=0;
ELSIF v_sal BETWEEN 1000 AND 2000 THEN
v_tax :=v_sal*0.05;
ELSE
v_tax :=v_sal*0.1;
END IF;
RETURN v_tax;
END;
2.写一个块,调用上述函数。
DECLARE
CURSOR tax_cursor
IS
SELECT ename,sal,empno
FROM emp;
v_tax emp.sal%TYPE;
BEGIN
FOR tax_record IN tax_cursor LOOP
v_tax :=calculateTax(tax_record.empno);
dbms_output.put_line('员工姓名'||tax_record.ename||' 工资:'||tax_record.sal ||' 应交税费:'||v_tax);
END LOOP;
END;
3.写一个SELECT语句,调用上述函数。
SELECT empno,ename,sal,calculateTax(empno)
FROM emp;
课后作业
1、创建函数,根据输入的参数(员工代码)值,返回对应的员工姓名
CREATE OR REPLACE FUNCTION getEname(p_empno emp.empno%TYPE)
RETURN emp.ename%TYPE
IS
v_ename emp.ename%TYPE;
BEGIN
SELECT ename
INTO v_ename
FROM emp
WHERE empno = p_empno;
RETURN v_ename;
EXCEPTION
WHEN no_Data_found THEN
RETURN NULL;
dbms_output.put_line('指定编号员工不存在');
WHEN too_many_rows THEN
RETURN NULL;
dbms_output.put_line('指定编号的员工存在多条记录');
END;
–调用
SELECT empno,getEname(empno)
FROM emp;
2、创建一个函数,根据输入的参数(部门代码)值,返回对应的部门员工的最高薪水;
CREATE OR REPLACE FUNCTION getMaxSal(p_deptno emp.deptno%TYPE)
RETURN emp.sal%TYPE
IS
v_maxsal emp.sal%TYPE;
v_count NUMBER(2) ;
BEGIN
SELECT COUNT(deptno)
INTO v_count
FROM dept
WHERE deptno = p_deptno;
IF v_count<=0 THEN
dbms_output.put_line('部门编号无效');
RETURN -1;
END IF;
SELECT MAX(sal)
INTO v_maxsal
FROM emp
WHERE deptno=p_deptno;
RETURN v_maxsal;
END;
3、创建一个存储过程,查询dept表的所有部门信息,调用该函数,当函数返回的薪水大于4000时,产生异常,在异常部分显示’某某部门的薪水太高了’。
CREATE OR REPLACE PROCEDURE finAllDeptMaxSal
IS
e_exec EXCEPTION;
v_dname VARCHAR2(100);
v_sal emp.sal%TYPE;
BEGIN
FOR dept_record IN
(SELECT *
FROM dept) LOOP
v_sal :=getmaxsal(dept_record.deptno);
IF v_sal >=4000 THEN
IF v_dname IS NULL THEN
v_dname :=dept_record.dname;
ELSE
v_dname :=v_dname||','||dept_record.dname;
END IF;
END IF;
END LOOP;
IF v_dname IS NOT NULL THEN
RAISE e_exec;
END IF;
EXCEPTION
WHEN e_exec THEN
dbms_output.put_line(v_dname||'部门的薪水太高了');
END;
–调用
BEGIN
finAllDeptMaxSal;
END ;
第7章 包
练习1
1.创建一个包,该包实现部门管理的功能,包括
1.1:函数:验证部门编号是否有效。
1.2:过程:查询当前所有部门信息
1.3:过程:新建一个部门,成功返回新建的部门编号,失败返回-1
1.4:过程:根据部门编号读取部门信息
1.5:过程:根据部门编号修改部门信息
1.6:过程:根据部门编号查询部门所有员工信息
1.7:过程:根据部门编号删除一个部门,之前要判断该部门下是否存在员工,如果存在员工,则提示用户“部门下已经存在员工,不能删除该部门”。
CREATE OR REPLACE PACKAGE dept_pak
IS
FUNCTION validDept(p_deptno IN dept.deptno%TYPE) RETURN BOOLEAN;
PROCEDURE searchAllDept ;
PROCEDURE addDept(p_dname dept.dname%TYPE,
p_loc dept.loc%TYPE,
p_deptno OUT dept.deptno%TYPE);
PROCEDURE getDeptByID(p_deptno dept.deptno%TYPE,
p_dname OUT dept.dname%TYPE,
p_loc OUT dept.loc%TYPE);
PROCEDURE updateDept(p_deptno dept.deptno%TYPE,
p_dname dept.dname%TYPE,
p_loc dept.loc%TYPE);
PROCEDURE searchAllEmp(p_deptno dept.deptno%TYPE);
PROCEDURE delDept(p_deptno dept.deptno%TYPE);
END;
CREATE OR REPLACE PACKAGE BODY dept_pak
IS
--1.1:函数:验证部门编号是否有效
FUNCTION validDept(p_deptno IN dept.deptno%TYPE) RETURN BOOLEAN
IS
v_deptno dept.deptno%TYPE;
BEGIN
SELECT COUNT(deptno)
INTO v_deptno
FROM dept
WHERE deptno=p_deptno;
IF v_deptno>0 THEN
RETURN TRUE;
ELSE
return FALSE;
END IF;
END;
--1.2:过程:查询当前所有部门信息
PROCEDURE searchAllDept
IS
BEGIN
FOR dept_record IN
(SELECT *
FROM dept) LOOP
dbms_output.put_line(dept_record.dname);
END LOOP;
END;
--1.3:过程:新建一个部门,成功返回新建的部门编号,失败返回-1
PROCEDURE addDept(p_dname dept.dname%TYPE,
p_loc dept.loc%TYPE,
p_deptno OUT dept.deptno%TYPE)
IS
v_deptno dept.deptno%TYPE;
BEGIN
SELECT MAX(deptno)
INTO v_deptno
FROM dept;
INSERT INTO dept(deptno,dname,loc)
VALUES(v_deptno+1,p_dname,p_loc);
IF SQL%ROWCOUNT>0 THEN
COMMIT;
p_deptno :=v_deptno+1;
dbms_output.put_line('新建部门成功');
ELSE
ROLLBACK;
p_deptno :=-1;
dbms_output.put_line('新建部门失败'||SQLERRM);
END IF;
END;
--1.4:过程:根据部门编号读取部门信息
PROCEDURE getDeptByID(p_deptno dept.deptno%TYPE,
p_dname OUT dept.dname%TYPE,
p_loc OUT dept.loc%TYPE)
IS
BEGIN
SELECT DName,loc
INTO p_dname,p_loc
FROM dept
WHERE deptno=p_deptno;
END;
--1.5:过程:根据部门编号修改部门信息
PROCEDURE updateDept(p_deptno dept.deptno%TYPE,p_dname dept.dname%TYPE,p_loc dept.loc%TYPE)
IS
BEGIN
--验证部门编号是否有效
IF validDept(p_deptno) THEN
UPDATE dept
SET dname=p_dname,loc = p_loc
WHERE deptno=p_deptno;
IF SQL%ROWCOUNT>0 THEN
COMMIT;
dbms_output.put_line('修改部门成功');
ELSE
ROLLBACK;
dbms_output.put_line('修改部门失败'||SQLERRM);
END IF;
ELSE
dbms_output.put_line(p_deptno ||'是一个无效的部门编号');
END IF;
END;
--1.6:过程:根据部门编号查询部门所有员工信息
PROCEDURE searchAllEmp(p_deptno dept.deptno%TYPE)
IS
CURSOR emp_cur
IS
SELECT *
FROM emp
WHERE deptno=p_deptno;
BEGIN
FOR emp_record IN emp_cur LOOP
dbms_output.put_line(p_deptno||'号部门员工为:'||emp_record.ename);
END LOOP;
END;
--1.7:过程:根据部门编号删除一个部门,之前要判断该部门下是否存在员工,如果存在员工,则提示用户“部门下已经存在员工,不能删除该部门”。
PROCEDURE delDept(p_deptno dept.deptno%TYPE)
IS
v_count NUMBER(2);
BEGIN
SELECT COUNT(empno)
INTO V_count
FROM emp
WHERE deptno = p_deptno;
IF v_count>0 THEN
dbms_output.put_line('该部门下存在员工,不能删除');
ELSE
DELETE FROM dept
WHERE deptno=p_deptno;
IF SQL%ROWCOUNT >0 THEN
COMMIT;
dbms_output.put_line('删除部门成功');
ELSE
ROLLBACK;
dbms_output.put_line('删除部门失败'||SQLERRM);
END IF;
END IF;
END;
END;
课后作业
1、创建表test,表定义如下:
empno number(2),
ename varchar2(10),
sal number(7,2)
empno是主键
CREATE TABLE test(
empno number(2) PRIMARY KEY,
ename varchar2(10),
sal number(7,2));
2、创建包的声明test_pak,内容包含add_user过程、del_user过程(根据empno值删除用户)、add_sal函数(根据empno值确定用户,增加员工工资,并返回该用户的工资)
CREATE OR REPLACE PACKAGE test_paK
IS
PROCEDURE add_user(p_empno IN test.empno%TYPE,
p_ename IN test.ename%TYPE,
p_sal IN test.sal%TYPE);
PROCEDURE del_user(p_empno IN test.empno%TYPE);
FUNCTION add_sal(p_empno IN test.empno%TYPE,
p_sal IN test.sal%TYPE) RETURN NUMBER;
3、创建包体,实现上述定义
CREATE OR REPLACE PACKAGE BODY test_paK
IS
PROCEDURE add_user(p_empno IN test.empno%TYPE,
p_ename IN test.ename%TYPE,
p_sal IN test.sal%TYPE)
IS
BEGIN
INSERT INTO test
VALUES(p_empno,p_ename,p_sal);
COMMIT;
END;
PROCEDURE del_user(p_empno IN test.empno%TYPE)
IS
BEGIN
DELETE FROM test
WHERE empno=p_empno;
commit;
END;
FUNCTION add_sal(p_empno IN test.empno%TYPE,
p_sal IN test.sal%TYPE) RETURN NUMBER
IS
v_sal NUMBER(10);
BEGIN
UPDATE test
SET sal=sal+p_sal
WHERE empno=p_empno;
COMMIT;
SELECT sal
INTO v_sal
FROM test
WHERE empno=p_empno;
RETURN v_sal;
END;
END;
4、调用上述的每部分,验证正确性
EXEC test_paK.add_user(2,‘A’,100);
DECLARE
v_sal test.sal%TYPE;
BEGIN
v_sal=test_pak.add_sal(2,300);
dbms_output.put_line(v_sal);
END;
EXEC test_pak.del_user(1);
第9章 触发器
练习1
1.在EMP表上创建语句级别的触发器,
当用户在8:00点至17:00点以外插入数据时,系统提示‘只是在工作期间可以录入数据’;
当用户在8:00点至17:00点以外修改数据时,系统提示‘只是在工作期间可以修改数据’;
当用户在8:00点至17:00点以外删除数据时,系统提示‘只是在工作期间可以删除数据’。
CREATE OR REPLACE TRIGGER tri_emp_insertInfo
BEFORE INSERT ON emp
BEGIN
IF(to_char(SYSDATE,'HH24:MI') NOT BETWEEN '08:00'
AND '17:00') THEN
raise_application_error(-20001,'只是在工作期间可以录入数据');
END IF;
END;
CREATE OR REPLACE TRIGGER tri_emp_updateInfo
BEFORE DELETE ON emp
BEGIN
IF(to_char(SYSDATE,'HH24:MI') NOT BETWEEN '08:00'
AND '17:00') THEN
raise_application_error(-20001,'只是在工作期间可以修改数据');
END IF;
END;
CREATE OR REPLACE TRIGGER tri_emp_deleteInfo
BEFORE DELETE ON emp
BEGIN
IF(to_char(SYSDATE,'HH24:MI') NOT BETWEEN '08:00'
AND '17:00') THEN
raise_application_error(-20001,'只是在工作期间可以删除数据');
END IF;
END;
练习2
1.在员工部门调转时,当修改员工表中的部门编号时,请在该操作上建立触发器,同步实现员工历史岗位表中数据的操作。
CREATE OR REPLACE TRIGGER tri_emp_updatedeptno
AFTER UPDATE OF deptno ON emp
FOR EACH ROW
DECLARE
v_maxid NUMBER(6);
BEGIN
SELECT MAX(id)
INTO v_maxid
FROM emp_jobhistory;
INSERT INTO Emp_Jobhistory
VALUES(v_maxid+1,:old.empno,:old.deptno,:new.deptno,SYSDATE,NULL,NULL);
END;
课件及习题答案汇总word文档百度云地址:
链接: https://pan.baidu.com/s/1H9cw1OpKu4B96F2yBwOfZQ
提取码: 8phq