第2章 编写简单的查询语句
练习1

1.使用两种方式查询所有员工(EMP)信息。

   SELECT *FROM emp;SELECT empno,ename,job,mgr,hiredate,sal,comm,deptnoFROM emp;

2.查询(EMP)员工编号、员工姓名、员工职位、员工月薪、工作部门编号。

   SELECT empno,ename,job,sal,deptnoFROM 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*6FROM 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 deptnoFROM 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,hiredateFROM empWHERE job='SALESMAN';

2.查询1985年12月31日之前入职的员工姓名及入职日期。

   SELECT empno,hiredateFROM empWHERE hiredate<'31-12月1985';

3.查询部门标号不在10部门的员工姓名、部门编号。

   SELECT ename,deptnoFROM empWHERE deptno<>10;

练习2

1.查询入职日期造82年至85年员工姓名,入职日期。

   SELECT ename,hiredateFROM empWHERE hiredate BETWEEN '01-1月-82' AND '01-1月-85';SELECT ename,hiredateFROM empWHERE hiredate BETWEEN TO_DATE('1982-01-01','YYYY-MM-DD')AND TO_DATE('1985-01-01','YYYY-MM-DD');

2.查询月薪在3000到5000的员工姓名,月薪。

   SELECT ename,salFROM empWHERE sal BETWEEN 3000 AND 5000;

3.查询部门编号为10或者20的员工姓名,部门编号。

   SELECT ename,deptnoFROM empWHERE deptno=10 OR deptno=20;

4.查询经理编号为7709,7566,7788的员工姓名,经理编号。

   SELECT ename,mgrFROM empWHERE mgr IN(7709,7756,778);

练习3

1.查询员工姓名以W开头的员工姓名。

   SELECT enameFROM empWHERE ename LIKE 'W%';SELECT enameFROM empWHERE INSTR(ename,'W')=1;

2.查询员工姓名倒数第2个字符为T的员工姓名。

   SELECT enameFROM empWHERE ename LIKE '%T_';

SELECT ename

FROM emp

WHERE SUBSTR(ename,-2,1)=‘T’;

3.查询奖金为空的员工姓名,奖金。

   SELECT ename,commFROM empWHERE comm IS NULL;

练习4

1.查询工资超过2000并且职位是WANAGER,或者职位是SALESMAN的员工姓名、职位、工资。

   SELECT ename,job,salFROM empWHERE (sal>2000 AND job='MANAGER') OR job='SALESMAN';

2 .查询工资超过2000并且职位是WANAGER或SALESMAN的员工姓名、职位、工资。

   SELECT ename,job,salFROM empWHERE (sal>2000 AND job='MANAGER') OR job='SALESMAN';

3.查询部门在10或者20,并且工资在3000到5000之间的员工姓名、部门、工资。

   SELECT ename,deptno,salFROM empWHERE (deptno=10 OR deptno=20) AND sal BETWEEN 3000 AND 5000;

4.查询入职日期在81年,并且职位不是SALES开头的员工姓名、入职日期、职位。

   SELECT ename,hiredate,jobFROM empWHERE (hiredate BETWEEN '01-1月-81' AND '31-12月-81') AND job NOT LIKE 'SALES%';SELECT ename,hiredate,jobFROM empWHERE (hiredate BETWEEN '01-1月-81' AND '31-12月-81')AND  SUBSTR(job,0,5)<>'SALES';

5.查询职位为SALESMAN或MANAGER,部门编号为10或者20,姓名包含A的员工姓名、职位、部门编号。

   SELECT ename,job,deptnoFROM empWHERE (job='SALESMAN' OR job='MANAGER') AND (deptno=10 OR deptno=20) AND               ename LIKE '%A%';SELECT ename,job,deptnoFROM empWHERE (job='SALESMAN' OR job='MANAGER')AND (deptno=10 OR deptno=20)AND INSTR(ename,'A')>0;

练习5

1.查询部门在20或30的员工姓名,部门编号,并按照工资升序排序。

   SELECT ename,deptno,salFROM empWHERE deptno=20 OR deptno=30ORDER BY sal;

2.查询工资在2000-3000之间,部门不在10号的员工姓名,部门编号,工资,并按照部门升序,工资降序排序。

   SELECT ename,deptno, salFROM empWHERE (sal BETWEEN 2000 AND 3000) AND deptno<>10ORDER BY deptno,sal DESC;

3.查询入职日期在82年至83年之间,职位以SALES或者MAN开头的员工姓名,入职日期,职位,并按照入职日期降序排序。

