Oracle数据库PL SQL开发、Oracle-SQL开发习题答案

第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

 

3. 当前日期为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);

 

3. 查询部门最低工资高于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

 

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;

 

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

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

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

 

练习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

程序输出为:插入部门成功

 

3.

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为假

 

4.

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

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

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

1. 编写一个匿名块,分别对部门做一个查询、插入、修改、删除操作,验证这几个操作执行后的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

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

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

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/1UQcb3sGaEHqS5vzWy5EnlQ

密码:34u2

你可能感兴趣的:(Oracle数据库PL SQL开发、Oracle-SQL开发习题答案)