实例1--if语句
/* 慕课网Oracle数据库开发必备之PL/SQL_2-3 判断用户从键盘输入的数字 1.如何使用if语句 2.接收一个键盘的输入(字符串) */ set serveroutput on; --接收一个键盘输入 --num:地址值,含义是:在该地址上保存了输入的值 accept num prompt '请输入一个数字'; declare --定义变量保存键盘输入的数字 pnum number := # begin --执行if语句进行条件判断 if pnum=0 then dbms_output.put_line('您输入数字是:0'); elsif pnum=1 then dbms_output.put_line('您输入数字是:1'); elsif pnum=2 then dbms_output.put_line('您输入数字是:2'); else dbms_output.put_line('您输入数字是:其他数字'); end if; end; /
实例2--while语句
/* 慕课网Oracle数据库开发必备之PL/SQL_2-4 while循环语句打印数字1-10 */ set serveroutput on declare pnum number := 1; begin while pnum<=10 loop dbms_output.put_line (pnum); pnum := pnum +1; end loop; end; /
实例3--loop语句
/* 慕课网Oracle数据库开发必备之PL/SQL_2-4 loop循环语句打印数字1-10 */ set serveroutput on declare pnum number := 1; begin loop exit when pnum>10; dbms_output.put_line (pnum); pnum := pnum +1; end loop; end; /
实例3--for语句
/* 慕课网Oracle数据库开发必备之PL/SQL_2-4 for循环语句打印数字1-10 for循环的格式: for i in 1..9 loop end loop; */ set serveroutput on declare pnum number := 1 ; begin for pnum in 1..10 loop dbms_output.put_line (pnum); end loop; end; /
慕课网建表sql:
select * from dept DROP TABLE DEPT; CREATE TABLE DEPT (DEPTNO NUMBER(2) CONSTRAINT PK_DEPT PRIMARY KEY, DNAME VARCHAR2(14) , LOC VARCHAR2(13) ) ; DROP TABLE EMP; CREATE TABLE EMP (EMPNO NUMBER(4) CONSTRAINT PK_EMP PRIMARY KEY, ENAME VARCHAR2(10), JOB VARCHAR2(9), MGR NUMBER(4), HIREDATE DATE, SAL NUMBER(7,2), COMM NUMBER(7,2), DEPTNO NUMBER(2) CONSTRAINT FK_DEPTNO REFERENCES DEPT); INSERT INTO DEPT VALUES (10,'ACCOUNTING','NEW YORK'); INSERT INTO DEPT VALUES (20,'RESEARCH','DALLAS'); INSERT INTO DEPT VALUES (30,'SALES','CHICAGO'); INSERT INTO DEPT VALUES (40,'OPERATIONS','BOSTON'); INSERT INTO EMP VALUES (7369,'SMITH','CLERK',7902,to_date('17-12-1980','dd-mm-yyyy'),800,NULL,20); INSERT INTO EMP VALUES (7499,'ALLEN','SALESMAN',7698,to_date('20-2-1981','dd-mm-yyyy'),1600,300,30); INSERT INTO EMP VALUES (7521,'WARD','SALESMAN',7698,to_date('22-2-1981','dd-mm-yyyy'),1250,500,30); INSERT INTO EMP VALUES (7566,'JONES','MANAGER',7839,to_date('2-4-1981','dd-mm-yyyy'),2975,NULL,20); INSERT INTO EMP VALUES (7654,'MARTIN','SALESMAN',7698,to_date('28-9-1981','dd-mm-yyyy'),1250,1400,30); INSERT INTO EMP VALUES (7698,'BLAKE','MANAGER',7839,to_date('1-5-1981','dd-mm-yyyy'),2850,NULL,30); INSERT INTO EMP VALUES (7782,'CLARK','MANAGER',7839,to_date('9-6-1981','dd-mm-yyyy'),2450,NULL,10); INSERT INTO EMP VALUES (7788,'SCOTT','ANALYST',7566,to_date('13-JUL-87')-85,3000,NULL,20); INSERT INTO EMP VALUES (7839,'KING','PRESIDENT',NULL,to_date('17-11-1981','dd-mm-yyyy'),5000,NULL,10); INSERT INTO EMP VALUES (7844,'TURNER','SALESMAN',7698,to_date('8-9-1981','dd-mm-yyyy'),1500,0,30); INSERT INTO EMP VALUES (7876,'ADAMS','CLERK',7788,to_date('13-JUL-87')-51,1100,NULL,20); INSERT INTO EMP VALUES (7900,'JAMES','CLERK',7698,to_date('3-12-1981','dd-mm-yyyy'),950,NULL,30); INSERT INTO EMP VALUES (7902,'FORD','ANALYST',7566,to_date('3-12-1981','dd-mm-yyyy'),3000,NULL,20); INSERT INTO EMP VALUES (7934,'MILLER','CLERK',7782,to_date('23-1-1982','dd-mm-yyyy'),1300,NULL,10); DROP TABLE BONUS; CREATE TABLE BONUS ( ENAME VARCHAR2(10) , JOB VARCHAR2(9) , SAL NUMBER, COMM NUMBER ) ; DROP TABLE SALGRADE; CREATE TABLE SALGRADE ( GRADE NUMBER, LOSAL NUMBER, HISAL NUMBER ); INSERT INTO SALGRADE VALUES (1,700,1200); INSERT INTO SALGRADE VALUES (2,1201,1400); INSERT INTO SALGRADE VALUES (3,1401,2000); INSERT INTO SALGRADE VALUES (4,2001,3000); INSERT INTO SALGRADE VALUES (5,3001,9999); COMMIT;
游标语法及第一个实例:
--查询并打印员工的薪水(游标的使用) set serveroutput on; declare cursor cemp is select empno,ename,sal from emp; pempno emp.empno%type; pename emp.ename%type; psal emp.sal%type; begin open cemp; loop fetch cemp into pempno,pename,psal; --dbms不能放于此 exit when cemp%notfound; dbms_output.put_line('编号:'||pempno||',姓名:'||pename||',工资:'||psal); end loop; close cemp; end; /
3-3给员工涨工资(游标的使用)
--给员工涨工资,总裁1000,经理800,其他400(游标的使用) set serveroutput on; declare --定义光标代表哪些员工涨工资 cursor cemp is select empno,job from emp; pempno emp.empno%type; pjob emp.job%type; begin --打开光标 open cemp; loop --取出一个员工 fetch cemp into pempno,pjob; exit when cemp%notfound; --判断员工的职位 if 'PRESIDENT'=pjob then update emp set sal= sal+1000 where empno= pempno; elsif 'MANAGER'=pjob then update emp set sal= sal+800 where empno= pempno; else update emp set sal= sal +400 where empno= pempno; end if; end loop; --关闭光标 close cemp; --事务的ACID commit; dbms_output.put_line('涨工资完成!'); end; /
3-4 光标的属性和光标数的限制
3-4-1
/* 1.光标的四个属性: %found;%notfound;%isopen 光标是否打开; %rowcount光标影响的行数 2.光标数的限制 */ set serveroutput on; declare cursor cemp is select empno,job from emp; pempno emp.empno%type; pjob emp.job%type; begin open cemp; if cemp%isopen then dbms_output.put_line('光标是打开的'); else dbms_output.put_line('光标是关闭的'); end if; close cemp; end; /
run:
匿名块已完成
光标是打开的
3-4-2
/* 1.光标的四个属性: %found;%notfound;%isopen 光标是否打开; %rowcount光标影响的行数(可以理解为光标已经取出的数总和) 2.光标数的限制 SQL> conn sys/password@host:1521/XE as sysdba; SQL> show parameters cursor NAME TYPE VALUE open_cursors integer 300 修改光标数的限制 alter system set open_cursors=400 scope=both; scope的取值:both,memory,spfile(数据库需要重启) */ set serveroutput on; declare cursor cemp is select empno,job from emp; pempno emp.empno%type; pjob emp.job%type; begin open cemp; loop fetch cemp into pempno,pjob; exit when cemp%notfound; dbms_output.put_line('光标属性rowcount:'||cemp%rowcount); end loop; close cemp; end; /
run:
匿名块已完成
光标属性rowcount:1
光标属性rowcount:2
光标属性rowcount:3
光标属性rowcount:4
光标属性rowcount:5
光标属性rowcount:6
光标属性rowcount:7
光标属性rowcount:8
光标属性rowcount:9
光标属性rowcount:10
光标属性rowcount:11
光标属性rowcount:12
光标属性rowcount:13
光标属性rowcount:14
3-5 带参数的光标
--查询某个部门中员工的姓名(得定义一个带参的光标 set serveroutput on; declare cursor cemp(dno number) is select ename from emp where deptno=dno; pename emp.ename%type; begin open cemp(20); loop fetch cemp into pename; exit when cemp%notfound; dbms_output.put_line('部门的员工姓名 :'||pename); end loop; close cemp; end; /
run:
匿名块已完成
部门的员工姓名 :SMITH
部门的员工姓名 :JONES
部门的员工姓名 :SCOTT
部门的员工姓名 :ADAMS
部门的员工姓名 :FORD
【光标】的总结
光标就是一个结果集(result set)
打开光标:open c1(cursor)
取一行光标的值:fetch c1 into pename;(去一行到变量中)
关闭光标:close c1;
5-2案例:统计每年入职的员工人数
/* 统计每年入职的员工人数 select to_char(hiredate,'yyyy') from emp; 步骤:1.游标代表查出的结果 2.变量来接受遍历游标的每列值 3.定义变量来存储统计结果 4.if判断语句每年的人数 5.打印结果 6.结束,关闭游标等 */ set serveroutput on declare cursor ctemp is select to_char(hiredate,'yyyy') from emp; phiredate varchar2(10); count80 number :=0; count81 number :=0; count82 number :=0; count87 number :=0; begin open ctemp; loop fetch ctemp into phiredate; exit when ctemp%notfound; if '1980'=phiredate then count80 := count80+1; elsif '1981'=phiredate then count81 := count81+1; elsif '1982'=phiredate then count82 := count82+1; else count87 := count87+1; end if; end loop; close ctemp; dbms_output.put_line('1980入职员工人数:'||count80); dbms_output.put_line('1981入职员工人数:'||count81); dbms_output.put_line('1982入职员工人数:'||count82); dbms_output.put_line('1987入职员工人数:'||count87); end; /
run as:
匿名块已完成
1980入职员工人数:1
1981入职员工人数:10
1982入职员工人数:1
1987入职员工人数:2
5-3 案例2- 员工涨工资问题
/* 为员工涨工资。从最低工资员工涨起每人涨现有工资的10%,但所有员工的工资总额不能超过5万元。请计算涨工资 的人数和涨工资后的工资总额,并输出涨工资人数及涨后工资总额。 分析:1.定义游标select empno,sal from emp order by sal;是一个集合,所以需要定义游标 2.定义变量来接收游标的列值 3.定义变量-工资总额=涨前总额+sal*0.1, 4.定义变量-涨工资人数 */ set serveroutput on; declare cursor ctemp is select empno,sal from emp order by sal; pempno emp.empno%type; psal1 emp.sal%type;--涨前 psal2 emp.sal%type;--涨后 sumsal number(7,2); sumemp number := 0; begin open ctemp; select sum(sal) into sumsal from emp; loop exit when sumsal >50000; fetch ctemp into pempno,psal1; exit when ctemp%notfound; psal2 := psal1+ psal1*0.1; exit when (sumsal+psal1*0.1) > 50000;--在涨之前先判断涨后是否会大于50000 update emp set sal= psal2 where empno= pempno; sumsal := sumsal + psal1*0.1; sumemp := sumemp+1; end loop; close ctemp; dbms_output.put_line('涨后工资总额:'||sumsal); dbms_output.put_line('涨工资人数'||sumemp); commit; end; /
run as:
匿名块已完成 涨后工资总额:40067.5 涨工资人数14
匿名块已完成 涨后工资总额:44074.25 涨工资人数14
匿名块已完成 涨后工资总额:48481.68 涨工资人数14
匿名块已完成 涨后工资总额:49939.14 涨工资人数7
匿名块已完成 涨后工资总额:49939.14 涨工资人数0
匿名块已完成 涨后工资总额:49939.14 涨工资人数0
5-4-1 自己的理解成一张表了。涉及两张表的员工涨工资问题
/* 用pl/sql语言编写一段程序,实现按部门分段(6000以上,(6000,3000),3000元以下)统计各工资段的职工人数、 以及各部门的工资总额(工资总额中不包括奖金). 分析:1.定义3个游标,有参游标:select empno,sal from emp where deptno=?; 无参游标:select distinct(deptno) ddeptno from emp order by ddeptno; select distinct(deptno) from emp; 2.定义变量来接收游标的列值。 3.定义变量存储 三个阶段的 职工人数, 4.定义变量各部门的工资总额; 5.对列值,判断是否在三个阶段的哪个阶段,然后相应的职工人数+1 */ set serveroutput on; declare cursor c1 is select distinct(deptno) from emp ; cursor c2(dno number) is select sal from emp where deptno= dno; pdeptno emp.deptno%type; psal emp.sal%type; sumemp10_6000 number := 0; sumemp10_6000_3000 number := 0; sumemp10_3000 number := 0; sumemp20_6000 number := 0; sumemp20_6000_3000 number := 0; sumemp20_3000 number := 0; sumemp30_6000 number := 0; sumemp30_6000_3000 number := 0; sumemp30_3000 number := 0; sumsal10 number(7,2); sumsal20 number(7,2); sumsal30 number(7,2); begin open c1; loop fetch c1 into pdeptno; exit when c1%notfound; open c2(pdeptno); loop fetch c2 into psal; exit when c2%notfound; if 10 = pdeptno then if psal>6000 then sumemp10_6000 := sumemp10_6000+1 ; elsif psal<3000 then sumemp10_3000 := sumemp10_3000+1; else sumemp10_6000_3000 := sumemp10_6000_3000+1; end if; elsif 20 = pdeptno then if psal>6000 then sumemp20_6000 := sumemp20_6000+1 ; elsif psal<3000 then sumemp20_3000 := sumemp20_3000+1; else sumemp20_6000_3000 := sumemp20_6000_3000+1; end if; else if psal>6000 then sumemp30_6000 := sumemp30_6000+1; elsif psal<3000 then sumemp30_3000 := sumemp30_3000+1; else sumemp30_6000_3000 := sumemp30_6000_3000+1; end if; end if; end loop; close c2; if 10 = pdeptno then select sum(sal) into sumsal10 from emp where deptno=pdeptno; elsif 20 = pdeptno then select sum(sal) into sumsal20 from emp where deptno=pdeptno; else select sum(sal) into sumsal30 from emp where deptno=pdeptno; end if; end loop; close c1; dbms_output.put_line('部门10,6000以上的人数:'||sumemp10_6000); dbms_output.put_line('部门10,6000-3000的人数:'||sumemp10_6000_3000); dbms_output.put_line('部门10,3000以下的人数:'||sumemp10_3000); dbms_output.put_line('部门20,6000以上的人数:'||sumemp20_6000); dbms_output.put_line('部门20,6000-3000的人数:'||sumemp20_6000_3000); dbms_output.put_line('部门20,3000以下的人数:'||sumemp20_3000); dbms_output.put_line('部门30,6000以上的人数:'||sumemp30_6000); dbms_output.put_line('部门30,6000-3000的人数:'||sumemp30_6000_3000); dbms_output.put_line('部门30,3000以下的人数:'||sumemp30_3000); dbms_output.put_line('部门10,总工资:'||sumsal10); dbms_output.put_line('部门20,总工资:'||sumsal20); dbms_output.put_line('部门30,总工资:'||sumsal30); end; /
run as:
匿名块已完成
部门10,6000以上的人数:0
部门10,6000-3000的人数:2
部门10,3000以下的人数:1
部门20,6000以上的人数:0
部门20,6000-3000的人数:3
部门20,3000以下的人数:2
部门30,6000以上的人数:0
部门30,6000-3000的人数:1
部门30,3000以下的人数:5
部门10,总工资:10950
部门20,总工资:13275
部门30,总工资:12200
5-4-2 正常做法 将查询结果放入一个表格msg_muke中
/* 用pl/sql语言编写一段程序,实现按部门分段(6000以上,(6000,3000),3000元以下)统计各工资段的职工人数、 以及各部门的工资总额(工资总额中不包括奖金). */ /* 分析: 1.有哪些部门:select deptno from dept;->光标->循环->退出条件:notfound 2.部门中员工的薪水:select sal from emp where deptno=?;带参数的光标->循环->退出条件:notfound 3.变量:1.初始值2.如何得到 每个段的员工人数; count1 number,count2 nunber,count3 number 每个部门的员工工资总额 saltotal number; select sum(sal) from emp where deptno=? */ set serveroutput on; declare cursor c1 is select deptno from dept; cursor c2(dno number) is select sal from emp where deptno=dno; pdeptno dept.deptno%type; psal emp.sal%type; count1 number; count2 number; count3 number; saltotal number; begin open c1; loop count1 := 0;--<3000 count2 := 0;-->=3000 and <6000 count3 := 0;-->=6000 fetch c1 into pdeptno; exit when c1%notfound; open c2(pdeptno); loop fetch c2 into psal; exit when c2%notfound; if psal<3000 then count1 := count1+1 ; elsif psal>=3000 and psal<6000 then count2 := count2 +1; else count3 := count3 +1; end if; end loop; close c2; select sum(sal) into saltotal from emp where deptno=pdeptno; insert into msg_muke values(pdeptno,count1,count2,count3,nvl(saltotal,0)); end loop; close c1; commit; dbms_output.put_line('任务执行完成'); end; /
run as:
匿名块已完成
任务执行完成
插入的表格:
5-6 多表的游标
/* 1.得到有哪些戏 select dno,dname from dep;-->光标-->循环-->退出条件:notfound; 2.得到系中,选修了'大学物理'课程学生的成绩 select grade from sc where cno=(select cno from course where cname=?? ) and sno in(select sno from student where dno =??) -->带参数的光标-->循环-->退出条件:notfound 变量:1.初始值;2.如何得到 每个分数段的人数: count1 number,count2 number,count3 number; 每个系选修了"大学物理"学生的平均成绩 avggrade number; 1.算数运算 2.select avg(grade) into avggrade from sc where cno=(select cno from course where cname= ??) and sno in (select sno from student where dno=??); */ set serveroutput on; declare --系的光标 cursor cdept is select dno,dname from dep; pdno dep.dno%type; pdname dep.dname%type; --学生成绩光标 cursor cgrade(tcname varchar2,tdno number) is select grade from sc where cno=(select cno from course where cname=tcname ) and sno in(select sno from student where dno=tdno); pgrade sc.grade%type; pavggrade number; count1 number;count2 number;count3 number; pcname varchar2 := '大学物理'; begin open cdept; loop fetch cdept into pdno,pdname; exit when cdept%notfounmd; select avg(grade) into pavggrade from sc where cno=(select cno from course where cname=pcname ) and dno= pdno; count1 := 0; count2 := 0; count3 := 0; open cgrade(pcname,pdno) ; loop fetch cgrade into pgrade; exit when cgrade%notfound; if pgrade <60 then count1 := count1+1; elsif pgrade >=60 and pgrade <85 then count2 := count2 +1; else count3 := count3 +1; end if; end loop; close cgrade; insert into msg1 values (pcname,pdname,count1,count2,count3,pavggrade); end loop; close cdept; commit; dbms_output.put_line('执行完成'); end; /
run as:
小结:
pl/sql:procedure language /sql;
pl/sql 是oracle对sql语言过程化的扩展;