第四章 pl/sql 异常处理 游标

五、PL/SQL的异常处理[外网链接:

https://www.cnblogs.com/ivictor/p/3892743.html]
程序的错误一般分为两类:编译错误和运行时错误。
在程序运行时出现的错误,称为异常。发生异常后,语句将停止执行,PL/SQL 引擎立即将控制权转到 PL/SQL 块的异常处理部分。异常处理机制简化了代码中的错误检测。PL/SQL 中任何异常出现时,每一个异常都对应一个异常码和异常信息。
1、预定义异常 (执行错误)
为了 Oracle 开发和维护的方便,在 Oracle 异常中,为常见的异常码定义了对应的异常名称,称为预定义异常
异常名称 异常码 概述
no_data_found ORA-01403 SELECT INTO 语句中没有返回任何记录。
too_many_rows ORA-01422 SELECT INTO 语句中返回多于1 条记录。
dup_val_no_index ORA-00001 试图向唯一索引列插入重复值
invalid_cursor ORA-01001 试图进行非法游标操作。
invalid_number ORA-01722 试图将字符串转换为数字
zero_divide ORA-01476 试图用0 作为除数。
cursor_already_open ORA-06511 试图打开一个已经打开的游标

PL/SQL 中用 Exception 关键字开始异常处理。
语法格式:异常处理
语法解析:
异常发生时,进入异常处理部分,具体的异常与若干个when 子句中指明的异常名匹配,匹配成功就进入对应的异常处理部分,如果对应不成功,则进入 others 进行处理。

2、自定义异常。 (用户自认为的异常信息)
除了预定义异常外,用户还可以在开发中自定义异常,自定义异常可以让用户采用与 PL/SQL 引擎处理错误相同的方式进行处理,用户自定义异常的两个关键点:
异常定义:
在变量声明部分采用Exception 关键字声明异常,定义方法与定义变量相同。
比如声明一个 PL/SQL块的声明myexception 异常方法是: myexception Exception ;
异常引发: 在程序可执行区域,使用Raise关键字进行引发。比如引发myexception 方法是:
raise myexception;
格式:
declare中声明异常;
异常名 exception;
begin语句块中引发:
raise 异常名;
exception中捕捉处理异常:when 异常名 then 异常处理内容。

3、引发应用程序异常
在 Oracle 开发中,遇到的系统异常都有对应的异常码,在应用系统开发中,用户自定义的异常也可以指定一个异常码和异常信息,Oracle 系统为用户预留了自定义异常码,其范围介于-20000 到-20999 之间的负整数。引发应用程序异常的语法是:
raise_application_error(异常码,异常内容信息)
—–用于自定义异常处理报错的框框。

4、异常码的绑定
如果要处理未命名的内部异常,必须使用 others异常处理器。也可以利用 相应的语法 把一个异常码与异常名绑定。
pragma exception_init(异常名,异常码);
注:在程序中进行引发应用程序异常时,必须在声明中进行异常码的绑定。
Pragma 由编译器控制,在编译时处理,而不是在运行时处理。Exception_int告诉编译器将异常名与 Oracle错误码绑定起来,这样可以通过异常名引用任意的内部异常, 并且可以通过异常名为异常编写适当的异常处理器。
这里的异常码可以是用户自定义的异常码,也可以是 Oracle 系统的异常码。

六、游标[查看表的时候,左边每一行点击都会有一个黑小三角那个就是游标

我们每次查询去打印的时候,都只能返回一条结果每次一条,如果让他返回一个结果集,最好的方法是用游标(就是一下返回多行数据)。

用游标就肯定会用循环。]
游标用于指向一个查询结果集。也可以指向数据插入、修改、删除的记录集。 游标也可以认为是指向某个结果集的指针。

通过游标访问结果集中的数据,一定要使用循环。循环遍历访问游标指向的每一行数据。
一、游标的分类
显性游标:使用关键字cursor 明确申明的游标。
是一个查询的结果集,放在 pl/sql块的declare部分
例如: cursor C_EMP is select EMPNO, ENAME from EMP; 这里的游标名称就是C_EMP。
隐性游标:没有使用关键字cursor明确申明的游标。 insert/ delete /update
例如:update EMP set ENAME=’New’ where EMPNO=7788; 这条SQL更新语句所影响的记录集有一个隐性游标,名称为“SQL”。

二、游标的属性
%notfound 属性:游标没有取到数据
当最近一次读记录(fetch),成功取到值,此数据为 false;
当最近一次读记录(fetch),没有取到值,此数据为true;
%found 属性:与% NOTFOUND相反; 游标取到数据
%rowcount 属性:返回行数信息
对于显性游标,% ROWCOUNT表示fetch 成功的数据条数。如果OPEN 游标,但没有进行fetch,则ROWCOUNT值为0。
对于隐性游标,% ROWCOUNT表示INSERT、 UPDATE或DELETE 所影响的行数。
三、游标属性的访问
显性:游标名%游标属性名。
由于隐性游标的名称是“SQL”,所以访问隐性游标属性的方法: SQL%游标属性名 。
四、游标的操作过程[游标的使用步骤:
Declare
cursor 游标名 is 查询语句;→ –在声明部分定义游标
begin
open 游标名;→ –打开游标
fetch 游标名 into 变量名;→ –把游标赋值给变量
exit when 游标名%游标属性;→ –满足游标属性时,跳出
close 游标名; –关闭游标
End;
]
显性游标一般要有如下工作过程:
(1) 声明部分定义游标:就是定义一个游标名,以及与其相对应的SELECT 语句。 定义游标的语句格式: cursor 游标名 is select查询语句;
(2) 执行块打开游标:open 游标名;
(3) 提取游标数据信息:就是检索结果集合中的数据行,放入指定的输出变量中。 第一行和下一行
fetch 游标名 into 变量名;

FETCH 语句的作用:取出游标指针所指向的那一行数据,放入变量中。然后下移指针到下一行。

(4)对该记录进行处理 ,直到活动集合中没有记录。
① loop 游标赋值变量→满足游标属性,跳出→输出 end loop;
② 游标赋值变量 while 游标名%游标属性 loop 输出
→游标赋值变量 end loop;
③ for 变量名(表名) in 游标名 loop 输出 end loop;
注:for中用%rowtype定义变量的数据类型,不需要游标打开,关闭,也不需要用fetch把游标赋值给变量,for中用in把从游标中的取出的数据赋给变量。 –变量名.列名
(5) 关闭游标,当提取和处理完游标结果集合中的数据后,应及时关闭游标, 以释放该游标所占用的系统资源。关闭游标的格式: close 游标名;

周末作业

1、使用游标和loop来显示所有部门的名称?
declare
cursor c_dname is
select deptno,dname from dept;
v_dno dept.deptno%type;
v_name dept.dname%type;
begin
open c_dname;

loop
fetch c_dname into v_dno,v_name;
exit when c_dname%notfound;
dbms_output.put_line(v_dno||’部门===部门名称是’||v_name);
end loop;
close c_dname;
end;
2、使用游标和while来显示所有部门的地理位置?
declare
cursor c_wz is select deptno,loc from dept;
v_dno dept.deptno%type;
v_loc dept.loc%type;
begin
open c_wz;
fetch c_wz into v_dno,v_loc;
while c_wz%found loop
dbms_output.put_line(v_dno||’部门的地理位置是’||v_loc);
fetch c_wz into v_dno,v_loc;
end loop;
close c_wz;
end;
3、接收输入的部门编号,用for循环和游标,打印出此部门的所有雇员的名字和工作以及工资信息?
declare
v_dno emp.deptno%type :=&dno;
cursor c_xx is select deptno,ename,sal from emp where deptno=v_dno;
begin
for emp in c_xx loop
dbms_output.put_line(emp.deptno||’部门的员工名字是’||emp.ename||’,其工资是’||emp.sal);
end loop;
end;
4、用更新游标来为雇员加佣金:
如果工资低于1500,按20%加薪,
如果工资低于2000,按50%加薪,
如果工资低于3000,按加薪为当前工资的两倍
(用if实现,创建一个与emp表一摸一样的emp1表,对emp1表进行修改操作),并将更新前后的数据输出出来?
create table emp1 as select * from emp where 1=1;
declare
cursor c_jx is select empno,sal from emp1;
v_eno emp1.empno%type;
v_sal emp1.sal%type;
v_jxsal emp1.sal%type;
begin
open c_jx;
loop
fetch c_jx into v_eno,v_sal;
exit when c_jx%notfound;
if v_sal <1500 then
v_jxsal:=v_sal*1.2;
elsif v_sal<2000 then
v_jxsal:=v_sal*1.5;
else
v_jxsal:=v_sal*2;
end if;
update emp1 set sal=v_jxsal where empno=v_eno;
dbms_output.put_line
(v_eno||’的原工资是’||v_sal||’更新后的工资是’||v_jxsal);
end loop;
close c_jx;
end;
5、编写一个PL/SQL程序块,对名字以‘A’或‘S’开始的所有雇员按他们的基本薪水(sal)的10%给他们加薪(对emp1表进行修改操作)?
declare
cursor c_jx is select ename,sal,sal*1.1 newsal from emp1 where ename like ‘A%’ or ename like ‘S%’;
begin
for emp1 in c_jx loop
dbms_output.put_line(emp1.ename||’加薪后的工资是’||emp1.newsal );
end loop;
end;
6、编写一个PL/SQL程序块,对所有的salesman增加佣金(comm)500元?
declare
cursor c_new is
select e.ename,e.comm ,(comm+500) newcomm
from emp e where job =’SALESMAN’;
begin
for emp in c_new loop
dbms_output.put_line
(emp.ename||’原佣金是’||emp.comm||’加佣金后是’||emp.newcomm);
end loop;
end;
7、编写一个PL/SQL程序块,以提升2个资格最老的职员为MANAGER(工作时间越长,资格越老)?
declare
cursor c_ts is
select * from
(select * from emp where job=’MANAGER’ order by hiredate asc)
where rownum <=2;
begin
for emp in c_ts loop
dbms_output.put_line(emp.ename||’是被提升的职员’);
end loop;
end;

8、编写一个PL/SQL程序块,对所有雇员按他们的基本薪水(sal)的20%为他们加薪,如果增加的薪水大于300就取消加薪(对emp1表进行修改操作,并将更新前后的数据输出出来)?
declare
cursor c_jx is
select * from emp1;
v_name emp1.ename%type;
v_sal emp1.ename%type;
v_nsal emp1.sal%type;
begin
for emp1 in c_jx loop
v_sal:=emp1.sal*0.2;
v_nsal:=emp1.sal*1.2;
if v_sal>300 then
v_sal:=v_sal;
dbms_output.put_line(emp1.ename||’员工不加薪,工资为’||emp1.sal);
else
dbms_output.put_line
(emp1.ename||’加薪前工资为’||emp1.sal||’加薪后的工资为’||v_nsal);
end if;
end loop;
end;
9、将每位员工工作了多少年零多少月零多少天输出出来?
declare
cursor c_day is
select ename,
trunc(months_between(sysdate,hiredate)/12) year,
trunc(mod(months_between(sysdate,hiredate),12)) month,
trunc(mod(mod(sysdate - hiredate, 365), 12)) day
from emp;
begin
for emp in c_day loop
dbms_output.put_line
(emp.ename||’工作了’||emp.year||’年’||emp.month||’月’||emp.day||’天’);
end loop;
end;
10、输入部门编号,按照下列加薪比例执行
– deptno raise(%)
– 10 5%
– 20 10%
– 30 15%
– 40 20%
– 加薪比例以现有的sal为标准
(用CASE实现,创建一个emp1表,修改emp1表的数据),并将更新前后的数据输出出来?
declare
cursor c_jx is select deptno,sal from emp1;
v_dno emp1.deptno%type;
v_newsal emp1.sal%type;
begin
for emp1 in c_jx loop
case
when emp1.deptno=10 then v_newsal:=emp1.sal*1.05;
when emp1.deptno=20 then v_newsal:=emp1.sal*1.1;
when emp1.deptno=30 then v_newsal:=emp1.sal*1.15;
when emp1.deptno=40 then v_newsal:=emp1.sal*1.2;
else v_newsal:=emp1.sal;
end case;
update emp1 set sal=v_newsal where deptno=v_dno;
dbms_output.put_line
(emp1.deptno||’部门的原工资是’||emp1.sal||’更新后工资为’||v_newsal);
end loop;
end;

猜你喜欢

转载自blog.csdn.net/weixin_42800008/article/details/81270471
今日推荐