–3.查询入职日期在82年至83年之间,职位以SALES或者MAN开头的员工姓名,入职日期,职位,并按照入职日期降序排序。

   SELECT ename,hiredate,jobFROM empWHERE (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,jobFROM empWHERE hiredate>'09-7月-1982' AND job<>'SALESMAN';

2.查询员工姓名的第三个字母是a的员工姓名。

   SELECT enameFROM empWHERE SUBSTR(ename,3,1)='a';SELECT enameFROM empWHERE ename LIKE '__a%';

3.查询除了10、20号部门以外的员工姓名、部门编号。

   SELECT ename,deptnoFROM empWHERE deptno NOT IN(10,20);

4.查询部门号为30号员工的信息,先按工资降序排序,再按姓名升序排序。

   SELECT *FROM empWHERE deptno=30ORDER BY sal DESC,ename;

5.查询没有上级的员工(经理号为空)的员工姓名。

   SELECT enameFROM empWHERE mgr IS NULL;

6.查询工资大于等于4500并且部门为10或者20的员工的姓名,工资,部门编号。

   SELECT ename,sal,deptnoFROM empWHERE sal>=4500 AND deptno IN(10,20);

第4章 单行函数
练习1

1.写一个查询,用首字母大写,其他字母小写显示雇员的ename,显示名字的长度,并给每列一个适当的标签,条件是满足所有雇员名字的开始字母是J、A或M的雇员,并对查询结果按雇员的ename升序排序。(提示:使用initcap、length、substr)

   SELECT INITCAP(ename) 雇员姓名,LENGTH(ename) 姓名长度FROM empWHERE 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
  1. 当前日期为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 empWHERE 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 empWHERE 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') DAYFROM 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 empWHERE SUBSTR(ename,3,1)='A';SELECT *FROM empWHERE 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*0WHEN sal>=1000 AND sal<2000 THEN sal*0.1WHEN sal>=2000 AND sal<3000 THEN sal*0.15WHEN sal>=3000 THEN sal*0.1ELSE 0 END) 税率FROM emp;

8.创建一个查询显示所有雇员的ename和sal。格式化sal围殴15个字符长度,用$左填充,列标签SALARY。

   SELECT ename,LPAD(sal,15,'$') SALARYFROM emp;

第5章 多表连接
练习1

1.写一个查询,显示所有员工姓名,部门编号,部门姓名。

   SELECT ename,emp.deptno,dnameFROM emp,deptWHERE emp.deptno=dept.deptno;

2.写一个查询,显示所有工作在CHICAGO并且奖金不为空的员工姓名,工作地点,奖金。

   SELECT ename,loc,commFROM emp,deptWHERE emp.deptno=dept.deptno AND comm IS NOT NULL;

3.写一个查询,显示所有姓名中含有A字符的员工姓名,工作地点。

   SELECT ename,locFROM emp,deptWHERE emp.deptno=dept.deptno AND ename LIKE '%A%';

练习2

1.查询每个员工的编号,姓名,工资,工资等级,所在工作城市,按照工资等级进行升序排序。

   SELECT e.deptno,ename,sal,grade,locFROM emp e,dept d,salgrade sWHERE e.deptno=d.deptnoAND (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 mWHERE e.mgr=m.empno;

2.在上一题的基础上,添加没有经理的员工King,并按照员工编号排序。

   SELECT e.ename 员工姓名,e.empno 员工编号,m.ename 经理姓名,m.empno 经理编号FROM emp e,emp mWHERE e.mgr=m.empno(+)

ORDER BY e.empno;

3.查询所有员工编号,姓名,部门名称,包括没有部门的员工也要显示出来。

   SELECT emp.empno,ename,dnameFROM emp,deptWHERE emp.deptno=dept.deptno(+);

练习4

使用SQL-99写法,完成如下练习

1.创建一个员工表和部门表的交叉连接。

   SELECT *FROM empCROSS JOIN dept;

2.使用自然连接,显示入职日期在80年5月1日之后的员工姓名,部门名称,入职日期。

   SELECT ename,dname,hiredateFROM emp

NATURAL JOIN dept

  WHERE hiredate>'01-5月-80';

3.使用USING子句,显示工作在CHICAGO的员工姓名,部门名称,工作地点。

   SELECT ename,dname,locFROM empJOIN dept USING(deptno)WHERE loc='CHICAGO';

4.使用ON子句,显示工作在CHICAGO的员工姓名,本门名称,工作地点,薪资等级。

   SELECT ename,dname,loc,gradeFROM emp eJOIN dept dON e.deptno=d.deptno AND loc='CHICAGO'JOIN salgrade sON sal BETWEEN losal AND hisal;

5.使用左连接,查询每个员工的姓名,经理姓名,没有经理的King也要显示出来。

   SELECT e.ename 员工姓名,m.ename 经理姓名FROM emp eOUTER JOIN emp mON e.mgr=m.empno;

6.使用右外连接,查询每个员工的姓名,经理姓名,没有经理的King也要显示出来。

   SELECT e.ename 员工姓名,m.ename 经理姓名FROM emp mRIGHT OUTER JOIN emp eON e.mgr=m.empno;

课后作业

1.显示员工SMITH的姓名,部门名称,直接上级名称。

   SELECT e.ename,dname,m.ename 直接上级名称FROM emp e,emp m,dept dWHERE e.mgr=m.empno AND e.deptno=d.deptno AND e.ename='SMITH';

2.显示员工姓名,部门名称,工资,工资级别,要求工资级别大于4级。

   SELECT ename,dname,sal,gradeFROM emp e,dept d,salgrade sWHERE e.deptno=d.deptnoAND (sal BETWEEN losal AND hisal)AND grade>4;

3.显示员工KING和FORD管理的员工姓名及其经理姓名。

   SELECT e.ename 员工姓名,m.ename 经理姓名FROM emp e,emp mWHERE e.mgr=m.empnoAND m.ename IN('KING','FORD');

4.显示员工姓名,参加工作时间,经理名,参加工作时间,要求参加时间比经理早。

   SELECT e.ename,e.hiredate,m.ename,m.hiredateFROM emp e,emp mWHERE e.mgr=m.empno AND e.hiredate>m.hiredate;

第6章 分组函数
练习1

1.查询部门20的员工,每月的工资总和及平均工资。

   SELECT SUM(sal),AVG(sal)FROM empWHERE deptno=20;

2.查询工作在CHICAGO的员工人数,最高工资及最低工资。

   SELECT COUNT(*),MIN(sal),MAX(sal)FROM emp e,dept dWHERE 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 dWHERE e.deptno(+)=d.deptnoGROUP 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 dWHERE e.deptno=d.deptnoGROUP BY d.deptno,dname,e.job;

3.查询每个经理所管理的人数,经理编号,经理姓名,要求包括没有经理的人员信息。

   SELECT COUNT(e.empno),m.empno,m.enameFROM emp e,emp mWHERE e.mgr=m.empno(+)GROUP BY m.empno,m.ename;

练习3

1.查询部门人数大于2的部门编号,部门名称,部门人数。

   SELECT d.deptno,dname,COUNT(empno)FROM emp e,dept dWHERE e.deptno=d.deptnoGROUP BY d.deptno,dname

HAVING COUNT(empno)>2;

2.查询部门平均工资大于2000,且人数大于2的部门编号,部门名称,部门人数,

部门平均工资,并按照部门人数升序排序。

   SELECT d.deptno,dname,COUNT(empno),AVG(sal)FROM emp e,dept dWHERE e.deptno=d.deptnoGROUP 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 dWHERE e.deptno=d.deptnoGROUP BY dname

HAVING AVG(sal)>2500;

2.查询员工岗位中不是以“SA”开头并且平均工资在2500员以上的岗位及平均工资,并按平均工资降序排序。

   SELECT job,AVG(sal)FROM empWHERE 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 dWHERE e.deptno=d.deptnoGROUP BY dname

HAVING COUNT(empno)>2;

4.查询岗位不为SALESMSMAN,工资和大于等于2500的岗位及每种岗位的工资和。

   SELECT job,SUM(sal)FROM empWHERE job<>'SALESMSMAN'GROUP BY job

HAVING SUM(sal)>2500;

5.显示经理编号和经理姓名,这个经理所管理员工的最低工资,没有经理的KING也要显示,不包括最低工资小于3000的,按最低工资由高到低排序。

   SELECT m.empno,m.ename,MIN(e.sal)FROM emp e,emp mWHERE 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 empGROUP BY deptno;

第7章 子查询
练习1

1.查询入职日期最早的员工姓名,入职日期。

   --最早的入职日期SELECT MIN(hiredate)FROM emp;SELECT ename,hiredateFROM empWHERE hiredate=(SELECT MIN(hiredate)FROM emp);

2.查询工资比SMITH工资高并且工作地点在CHICAGO的员工姓名,工资,部门名称。

   --SMITH的工资SELECT salFROM empWHERE ename='SMITH';SELECT ename,sal,dnameFROM emp e,dept dWHERE sal>(SELECT salFROM empWHERE ename='SMITH')AND loc='CHICAGO';

3.查询入职日期比20部门入职日期最早的员工还早的员工姓名,入职日期。

   --20部门员工的最早入职日期SELECT MIN(hiredate)FROM empWHERE deptno=20;SELECT ename,hiredateFROM empWHERE hiredate<(SELECT MIN(hiredate)FROM empWHERE deptno=20);

4.查询部门人数大于所有部门平均人数的部门编号,部门名称,部门人数。

   --所有部门平均人数SELECT AVG(COUNT(empno))FROM empGROUP BY deptno;SELECT d.deptno,dname,COUNT(empno)FROM emp e,dept dWHERE e.deptno=d.deptnoGROUP BY d.deptno,dname

HAVING COUNT(empno)>

                      (SELECT AVG(COUNT(empno))FROM empGROUP BY deptno);

练习2

1.查询入职日期比10部门任意一个员工晚的员工姓名,入职日期,不包括10部门员工。

   --10部门员工的最早入职日期SELECT MIN(hiredate)FROM empWHERE deptno=10;SELECT ename,hiredateFROM empWHERE hiredate>(SELECT MIN(hiredate)FROM empWHERE deptno=10)AND deptno<>10;

2.查询入职日期比10部门所有员工晚的员工姓名,入职日期,不包括10部门员工。

   --10部门最晚的员工入职日期SELECT MAX(hiredate)FROM empWHERE deptno=10;SELECT ename,hiredateFROM empWHERE hiredate>(SELECT MAX(hiredate)FROM empWHERE deptno=10)AND deptno<>10;

3.查询职位和10部门人员一个员工职位相同的员工姓名,职位,不包括10部门员工。

   --10部门员工职位SELECT jobFROM empWHERE deptno=10;SELECT ename,jobFROM empWHERE job IN(SELECT jobFROM empWHERE deptno=10)AND deptno<>10;

练习3

1.查询职位及经理和10部门任意一个员工职位及经理相同的员工姓名,职位,不包括10部门员工。

   --10部门的全部员工职位及经理SELECT job,mgrFROM empWHERE deptno=10;SELECT ename,jobFROM empWHERE (job,mgr) IN(SELECT job,mgrFROM empWHERE deptno=10)AND deptno<>10;

2.查询职位及经理和10部门任意一个员工职位或经理相同的员工姓名,职位,不包括10部门员工。

   SELECT ename,jobFROM empWHERE (job IN(SELECT jobFROM empWHERE deptno=10)AND deptno<>10)OR (mgr IN(SELECT mgrFROM empWHERE deptno=10)AND deptno<>10);

练习4

1.查询比自己职位平均工资高的员姓名,职位,部门名称,职位平均工资。

   --查询每个职位的平均工资SELECT job,AVG(sal) avgsalFROM empGROUP BY job;SELECT ename,e.job,dname,a.avgsalFROM emp e,dept d,(SELECT job,AVG(sal) avgsalFROM empGROUP BY job) a

WHERE e.deptno=d.deptno

 AND e.job=a.jobAND e.sal>a.avgsal;

2.查询职位和经理同员工SCOTT或BLAKE完全相同的员工姓名,职位,不包括SCOTT和BLAKE本人。

   --员工SCOTT或BLAKE的职位和经理SELECT job,mgrFROM empWHERE ename='SCOTT'OR ename='BLAKE';SELECT ename,jobFROM empWHERE (job,mgr) IN(SELECT job,mgrFROM empWHERE ename='SCOTT'OR ename='BLAKE');

3.查询不是经理的员工姓名。

  SELECT enameFROM empWHERE job<>'MANAGER';

练习5

1.查询入职日期最早的前5名员姓名,入职日期。

   SELECT ROWNUM,ename,hiredateFROM empWHERE ROWNUM<=5ORDER BY hiredate;

2.查询工作在CHICAGO并且入职日期最早的前2名员工姓名,入职日期。

   SELECT ROWNUM,ename,hiredateFROM emp e,dept dWHERE e.deptno=d.deptnoAND loc='CHICAGO'AND ROWNUM<=2ORDER BY hiredate;

练习6

1.按照每页显示5条记录,分别查询第1页,第2页,第3页信息,要求显示员工姓名,入职日期,部门名称。

   SELECT ROWNUM rn,ename,hiredate,dnameFROM emp e,dept dWHERE e.deptno=d.deptno--第一页SELECT a.*FROM (SELECT ROWNUM rn,ename,hiredate,dnameFROM emp e,dept dWHERE e.deptno=d.deptno) aWHERE rn<=5*1 AND rn>5*0;--第二页SELECT a.*FROM (SELECT ROWNUM rn,ename,hiredate,dnameFROM emp e,dept dWHERE e.deptno=d.deptno) aWHERE rn<=5*2 AND rn>5*1;--第三页SELECT a.*FROM (SELECT ROWNUM rn,ename,hiredate,dnameFROM emp e,dept dWHERE e.deptno=d.deptno) aWHERE rn<=5*3 AND rn>5*2;

练习7

1.按照每页显示5条记录,分别查询工资最高的第1页,第2页,第3页信息,要求显示员工姓名,入职日期,部门名称,工资。

   SELECT ROWNUM rn,ename,hiredate,dname,salFROM emp e,dept dWHERE e.deptno=d.deptnoORDER BY sal DESC--第一页SELECT a.*FROM (SELECT ROWNUM rn,ename,hiredate,dname,salFROM emp e,dept dWHERE e.deptno=d.deptnoORDER BY sal DESC) aWHERE rn<=5*1 AND rn>5*0;--第二页SELECT a.*FROM (SELECT ROWNUM rn,ename,hiredate,dname,salFROM emp e,dept dWHERE e.deptno=d.deptnoORDER BY sal DESC) aWHERE rn<=5*2 AND rn>5*1;--第三页SELECT a.*FROM (SELECT ROWNUM rn,ename,hiredate,dname,salFROM emp e,dept dWHERE e.deptno=d.deptnoORDER BY sal DESC) aWHERE rn<=5*3 AND rn>5*2;

课后作业

1.查询工资高于编号为7782的员工工资,并且和7369号员工从事相同工作的员工的编号,姓名及工资。

   --编号为7782的员工工资SELECT salFROM empWHERE empno='7782';--7369号员工从事的工作SELECT jobFROM empWHERE empno='7369';SELECT empno,ename,salFROM empWHERE sal>(SELECT salFROM empWHERE empno='7782')AND job=(SELECT jobFROM empWHERE empno='7369');

2.查询工资最高的员工姓名和工资。

   SELECT ename,salFROM empWHERE sal=(SELECT MAX(sal)FROM emp);
  1. 查询部门最低工资高于10号部门最低工资的部门的编号、名称及部门最低工资。

    --10号部门最低工资SELECT MIN(sal)FROM empWHERE deptno=10;SELECT e.deptno,dname,MIN(sal)FROM emp e,dept dWHERE e.deptno=d.deptno
    

    GROUP BY e.deptno,dname

    HAVING MIN(sal)<(SELECT MIN(sal)FROM empWHERE 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 empGROUP BY deptno) d

WHERE e.deptno=d.deptno

AND sal=minsal;

5.显示经理是KING的员工姓名,工资。

SELECT ename,sal

FROM emp

WHERE mgr=

        (SELECT empnoFROM empWHERE ename='KING');

6.显示比员工SMITH参加工作时间晚的员工姓名,工资,参加工作时间。

SELECT ename,sal,hiredate

FROM emp

WHERE hiredate>

             (SELECT hiredateFROM empWHERE ename='SMITH');

7.使用子查询的方式查询哪些职员在NEW YORK工作。

SELECT *

FROM emp

WHERE deptno=

            (SELECT deptnoFROM deptWHERE loc='NEW YORK');

8.写一个查询显示和员工SMITH工作在同一个部门的员工姓名,雇用日期,查询结果中排除SMITH。

SELECT ename,hiredate

FROM emp

WHERE deptno=

            (SELECT deptnoFROM empWHERE 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 empnoFROM empWHERE ename='KING');

11.显示所有工作在RESEARCH部门的员工姓名,职位。

SELECT ename,job

FROM emp

WHERE deptno=

             (SELECT deptnoFROM deptWHERE dname='RESEARCH');

12.查询每个部门的部门编号、平均工资,要求部门的平均工资高于部门20的平均工资。

SELECT deptno,AVG(sal)

FROM emp

GROUP BY deptno

HAVING AVG(sal)>

              (SELECT AVG(sal)FROM empWHERE deptno=20);

13.查询大于自己部门平均工资的员工姓名,工资,所在部门平均工资,高于部门平均工资的额度。

SELECT ename,sal,avgsal,sal-avgsal

FROM emp e,(SELECT deptno,AVG(sal) avgsal

           FROM empGROUP BY deptno) d

WHERE e.deptno=d.deptno AND sal>avgsal;

14.列出至少有一个雇员的所有部门。

SELECT *

FROM dept

WHERE deptno IN

              (SELECT deptnoFROM empGROUP BY deptnoHAVING COUNT(*)>0);

15.列出薪金比"SMITH"多的所有雇员。

SELECT *

FROM emp

WHERE sal>

         (SELECT salFROM empWHERE ename='SMITH');

16.列出入职日期早于其直接上级的所有雇员。

SELECT *

FROM emp e

WHERE hiredate<

              (SELECT m.hiredateFROM emp mWHERE e.mgr=m.empno);

SELECT DISTINCT *

FROM emp a,(SELECT e.mgr mno,m.hiredate mdate

            FROM emp e,emp mWHERE 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 empGROUP BY deptno);

20.显示出和员工号7369部门相同的员工姓名,工资。

SELECT ename,sal

FROM emp

WHERE deptno=

            (SELECT deptnoFROM empWHERE empno='7369');

21.显示出和姓名中包含"W"的员工相同部门的员工姓名。

SELECT ename

FROM emp

WHERE deptno=

            (SELECT deptnoFROM empWHERE 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 empGROUP 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 empGROUP BY mgr);

25.显示比工资最高的员工参加工作时间晚的员工姓名,参加工作时间

SELECT ename,hiredate

FROM emp

WHERE hiredate>

             (SELECT hiredateFROM empWHERE sal=(SELECT MAX(sal)FROM emp));

26.显示出平均工资最高的的部门平均工资及部门名称

SELECT *

FROM (SELECT AVG(sal),dname

      FROM emp e,dept dWHERE e.deptno=d.deptnoGROUP BY dnameORDER BY AVG(sal) DESC)

WHERE ROWNUM<=1;

第8章 集合运算
练习1

1.分别使用联合运算及完全联合运算完成,按照时间升序顺序,查询员工7839的工作岗位列表。

   --集合运算SELECT hiredate,jobFROM empWHERE empno= 7839UNIONSELECT begindate,jobFROM emp_jobhistoryWHERE 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;

  1. 使用集合运算,输出如下效果?

部门 工作地点 员工姓名 入职日期

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 empWHERE job=e.job);

2.查询工资为其部门最低工资的员工编号,姓名 ,工资。

SELECT empno,ename,sal

FROM emp e

WHERE sal=

        (SELECT MIN(sal)FROM empWHERE deptno=e.deptno);

练习2

如下练习,用相关子查询完成

1.查询所有雇员编号,名字和部门名字。

SELECT empno,ename,

    (SELECT dnameFROM deptWHERE e.deptno=deptno) 部门名字

FROM emp e;

2.查询哪些员工是经理?

SELECT *

FROM emp e

WHERE EXISTS

          (SELECT '1'FROM empWHERE mgr=e.empno);

3.查询哪些员工不是经理?

SELECT *

FROM emp e

WHERE NOT EXISTS

              (SELECT '1'FROM empWHERE mgr=e.empno);

4.查询每个部门工资最低的两个员工编号,姓名,工资。

SELECT empno,ename,sal

FROM emp e

WHERE 1>=

       (SELECT COUNT(empno)FROM empWHERE deptno=e.deptnoAND sal<e.sal)

练习3

如下练习,用exists或not exists完成

1.列出至少有一个雇员的所有部门名称。

SELECT dname

FROM dept d

WHERE EXISTS

          (SELECT '1'FROM empWHERE deptno=d.deptno);

2.列出一个雇员都没有的所有部门名称。

SELECT dname

FROM dept d

WHERE NOT EXISTS

              (SELECT '1'FROM empWHERE deptno=d.deptno);

课后作业 :

如下练习,使用相关子查询完成。

1.查询薪水多于他所在部门平均薪水的雇员名字 ,部门号。

SELECT ename,deptno

FROM emp e

WHERE sal>

        (SELECT AVG(sal)FROM empWHERE job=e.job);

2.查询员工姓名和直接上级的名字。

SELECT ename,

    (SELECT enameFROM empWHERE e.mgr=empno) 直接上级名字

FROM emp e;

3.查询每个部门工资最高的员工姓名,工资。

SELECT ename,sal

FROM emp e

WHERE sal=

       (SELECT MAX(sal)FROM empWHERE deptno=e.deptno);

4.查询每个部门工资前两名高的员工姓名,工资。

SELECT empno,ename,sal

FROM emp e

WHERE 1>=

       (SELECT COUNT(empno)FROM empWHERE deptno=e.deptnoAND 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 deptnoFROM  deptWHERE locIN ('CHICAGO','NEW YORK'));

练习5

1.重复做一下刚才的案例。

ALTER TABLE emp_back

ADD(dname varchar2(14));

UPDATE emp_back e

SET dname =(SELECT dnameFROM dept dWHERE deptno=e.deptno);

练习6

1.删除经理编号为7566的员工记录

DELETE FROM emp

WHERE mgr=7566;

2.删除工作在NEW YORK的员工记录

DELETE FROM emp

WHERE deptno IN

            (SELECT deptnoFROM deptWHERE loc='NEW YORK');

3.删除工资大于所在部门平均工资的员工记录

DELETE FROM emp

WHERE sal>

       (SELECT AVG(sal)FROM empWHERE 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班,null3,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 classidFROM classWHERE cname='java3班')

WHERE birthday IS NULL;

(8)请使用一条SQL语句,使用子查询,更新班级表中每个班级的人数字段

UPDATE CLASS c

SET ccount=(SELECT COUNT(*)FROM student sWHERE 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 NULLCONSTRAINT student_studentno_fk REFERENCES student(studentno),courseno VARCHAR(10) NOT NULLCONSTRAINT course_courseno_fk REFERENCES course(courseno),grade NUMBERCONSTRAINT 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

CYCLECACHE 10;

2.创建序列,起始值为50,每次增加5;

CREATE SEQUENCE test_seq3START 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_seqSTART WITH 1

INCREMENT BY 1

MAXVALUE 1000000000000

MINVALUE 1

 CYCLECACHE 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_deptnoFROM 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_empnoFROM emp;SELECT empnoINTO v_mgrFROM empWHERE ename='SMITH';INSERT INTO empVALUES(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 salINTO v_salFROM empWHERE 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 testSELECT *FROM emp eWHERE 1>(SELECT COUNT(*)FROM empWHERE sal>e.sal);COMMIT;

END;

5、创建pl/sql块,将emp表中员工的平均薪水更新到test表中,并打印平均薪水

DECLARE

v_sal emp.sal%TYPE;

BEGIN

SELECT AVG(sal)INTO v_salFROM emp;dbms_output.put_line(v_sal);UPDATE testSET 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_empnoFROM emp;INSERT INTO emp(empno,ename,job,deptno)VALUES(v_empno+1,'TOM','CLERK',10);SELECT maxnumberINTO v_maxnumberFROM deptWHERE deptno=10;SELECT COUNT(empno)INTO v_empnumFROM empWHERE deptno=10;IF v_empnum>v_maxnumber THENdbms_output.put_line('入职失败');ROLLBACK;ELSEdbms_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_empnoFROM emp;LOOPINSERT 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,dnameFROM emp e,dept dWHERE e.deptno=d.deptno) LOOPdbms_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 ISSELECT ename,dnameFROM emp e,dept dWHERE e.deptno=d.deptno;

BEGIN

OPEN emp_cursor;FETCH emp_cursor INTO v_ename,v_dname;WHILE emp_cursor%found LOOPdbms_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 salINTO v_salFROM empWHERE empno=&ID;IF v_sal<2000 THENdbms_output.put_line('挣的不多,需努力');     ELSIF v_sal BETWEEN 2000 AND 5000 THENdbms_output.put_line('收入还可以,还需努力');     ELSIF v_sal>5000 THENdbms_output.put_line('挣的挺多了,歇歇吧');END IF;

END;

2.屏幕上输出1到10(不包括6和8)

DECLARE

v_num NUMBER :=1;

BEGIN

WHILE v_num<=10 LOOPIF v_num NOT IN(6,8) THENdbms_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_empnoFROM emp;FOR v_count IN 1..5 LOOPINSERT 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_empnoFROM emp;FOR v_count <=5 LOOPINSERT 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_countFrom emp Where deptno=10;IF SQL%Rowcount>0  THENDelete From emp Where deptno = 20;ELSEDelete 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 Thendbms_output.PUT_LINE(‘插入部门成功’);Elsedbms_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;

输出结果:

   游标所影响的行数:0Found为假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;

输出结果:

   游标所影响的行数:1Found为真NotFound为假isOpen为假

练习2

  1. 使用游标,完成遍历所有员工姓名和部门名称的操作。

DECLARE

v_ename emp.ename%TYPE;v_dname dept.dname%TYPE;v_count NUMBER;CURSOR emp_cursorISSELECT ename,dnameFROM emp e,dept dWHERE e.deptno=d.deptno;

BEGIN

SELECT COUNT(empno)INTO v_countFROM emp e; OPEN emp_cursor;FETCH emp_cursor INTO v_ename,v_dname;FOR i IN 1..v_count LOOPdbms_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 ISSELECT ename,dnameFROM emp e,dept dWHERE e.deptno=d.deptno;

BEGIN

OPEN emp_cursor;FETCH emp_cursor INTO v_ename,v_dname;WHILE emp_cursor%found LOOPdbms_output.put_line(v_ename||'的部门是'||v_dname);  FETCH emp_cursor INTO v_ename,v_dname;END LOOP;

END;

练习4

1.使用游标和记录联合方式,完成遍历所有员工姓名和部门名称的操作。

DECLARE

CURSOR emp_cursor ISSELECT ename,dnameFROM emp e,dept dWHERE e.deptno=d.deptno;emp_record emp_cursor%ROWTYPE;

BEGIN

OPEN emp_cursor;FETCH emp_cursor INTO emp_record;WHILE emp_cursor%found LOOPdbms_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 ISSELECT ename,dnameFROM emp e,dept dWHERE e.deptno=d.deptno;

BEGIN

SELECT COUNT(empno)INTO v_countFROM emp e; OPEN emp_cursor;FETCH emp_cursor INTO v_ename,v_dname;FOR i IN 1..v_count LOOPdbms_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,dnameFROM emp e,dept dWHERE e.deptno=d.deptno) LOOPdbms_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) --员工信息ISSELECT ename,hiredateFROM empWHERE 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 LOOPdbms_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_countFROM emp eWHERE 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 LOOPdbms_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_countFROM emp eWHERE deptno=30;dbms_output.put_line('…………………….');dbms_output.put_line('小计:30号部门员工数为:'||v_count||'人');dbms_output.put_line('');dbms_output.put_line('------没有号号部门的员工列表---------'); SELECT ename,hiredateINTO v_ename,v_hiredateFROM empWHERE deptno IS NULL;dbms_output.put_line('姓名:'||v_ename||',入职日期:'||v_hiredate); SELECT COUNT(empno)INTO v_countFROM emp eWHERE 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 --部门ISSELECT DISTINCT deptnoFROM dept;CURSOR emp_cursor(p_deptno dept.deptno%Type) --员工信息ISSELECT ename,hiredateFROM empWHERE deptno=p_deptno;

