慕课网oracle

/* 慕课网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语言过程化的扩展;












猜你喜欢

转载自blog.csdn.net/z_alvin/article/details/79711494