1. 第一部分:oracle pl/sql实例练习(1)  
  2. 一、使用scott/tiger用户下的emp表和dept表完成下列练习,表的结构说明如下  
  3. emp员工表(empno员工号/ename员工姓名/job工作/mgr上级编号/hiredate受雇日期/sal薪金/comm佣金/deptno部门编号)  
  4. dept部门表(deptno部门编号/dname部门名称/loc地点)  
  5. 工资 = 薪金 + 佣金  
  6. 也可以通过以下脚本测试:  
  7. create table DEPT  
  8. (  
  9. DEPTNO NUMBER(2) not null,  
  10. DNAME VARCHAR2(14),  
  11. LOC    VARCHAR2(13)  
  12. )  
  13. tablespace USERS;  
  14. alter table DEPT add constraint PK_DEPT primary key (DEPTNO);  
  15. insert into DEPT (DEPTNO, DNAME, LOC)  
  16. values (10, 'ACCOUNTING''NEW YORK');  
  17. insert into DEPT (DEPTNO, DNAME, LOC)  
  18. values (20, 'RESEARCH''DALLAS');  
  19. insert into DEPT (DEPTNO, DNAME, LOC)  
  20. values (30, 'SALES''CHICAGO');  
  21. insert into DEPT (DEPTNO, DNAME, LOC)  
  22. values (40, 'OPERATIONS''BOSTON');  
  23. commit;  
  24. create table EMP  
  25. (  
  26. EMPNO    NUMBER(4) not null,  
  27. ENAME    VARCHAR2(10),  
  28. JOB      VARCHAR2(9),  
  29. MGR      NUMBER(4),  
  30. HIREDATE DATE,  
  31. SAL      NUMBER(7,2),  
  32. COMM     NUMBER(7,2),  
  33. DEPTNO   NUMBER(2)  
  34. )  
  35. tablespace USERS;  
  36. alter table EMP add constraint PK_EMP primary key (EMPNO);  
  37. insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)  
  38. values (7369, 'SMITH''CLERK', 7902, to_date('17-12-1980''dd-mm-yyyy'), 800, null, 20);  
  39. insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)  
  40. values (7499, 'ALLEN''SALESMAN', 7698, to_date('20-02-1981''dd-mm-yyyy'), 1600, 300, 30);  
  41. insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)  
  42. values (7521, 'WARD''SALESMAN', 7698, to_date('22-02-1981''dd-mm-yyyy'), 1250, 500, 30);  
  43. insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)  
  44. values (7566, 'JONES''MANAGER', 7839, to_date('02-04-1981''dd-mm-yyyy'), 2975, null, 20);  
  45. insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)  
  46. values (7654, 'MARTIN''SALESMAN', 7698, to_date('28-09-1981''dd-mm-yyyy'), 1250, 1400, 30);  
  47. insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)  
  48. values (7698, 'BLAKE''MANAGER', 7839, to_date('01-05-1981''dd-mm-yyyy'), 2850, null, 30);  
  49. insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)  
  50. values (7782, 'CLARK''MANAGER', 7839, to_date('09-06-1981''dd-mm-yyyy'), 2450, null, 10);  
  51. insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)  
  52. values (7788, 'SCOTT''ANALYST', 7566, to_date('19-04-1987''dd-mm-yyyy'), 3000, null, 20);  
  53. insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)  
  54. values (7839, 'KING''PRESIDENT'null, to_date('17-11-1981''dd-mm-yyyy'), 5000, null, 10);  
  55. insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)  
  56. values (7844, 'TURNER''SALESMAN', 7698, to_date('08-09-1981''dd-mm-yyyy'), 1500, 0, 30);  
  57. insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)  
  58. values (7876, 'ADAMS''CLERK', 7788, to_date('23-05-1987''dd-mm-yyyy'), 1100, null, 20);  
  59. insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)  
  60. values (7900, 'JAMES''CLERK', 7698, to_date('03-12-1981''dd-mm-yyyy'), 950, null, 30);  
  61. insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)  
  62. values (7902, 'FORD''ANALYST', 7566, to_date('03-12-1981''dd-mm-yyyy'), 3000, null, 20);  
  63. insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)  
  64. values (7934, 'MILLER''CLERK', 7782, to_date('23-01-1982''dd-mm-yyyy'), 1300, null, 10);  
  65. commit;  
  66.  
  67. 二、问题:  
  68. 1.列出至少有一个员工的所有部门。  
  69. 2.列出薪金比“SMITH”多的所有员工。  
  70. 3.列出所有员工的姓名及其直接上级的姓名。  
  71. 4.列出受雇日期早于其直接上级的所有员工。  
  72. 5.列出最低薪金大于1500的各种工作。  
  73. 6.列出在每个部门工作的员工数量、平均工资和平均服务期限。  
  74. 答案:  
  75. 1.列出至少有一个员工的所有部门。  
  76. select deptno from emp group by deptno having count(*)>1;  
  77. 解析:该语句主要学习分组函数group by,以及对分组后过滤的条件函数having。需要注意的是使用了分组函数语句的select字段中不能包含group by后没有的字段,原因是如果显示非分组的字段就可能显示多条记录,就达不到按某字段分组的目的。Having只能用在分组函数group by后,相当于对分组后的记录做where条件过滤。  
  78. 2.列出薪金比“SMITH”多的所有员工。  
  79. select * from emp where sal>(select sal from emp where ename='SMITH');  
  80. 解析:该语句主要学习子查询,且子查询在where条件的后面。注意和3的区别。  
  81. 3.列出所有员工的姓名及其直接上级的姓名。  
  82. select ename,(select ename from emp where empno=a.mgr) from emp a;  
  83. 解析:该语句主要学习子查询,且子查询在select 和 from的中间,同时内部语句使用了外部语句的字段。注意和2的区别。  
  84. 4.列出受雇日期早于其直接上级的所有员工。  
  85. select ename from emp a where hiredate>(select hiredate from emp where empno=a.mgr);  
  86. 解析:该语句主要学习子查询,且子查询在where条件的后面。同时内部语句使用了外部语句的字段。注意和2的区别。注意和2的区别。  
  87. 5.列出最低薪金大于1500的各种工作。  
  88. select job,min(sal) msal from emp group by job having min(sal)>1500;  
  89. 解析:该语句主要学习分组函数,功能同1。  
  90. 6.列出在每个部门工作的员工数量、平均工资和平均服务期限。  
  91. select deptno,count(*), trunc(avg(sal+nvl(comm,0))) avgsal, trunc(avg(sysdate-hiredate)) avgday from emp group by deptno;  
  92. 解析:该语句主要学习分组函数,同时学习其相关的统计函数countavg等。  
  93. 三、以下是过程、函数的学习事例。所有的过程和函数都放到了package下面。  
  94. 包声明:  
  95. create or replace package MyPack1 is 
  96. --过程模板  
  97. procedure P_Templet(i_myNumber In Number,o_myVarchar Out varchar2);  
  98. function f_Templet(i_a1 varchar2,i_a2 Number) return number;  
  99. --声明一个游标  
  100. type Ref_Cursor_Type is ref cursor;  
  101. --列出至少有一个员工的所有部门  
  102. procedure p_test1;  
  103. --列出薪金比“SMITH”多的所有员工  
  104. function f_test2(i_ename emp.ename%type) return number;  
  105. end MyPack1;  
  106. 包实现:  
  107. create or replace package body MyPack1 is 
  108. --过程模板  
  109.     procedure P_Templet(i_myNumber In Number,  
  110.        o_myVarchar Out varchar2) is 
  111.     myDate      date;  
  112.     myNumber    Number(10);  
  113.     myVarchar   varchar2(50);  
  114. begin 
  115.        null;  
  116.        exception  
  117.        when others then 
  118.        dbms_output.put_line('程序出现了异常!'||Sqlcode||Sqlerrm);  
  119. end;  
  120. ---------------------------------------------------  
  121. --函数模板  
  122. function f_Templet(i_a1 varchar2,i_a2 Number) return number is 
  123.     myDate      date;  
  124.     myNumber    Number(10);  
  125.     myVarchar   varchar2(50);  
  126. begin 
  127.        null;  
  128.        exception  
  129.        when others then 
  130.       dbms_output.put_line('程序出现了异常!'||Sqlcode||Sqlerrm);  
  131.        return myNumber;  
  132. end;  
  133. -----------------------------------------------------  
  134. --列出至少有一个员工的所有部门  
  135. --用一个sql语句实现:select count(*),deptno from emp group by deptno having count(*)>1;  
  136. --主要学习过程的写法,以及游标的用法。  
  137. procedure p_test1 is 
  138.    v_deptno         dept.deptno%type;  
  139.    v_deptname         dept.dname%type;  
  140.    v_count1    Number(10);  
  141.    C1               Ref_Cursor_Type;  
  142. begin 
  143.         open C1 for 
  144.           select distinct deptno,dname from dept;  
  145.          loop  
  146.         fetch C1  
  147.           into v_deptno,v_deptname;  
  148.            exit when C1%notfound;  
  149.              begin 
  150.              select count(*) into v_count1 from emp e where e.deptno=v_deptno;  
  151.              if(v_count1>0) then 
  152.                Dbms_Output.Put_Line(v_deptname);  
  153.              else null;  
  154.              end if;  
  155.              end;  
  156.         end loop;  
  157.        exception  
  158.       when others then 
  159.         null;  
  160. end;  
  161. -----------------------------------------------------  
  162. --列出薪金比“SMITH”多的所有员工  
  163. --用一个sql语句实现:select * from emp where sal>(select sal from emp where ename='SMITH');  
  164. -- 调用该函数的语句:select * from (select ename,mypack1.f_test2(ename) as count1 from(select --distinct t.ename from emp t) ) where count1>0  
  165. --主要学习函数的写法,学习外部sql如何调用该函数,因为这样调用对条件控制或分页等更灵活,同--时降低了函数的复杂性。  
  166. function f_test2(i_ename emp.ename%type) return number is 
  167.    v_sal    Number(10);  
  168.    v_sal2    Number(10);  
  169.    v_return    Number(10);  
  170. begin 
  171.        begin 
  172.             select sal into v_sal from emp where ename='SMITH';  
  173.             exception  
  174.                 when others then 
  175.                 v_sal :=0;  
  176.        end;  
  177.        begin 
  178.             select sal into v_sal2 from emp where ename=i_ename;  
  179.             exception  
  180.                 when others then 
  181.                 v_sal2 :=0;  
  182.        end;  
  183.        v_return := v_sal2-v_sal;  
  184.        return v_return;  
  185. end;  
  186. end MyPack1;  
  187. ---------------------------------------------------------------  
  188. 第二部分:oracle pl/sql实例练习(2)  
  189. --创建测试表  
  190. create table TESTTABLE  
  191. (  
  192. ID          NUMBER(4) not null,  
  193. CURRENTDATE DATE not null 
  194. )  
  195. --------------------------------------------------------------  
  196. 实例1  
  197. --该实例要学习如何通过pl/sql批量插入数据,以及常量、For的用法。  
  198. Declare 
  199. maxrecords Constant Int:=100;  
  200. Int:=1;  
  201. Begin 
  202.         For i In 1..maxrecords Loop  
  203.             Insert Into testtable(id,currentdate)  
  204.             Values(i,Sysdate);  
  205.             dbms_output.put_line('现在插入的内容是:'||i||'   '||Sysdate);  
  206.             Commit;         --这里切记要commit否则将不会将数据提交到表中  
  207.         End Loop;  
  208.         dbms_output.put_line(maxrecords||'条记录已经插入。');  
  209. End;  
  210. ------------------------------------------------------------------  
  211. 实例2  
  212. --这种写法是为了简化多个选择用if来做判断。  
  213. Declare 
  214.         v_test Int:=60;         
  215.         Begin 
  216.              Case v_test  
  217.              When 90 Then 
  218.              dbms_output.put_line('v_test的值为:90!');  
  219.              When 80 Then 
  220.              dbms_output.put_line('v_test的值为:80!');  
  221.              Else 
  222.              dbms_output.put_line('v_test的值我不知道!');  
  223.              End Case;  
  224.         End;  
  225.          
  226. ------------------------------------------------------  
  227. 实例3  
  228. --完整定义了一个记录类型的变量,简单应用。这里要学习如何使用Record类型变量。  
  229. Declare 
  230.         Type myrecord Is Record(  
  231.              r_Id Number(4),  
  232.              r_currentdate Date 
  233.              );  
  234.         v_myrecord myrecord;  
  235.         Begin 
  236.              Select * Into v_myrecord From testtable Where id=10;  
  237.              dbms_output.put_line('用记录类型的变量取出来的值为:'||  
  238.                                   v_myrecord.r_Id||' '||v_myrecord.r_currentdate);  
  239.         End;  
  240. ------------------------------------------------------------  
  241. 实例4  
  242. --学习使用%Rowtype定义变量  
  243. Declare 
  244.         v_myrow testtable%Rowtype;  
  245.         Begin 
  246.              Select * Into v_myrow From testtable Where id=20;  
  247.              dbms_output.put_line('用rowtype查询的结果是:'||v_myrow.id||v_myrow.currentdate);  
  248.         End;  
  249. ---------------------------------------------------------------  
  250. 实例5  
  251. --学习如何定义一维表变量,以及如何给一维表变量赋值。这种变量类似编程语言中的一维数组  
  252. Declare 
  253.        Type mytbtype1 Is Table Of Varchar2(4) Index By Binary_Integer;  
  254.        Type mytbtype2 Is Table Of testtable.id%Type Index By Binary_Integer;  
  255.        tb1 mytbtype1;  
  256.        tb2 mytbtype2;  
  257.        Begin 
  258.             tb1(1):='大学';  
  259.             tb1(2):='大专';  
  260.             dbms_output.put_line(tb1(1)||tb1(2));  
  261.             select id BULK COLLECT into tb2 from testtable where id<10 order by id;  
  262.             For i In 1..tb2.count Loop  
  263.               dbms_output.put_line(tb2(i));  
  264.             End Loop;  
  265.        End;  
  266.         
  267.         
  268. ------------------------------------------------------------  
  269. 实例6  
  270. --定义一个多维表变量,这就像一个二维数组  
  271. --当然这个二维的数组的下表就有些区别与我们在编程语言中熟悉的二维数组了  
  272. --可以理解为一维存储的列名,而另一维则是存储与一维列名相对应的数据  
  273. Declare 
  274.        --这里区别与一维表变量的定义  
  275.        Type multbtype Is Table Of testtable%Rowtype Index By Binary_Integer;  
  276.        multb multbtype;  
  277.        Begin 
  278.             Select * Into multb(1)  
  279.             From testtable  
  280.             Where id=88;  
  281.             dbms_output.put_line('multb(1).id='||  
  282.                                  multb(1).id||  
  283.                                  ' multb(1).currentedate'||  
  284.                                  multb(1).currentdate  
  285.                                  );  
  286.        End;  
  287.         
  288.         
  289.         
  290. --------------------------------------------------------------------  
  291. 实例7     
  292. --这里主要学习oracle中的‘数组’的属性和方法,有点类似数据结构中的链表  
  293. Declare 
  294.        Type mytabletype Is Table Of Varchar2(9) Index By Binary_Integer;  
  295.        tb mytabletype;  
  296.        Begin 
  297.             tb(1):='成都市';  
  298.             tb(2):='太原市';  
  299.             tb(3):='北京市';  
  300.             dbms_output.put_line('记录总数:'||to_char(tb.Count));  
  301.             dbms_output.put_line('第一条记录为:'||tb.First||'其值为:'||tb(tb.First));  
  302.             dbms_output.put_line('最后条记录为:'||tb.Last||'其值为:'||tb(tb.Last));  
  303.             dbms_output.put_line('第二条的前一条记录为:'||tb.Prior(2)||'其值为:'||tb(tb.Prior(2)));  
  304.             dbms_output.put_line('第二条的后一条记录为:'||tb.Next(2)||'其值为:'||tb(tb.Next(2)));  
  305.             dbms_output.put_line('第二条记录为:'||tb(2));  
  306.             tb.Delete(2);  
  307.             dbms_output.put_line('删除第二条记录后的第二条记录为:'||tb(3));  
  308.             --exists存在的问题,不知到怎么使用  
  309.             --tb.Exists('太原市');  
  310.        End;  
  311.         
  312. ---------------------------------------------------------------------  
  313. 实例8  
  314. --学习如何定义和使用游标,这里展示了%isopen,%found,%Rowcount  
  315. Declare 
  316.        Cursor mycursor Is 
  317.               Select * From testtable e  
  318.               Where e.id<100;  
  319.        currentrecord mycursor%Rowtype;  
  320.        Begin 
  321.             --打开游标  
  322.             If mycursor%Isopen Then 
  323.                dbms_output.put_line('该游标已经打开了,正在关闭!');  
  324.                Close mycursor;  
  325.             Else 
  326.                dbms_output.put_line('游标已经关闭');  
  327.             End If;  
  328.             --读取数据  
  329.             Open mycursor;--打开游标时最好做判断当前游标是否是关闭的,这里略写  
  330.             Loop  
  331.             Fetch mycursor Into currentrecord;  
  332.             Exit When mycursor%Notfound;  
  333.             Begin 
  334.                 dbms_output.put_line('游标已经取到数据,查询结果是:');  
  335.                 dbms_output.put_line(to_char(currentrecord.id||currentrecord.currentdate));  
  336.     End;  
  337.     End Loop;  
  338.     Close mycursor;--关闭游标时最好做判断当前游标是否是打开的,这里略写  
  339.             --读取记录总条数  
  340.             Open mycursor;  
  341.             Loop  
  342.                 Fetch mycursor Into currentrecord;             
  343.             Exit When mycursor%Notfound;  
  344.             End Loop;  
  345.             dbms_output.put_line('查结果总共有:'||mycursor%Rowcount);  
  346.             --关闭游标  
  347.             If mycursor%Isopen Then 
  348.              dbms_output.put_line('正在关闭游标。');                                                              
  349.             Close mycursor;  
  350.             End If;  
  351.        End;  
  352. --------------------------------------------------------------------------  
  353. 实例9  
  354. --学习存储过程如何带输入参数和输出参数  
  355. Create Or Replace Procedure myprocedure(  
  356.        i_id In testtable.id%Type,  
  357.        o_currentdate Out testtable.currentdate%Type) Is 
  358.        v_currentdate testtable.currentdate%Type;  
  359.        Begin 
  360.             Select currentdate Into v_currentdate From testtable t Where t.id=i_id;  
  361.             dbms_output.put_line('currentdate:'||v_currentdate);  
  362.             o_currentdate:=v_currentdate;  
  363.             Exception  
  364.             When Others Then 
  365.             dbms_output.put_line('程序出现了异常!'||Sqlcode||Sqlerrm);  
  366.        End