BEGIN

FOR dept_record IN dept_cursor LOOPdbms_output.put_line('------'||dept_record.deptno||'号部门的员工列表---------');FOR emp_record IN emp_cursor(dept_record.deptno) LOOPdbms_output.put_line('姓名:'||emp_record.ename||',入职日期:'||emp_record.hiredate); END LOOP;SELECT COUNT(*)INTO v_countFROM emp eWHERE 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 ISSELECT   sal FROM    emp WHERE    deptno = 30 FOR UPDATE OF sal NOWAIT;

BEGIN

FOR emp_record IN sal_cursor LOOPUPDATE  emp SET   sal = emp_record.sal * 1.10;END LOOP;

END;

执行结果:所有员工的工资都变成了30号部门最后一名员工的工资的110%。

DECLARE

CURSOR sal_cursor ISSELECT   sal FROM    emp WHERE    deptno = 30 FOR UPDATE OF sal NOWAIT;

BEGIN

FOR emp_record IN sal_cursor LOOPUPDATE  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 empnoINTO v_mgrnoFROM empWHERE ename='JONES';SELECT deptnoINTO v_deptnoFROM deptWHERE 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 THENROLLBACK;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 THENROLLBACK;dbms_output.put_line('该部门下存在员工,不能删除部门');

END;

练习3

  1. 编写一个匿名块,分别对部门做一个查询、插入、修改、删除操作,验证这几个操作执行后的SQLCODE和SQLERRM结果。

DECLARE

v_dname dept.dname%TYPE;

BEGIN

SELECT dnameINTO v_dnameFROM deptWHERE deptno = 10;dbms_output.put_line('查询成功的SQLCODE:'||SQLCODE);dbms_output.put_line('查询成功的SQLerrm:'||SQLERRM);SELECT dnameINTO v_dnameFROM deptWHERE 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 deptSET 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 THENdbms_output.put_line('查询失败的SQLCODE:'||SQLCODE);dbms_output.put_line('查询失败的SQLerrm:'||SQLERRM);

END;

练习4

  1. 修改员工入职的功能,当入职部门的人数超编时,提示用户部门以超编,不能再录入员工。

DECLARE

v_max dept.maxnumber%TYPE;v_current v_max%TYPE;v_empno emp.empno%TYPE;e_havemaxnumber EXCEPTION;

BEGIN

--查询10号部门的编制SELECT maxnumberINTO v_maxFROM deptWHERE deptno = 10;--查询10号部门的当前人数SELECT COUNT(empno)INTO v_currentFROM empWHERE deptno = 10;IF v_max-v_current > 0 THEN--说明有剩余编制,可以实现入职操作SELECT MAX(empno)INTO v_empnoFROM 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('入职成功');                ELSERAISE e_havemaxnumber;      END IF;

EXCEPTION

WHEN e_havemaxnumber THENdbms_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_countFROM empWHERE sal = &sal;IF v_count = 0 THENRAISE e_noequal;ELSIF v_count >1 THENRAISE e_toomanyupper;ELSESELECT ename INTO v_ename FROM emp WHERE sal = &sal;dbms_output.put_line(v_ename ||','|| &sal);END IF;

EXCEPTION

WHEN e_noequal THENINSERT INTO messageVALUES('没有雇员挣sal的薪水');COMMIT;dbms_output.put_line('没有雇员挣sal的薪水');WHEN e_toomanyupper THENINSERT INTO messageVALUES('太多的雇员挣sal的薪水');COMMIT;dbms_output.put_line('太多的雇员挣sal的薪水');

END;

3、根据员工号,获得员工到目前为止参加工作年限(保留到整数),员工号不存在时提示“此员工号不存在”

DECLARE

v_year NUMBER(3);

BEGIN

SELECT ROUND(months_between(SYSDATE,hiredate)/12)INTO v_yearFROM emp WHERE empno = &empno;dbms_output.put_line(v_year);

EXCEPTION

WHEN no_data_found THENdbms_output.put_line('此员工号不存在') ;

END;

4、编写PL/SQL块,使用SELECT语句将管理者编号为空的员工的姓名及工作编号显示出来,如果符合条件的员工多于一人,则返回字符串“最高管理者人员过多!”字符串,如果找到没有符合条件的记录,则返回字符串“没有最高管理者,请指定”

DECLARE

v_ename emp.ename%TYPE;v_job emp.job%TYPE;

BEGIN

SELECT ename,jobINTO v_ename,v_jobFROM empWHERE mgr IS NULL;dbms_output.put_line(v_ename || ',' || v_job);

EXCEPTION

WHEN too_many_rows THENdbms_output.put_line('最高管理者人员过多');WHEN no_data_found THENdbms_output.put_line('没有最高管理者,请指定');

END;

5、获得每个部门的平均工资,如果平均工资大于15000,视为用户定义的异常,提示“该部门的平均工资过高”

DECLARE

e_high_sal EXCEPTION;

BEGIN

FOR v_count IN(SELECT deptno,AVG(sal) avgsalFROM empGROUP BY deptno) LOOPIF v_count.avgsal>15000 THENRAISE e_high_sal;dbms_output.put_line(v_count.deptno);END IF;                END LOOP;

EXCEPTION

WHEN e_high_sal THENdbms_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_salFROM emp;SELECT COUNT(empno)INTO v_count_empnoFROM empWHERE sal>v_avg_sal;IF v_count_empno<=5 THENRAISE e_too_low;ELSIF v_count_empno>5 THENRAISE e_too_many;END IF;

EXCEPTION

WHEN e_too_many THENdbms_output.put_line('大于平均工资的人数太少');WHEN e_too_low THENdbms_output.put_line('大于平均工资的人数不少');

END;

第5章 存储过程
练习1

1.写一个存储过程getAllDept,遍历所有部门。

CREATE OR REPLACE PROCEDURE getAllDept

ISCURSOR dept_cursorISSELECT deptno,dname ,locFROM dept;

BEGIN

FOR dept_record IN dept_cursor LOOPdbms_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)ISv_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 THENCOMMIT;dbms_output.put_line('新建部门成功');ELSEROLLBACK;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)ISv_count NUMBER(2);

BEGIN

SELECT COUNT(deptno)INTO v_countFROM deptWHERE deptno=p_deptno;IF v_count>0 THENUPDATE deptSET dname=p_dname,loc=p_locWHERE deptno=p_deptno;       IF SQL%ROWCOUNT>0 THENCOMMIT;dbms_output.put_line('修改部门成功');ELSEROLLBACK;dbms_output.put_line('修改部门失败'||SQLERRM);     END IF;   ELSEdbms_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,locINTO p_dname,p_locFROM deptWHERE 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)

ISv_count NUMBER(2);

BEGIN

SELECT COUNT(empno)INTO V_countFROM empWHERE deptno=p_deptno;IF v_count >0 THENdbms_output.put_line('该部门下存在员工,不能删除');ELSEDELETE FROM dept WHERE deptno=p_deptno;IF SQL%ROWCOUNT >0 THENCOMMIT;dbms_output.put_line('删除部门成功');ELSEROLLBACK;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_curISSELECT b.*FROM (SELECT ROWNUM rn,ename,dnameFROM emp e,dept dWHERE e.deptno=d.deptnoAND e.deptno=p_deptnoAND ROWNUM<=p_pageNo*p_pageCount) bWHERE rn>(p_pageNo-1)*p_pageCOunt;

BEGIN

FOR emp_record IN emp_cur LOOPdbms_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)ISv_ecount NUMBER(2);v_dcount NUMBER(2);v_maxid emp_jobhistory.id%TYPE;

BEGIN

p_flag := FALSE;--判断传入的员工编号和部门编号是否有效SELECT COUNT(empno)INTO v_ecountFROM empWHERE empno=p_empno AND deptno=p_olddeptno;IF v_ecount<=0THENdbms_output.put_line('员工编号或部门编号无效');RETURN;END IF;--判断新部门编号是否有效SELECT COUNT(deptno)INTO v_dcountFROM deptWHERE deptno=p_newdeptno;IF v_dcount<=0THENdbms_output.put_line('要调入的部门编号无效');RETURN;END IF;--修改员工当前部门编号UPDATE empSET deptno = p_newdeptnoWHERE empno = p_empno;IF SQL%ROWCOUNT<=0 THENROLLBACK;dbms_output.put_line('调转失败');RETURN;END IF;--读取最大IDSELECT MAX(ID)INTO v_maxidFROM emp_jobhistory;IF v_maxid IS NULL THENv_maxid :=0;END IF; --向历史岗位表中插入一条记录INSERT INTO emp_jobhistoryVALUES(v_maxid+1,p_empno,p_olddeptno,p_newdeptno,p_date,p_type,p_res);IF SQL%ROWCOUNT>0 THENCOMMIT;dbms_output.put_line('调转成功');p_flag :=TRUE;ELSEROLLBACK;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)ISv_maxid NUMBER(6);

BEGIN

p_flag :=FALSE;--更新员工当前状态UPDATE empSET status=2WHERE empno=p_empno;   IF SQL%ROWCOUNT<=0THENROLLBACK;dbms_output.put_line('离职失败 :'||SQLERRM);RETURN ;END IF;--读取当前最大IDSELECT MAX(ID)INTO v_maxidFROM dimission;IF v_maxid IS NULL THENv_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 THENCOMMIT;p_flag :=TRUE;dbms_output.put_line('办理离职成功');ELSEROLLBACK;dbms_output.put_line('办理离职失败'||SQLERRM);END IF;

END;

4.写一个存储过程searchDim,实现遍历指定时间段办理入职的员工姓名。

CREATE OR REPLACE PROCEDURE searchDim(p_begindate DATE,

                                  p_enddate DATE)ISCURSOR emp_cur ISSELECT ename,dimdate from dimission d,emp eWHERE d.empno=e.empnoAND dimdate>=p_begindateAND dimdate<p_enddate;

BEGIN

FOR emp_rec IN emp_cur LOOPdbms_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 NUMBERISv_tax NUMBER;v_sal emp.sal%TYPE;

BEGIN

SELECT salINTO v_salFROM empWHERE empno=p_empno;IF v_sal<1000 THENv_tax :=0;ELSIF v_sal BETWEEN 1000 AND 2000 THENv_tax :=v_sal*0.05;ELSEv_tax :=v_sal*0.1;END IF;RETURN v_tax;

END;

2.写一个块,调用上述函数。

DECLARE

CURSOR tax_cursorISSELECT ename,sal,empnoFROM emp;v_tax emp.sal%TYPE;

BEGIN

FOR tax_record IN tax_cursor LOOPv_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%TYPEISv_ename emp.ename%TYPE;

BEGIN

SELECT enameINTO v_enameFROM empWHERE empno = p_empno;RETURN v_ename;

EXCEPTION

WHEN no_Data_found THENRETURN NULL;dbms_output.put_line('指定编号员工不存在'); WHEN too_many_rows THENRETURN 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%TYPEISv_maxsal emp.sal%TYPE;v_count NUMBER(2) ;

BEGIN

SELECT COUNT(deptno)INTO v_countFROM deptWHERE deptno = p_deptno;IF v_count<=0 THENdbms_output.put_line('部门编号无效');RETURN -1;END IF;   SELECT MAX(sal)INTO v_maxsalFROM empWHERE deptno=p_deptno;RETURN v_maxsal;

END;

3、创建一个存储过程,查询dept表的所有部门信息,调用该函数,当函数返回的薪水大于4000时,产生异常,在异常部分显示’某某部门的薪水太高了’。

CREATE OR REPLACE PROCEDURE finAllDeptMaxSal

ISe_exec EXCEPTION;v_dname VARCHAR2(100);v_sal emp.sal%TYPE;

BEGIN

FOR dept_record IN(SELECT *FROM dept) LOOPv_sal :=getmaxsal(dept_record.deptno);IF v_sal >=4000 THENIF v_dname IS NULL THENv_dname :=dept_record.dname;ELSEv_dname :=v_dname||','||dept_record.dname;END IF; END IF;END LOOP;IF v_dname IS NOT NULL THENRAISE e_exec;END IF;

EXCEPTION

WHEN e_exec THENdbms_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

 ISFUNCTION 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 BOOLEANISv_deptno dept.deptno%TYPE;BEGINSELECT COUNT(deptno)INTO v_deptnoFROM deptWHERE deptno=p_deptno;IF v_deptno>0 THENRETURN TRUE;ELSEreturn FALSE;END IF;END;--1.2:过程:查询当前所有部门信息PROCEDURE searchAllDeptISBEGINFOR dept_record IN(SELECT *FROM dept) LOOPdbms_output.put_line(dept_record.dname);END LOOP;END;--1.3:过程:新建一个部门,成功返回新建的部门编号,失败返回-1PROCEDURE addDept(p_dname dept.dname%TYPE,p_loc dept.loc%TYPE,p_deptno OUT dept.deptno%TYPE)ISv_deptno dept.deptno%TYPE;BEGINSELECT MAX(deptno)INTO v_deptnoFROM dept;INSERT INTO dept(deptno,dname,loc)VALUES(v_deptno+1,p_dname,p_loc);IF SQL%ROWCOUNT>0 THENCOMMIT;p_deptno :=v_deptno+1;dbms_output.put_line('新建部门成功');ELSEROLLBACK;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)ISBEGINSELECT DName,locINTO p_dname,p_locFROM deptWHERE deptno=p_deptno;END;--1.5:过程:根据部门编号修改部门信息PROCEDURE updateDept(p_deptno dept.deptno%TYPE,p_dname  dept.dname%TYPE,p_loc  dept.loc%TYPE)ISBEGIN--验证部门编号是否有效IF validDept(p_deptno) THENUPDATE deptSET dname=p_dname,loc = p_locWHERE deptno=p_deptno;IF SQL%ROWCOUNT>0 THENCOMMIT;dbms_output.put_line('修改部门成功');ELSEROLLBACK;dbms_output.put_line('修改部门失败'||SQLERRM);END IF;ELSEdbms_output.put_line(p_deptno ||'是一个无效的部门编号');END IF;END;--1.6:过程:根据部门编号查询部门所有员工信息PROCEDURE searchAllEmp(p_deptno dept.deptno%TYPE)ISCURSOR emp_curISSELECT *FROM empWHERE deptno=p_deptno;BEGINFOR emp_record IN emp_cur LOOPdbms_output.put_line(p_deptno||'号部门员工为:'||emp_record.ename);END LOOP;END;--1.7:过程:根据部门编号删除一个部门,之前要判断该部门下是否存在员工,如果存在员工,则提示用户“部门下已经存在员工,不能删除该部门”。PROCEDURE delDept(p_deptno dept.deptno%TYPE)ISv_count NUMBER(2);BEGINSELECT COUNT(empno)INTO V_countFROM empWHERE deptno = p_deptno;IF v_count>0 THENdbms_output.put_line('该部门下存在员工,不能删除');ELSEDELETE FROM deptWHERE deptno=p_deptno;IF SQL%ROWCOUNT >0 THENCOMMIT;dbms_output.put_line('删除部门成功');ELSEROLLBACK;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

ISPROCEDURE 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

ISPROCEDURE add_user(p_empno IN test.empno%TYPE,p_ename IN test.ename%TYPE,p_sal IN test.sal%TYPE)ISBEGININSERT INTO testVALUES(p_empno,p_ename,p_sal);COMMIT;END;PROCEDURE del_user(p_empno IN test.empno%TYPE)ISBEGINDELETE FROM testWHERE empno=p_empno;commit;END;FUNCTION add_sal(p_empno IN test.empno%TYPE,p_sal IN test.sal%TYPE) RETURN NUMBERISv_sal NUMBER(10);BEGINUPDATE testSET sal=sal+p_salWHERE empno=p_empno;COMMIT;SELECT salINTO v_salFROM testWHERE 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') THENraise_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') THENraise_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') THENraise_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_maxidFROM emp_jobhistory;INSERT INTO Emp_JobhistoryVALUES(v_maxid+1,:old.empno,:old.deptno,:new.deptno,SYSDATE,NULL,NULL);

END;

课件及习题答案汇总word文档百度云地址:

链接: https://pan.baidu.com/s/1H9cw1OpKu4B96F2yBwOfZQ
提取码: 8phq

Oracle数据库PL SQL开发、Oracle-SQL开发习题答案相关推荐

  1. ORACLE数据库查询锁表语句sql脚本,以及删除锁信息脚本(数据库开发ETL、DBA必备)

    ORACLE数据库查询锁表语句sql脚本,以及删除锁信息脚本(数据库开发ETL.DBA必备) 文章目录 ORACLE数据库查询锁表语句sql脚本,以及删除锁信息脚本(数据库开发ETL.DBA必备) 前 ...

  2. oracle写SQL快捷键,Oracle数据库PL/SQL快捷键设置详解

    Oracle数据库中,PL/SQL设置快捷键的方法是本文我们主要要介绍的内容,了解了这些设置可以是我们更效率地使用Oracle数据库,接下来就让我们一起来了解一下这部分内容吧. 1.登录后默认自动选中 ...

  3. oracle 不能导入sql语句,oracle数据库导入.dmp脚本的sql 语句

    一.更改数据库管理员sys/system密码 1.运行到C盘根目录 2.输入:SET ORACLE_SID = 你的SID名称 3.输入:sqlplus /nolog 4.输入:connect /as ...

  4. oracle数据库初始化失败怎么办,oracle数据库正常停止

    利用dbstart和dbshut脚本自动启动和停止数据库的问题 客户的两台IBM Power 740小型机使用HACMP软件创建互备关系的数据库服务器,每台小型机运行一个数据库,任何一台服务器出现故障 ...

  5. oracle数据库各组件介绍,Oracle 数据库 组件相关说明【第一部分】

    参考MOS文档: Information On Installed Database Components and Schemas (文档 ID 472937.1) Oracle 组件可以通过下面的S ...

  6. oracle数据库exp备份表,oracle数据库exp备份表

    Oracle exp/imp,备份或导入时注意的事项 Oracle exp/imp,备份或导入时注意的事项: 本篇主要讲述的是Oracle exp/imp备份导入的实际操作中需要注意的事项的介绍,凡事 ...

  7. Oracle数据库用管理员登录,oracle数据库关于用户登录

    本文主要向大家介绍了oracle数据库关于用户登录的问题,通过具体的内容向大家展现,希望对大家学习oracle数据库有所帮助. oracle 数据库的安装 : 一: 安装的时候可以设定解锁的用户  一 ...

  8. oracle数据库没有选项,创建oracle数据库时,出现ORA-00922: 选项缺失或无效

    sdd53HOME 新建oracle数据库时遇到ORA-00922: 选项缺失或无效的问题,如图: 原因:一般是语句的语法有问题.比如命名不对,关键字写错等等.对于非标准的命名,一般采用双引号来创建. ...

  9. oracle数据库存储结构语句,oracle之物理数据库结构描述

    oracle之物理数据库结构概述 oracle的物理结构其实是由各种各样的文件组成的, 其中与数据库相关的有: 数据文件(data file):这些文件是数据库的主要文件:其中包括数据表.索引和所有其 ...

  10. oracle 数据库问题,ORACLE数据库常见问题汇总,oracle常见问题汇总

    ORACLE数据库常见问题汇总,oracle常见问题汇总 提交事务的时候提示(数据库被一个用户锁住的解决方法) select object_id,session_id,locked_mode from ...

最新文章

  1. Google刚刚开源了一款用于测试iOS应用的工具:EarlGrey
  2. ubuntu 系统设置bugzilla制
  3. [JS]计算字符串中出现最多的字符和其出现次数
  4. led控制器java_TM1668 Led 驱动芯片源程序
  5. Android 自定义View实现画背景和前景(ViewGroup篇)
  6. 【BZOJ28431180】极地旅行社,LCT练习
  7. 大数据 挑战 机会_大数据可视化面临哪些挑战
  8. mysql相关知识点_mysql相关知识点整理
  9. 啦啦啦-我又来了!!!
  10. pca各个向量之间的相关度_机器学习十大经典算法之PCA主成分分析
  11. python爬取网页原理_网页基本构成和抓取原理
  12. html中背景属性的缩写语法,CSS缩写
  13. ie11不兼容window.createPopup的问题解决
  14. execution常用表达式整理
  15. 在anaconda设置Python的IDEL编辑器
  16. FT2232作为JTAG烧录器的使用步骤详解
  17. 计算机毕业设计JAVA汽车配件管理系统mybatis+源码+调试部署+系统+数据库+lw
  18. python中[::]的含义
  19. Linux 多线程编程(三)
  20. 计算机单机游戏c0005错误,单机游戏安装中出现的错误,我教你解决它!

热门文章

  1. AVM 环视拼接方法介绍
  2. 驱动调试-摄像头部分
  3. linux开启(永久)端口
  4. Word更新所有域的代码
  5. 登录和第三方授权(Cookie和Authorization)
  6. Quick #UE4 Tip (第3周 2020.4.10)
  7. git 本地回退到某个版本
  8. 销量“掉队”,零跑汽车火力全开
  9. MapReduce理解-深入理解MapReduce
  10. 中国科学院院士徐宗本:人工智能的基石是数学