oracle cursor and exception

/*
游标是SQL的一个内存工作区,有系统或用户以变量的形式定义。游标的作用就是用于临时存储从数据库中提取
的数据块。

游标有两种类型:显示游标和隐式游标。
一次从数据库中提取一行数据,对于这种形式的查询和DML操作,系统都会使用一个隐式游标,
如果要提取多行数据,就要有程序员定义一个显示游标,并通过与游标有关的语句进行处理。
显示游标对应一个返回结果为多行多列的SELECT语句。

游标一旦打开,数据就从数据库中传送到游标变量中,然后应用程序再从游标中分解出需要的数据,并进行处理。

*/


/**
隐式游标
DML操作和单行SELECT语句使用隐式游标
INSERT, UPDATE,  DELETE,  SELECT...INTO...

当系统使用一个隐式游标时,可以通过隐式游标的属性来了解操作的状态和结果,进而控制程序的流程。
隐式游标可以使用名字SQL来访问,但要注意,通过SQL游标名总是只能访问前一个DML操作或单行SELECT操作的游标属性。
所以通常在刚刚执行完操作之后哦,立即使用SQL游标名来访问属性。
游标的属性有以下四种:
隐式游标的属性          返回值类型      意 义
SQL%ROWCOUNT           整型             代表DML 语句成功执行的数据行数
SQL%FOUND              布尔型            值为TRUE 代表插入、删除、更新或单行查询操作成功
SQL%NOTFOUND           布尔型            与SQL%FOUND 属性返回值相反
SQL%ISOPEN             布尔型            DML 执行过程中为真,结束后为假
*/

--使用隐式游标的属性,判断对雇员工资的修改是否成功
declare
begin
  update scott.emp emp set emp.sal = sal+100  where empno=7788;
  if SQL%FOUND then
    dbms_output.put_line('OK'); 
    commit;
  else
      dbms_output.put_line('fail'); 
  end if;
end;
      
--使用隐式游标的属性,判断修改员工的行数
declare
begin
     update scott.emp emp set emp.sal = sal+1;
       dbms_output.put_line(SQL%ROWCOUNT);    
end;     
--输出结果:20

/**
显示游标
显示游标的使用分为以下4个步骤
1. 声明游标
  在DECLARE部分按以下格式声明游标:
  CURSOR 游标名[(参数1 数据类型[,参数2 数据类型...])]
  IS SELECT语句:
  参数是可选部分,所定义的参数可以出现在SELECT语句的WHERE子句中。如果定义了参数,
则必须在打开游标时传递相应的实际参数
  SELECT语句是对表或视图的查询语句,甚至也可以是联合查询,可以带WHERE条件、ORDER BY或GROUP BY
等子句,但不能使用INTO子句。在SELECT语句中可以使用在定义游标之前定义的变量
2. 打开游标
  在可执行部分,按以下格式打开游标
  OPEN 游标名[(实际参数1[,实际参数2...])]
  打开游标时,SELECT语句的查询结果就被传递到了游标工作区。
3. 提取数据
  在可执行部分,按以下格式将游标工作区中的数据提取到变量中。提取操作必须在打开游标之后进行。
  FETCH 游标名 INTO 变量名1,变量2...]
  或
  FETCH 游标名 INTO 记录变量;
  游标打开后有一个指针指向数据区,FETCH语句一次返回指针值得一行数据,要返回多行重复执行,可以使用循环语句来实现。
控制循环可以通过判断游标的属性来进行。

下面对这两种格式进行说明:
 1).变量名是用来从游标中提取数据的变量,需要事先定义。变量的个数和类型应该与SELECT语句中的字段变量的个数和类型一致
 2).一次将一行数据提取到记录变量中,需要使用%ROWTYPE事先定义记录变量,这种形式使用起来比较方便,不必分别定义和使用
 多个变量
     定义记录变量的方法如下:
     变量名 表名|游标名%ROWTYPE;
     其中的表必须存在,游标名也必须先定义
      
4. 关闭游标
  CLOSE 游标名
  显示游标名打开后,必须显示地关闭。游标一旦关闭,游标占用的资源就被释放,游标变成无效,必须重新打开才能使用。
*/      

--用游标提取emp表中7788雇员的名称和职务
declare
 v_ename varchar(10);
 v_job varchar(10);
 cursor emp_cursor IS
 select emp.ename, emp.job from scott.emp emp;
 begin
   open emp_cursor;
   fetch emp_cursor into v_ename, v_job;
   DBMS_OUTPUT.PUT_LINE(v_ename||','||v_job); 
   close emp_cursor;
   end;
 --执行结果:SCOTT,ANALYST 
 
 --用游标变量提取emp中7788雇员的名称和职务
  declare
    cursor emp_cursor is
    select emp.ename, emp.job from scott.emp emp where emp.empno=7788;
    emp_record emp_cursor%ROWTYPE;
    begin
      open emp_cursor;
      fetch emp_cursor into emp_record;
      DBMS_OUTPUT.PUT_LINE(emp_record.ename||','||emp_record.job);
      close emp_cursor;
      end;
 --执行结果:SCOTT,ANALYST     
      
--显示工资最高的前三名雇员的名称和工资。
DECLARE
 v_ename varchar(10);
 v_sal number(5);
 cursor emp_cursor is
 select emp.ename, emp.sal from scott.emp emp where sal>0 order by sal desc ;
 begin
   open emp_cursor;
   for i in 1..3 loop
     fetch emp_cursor into v_ename, v_sal;
      DBMS_OUTPUT.PUT_LINE(v_ename||','||v_sal);
   end loop;    
    close emp_cursor;
 end;           
/*
输出结果
KING,5000
SCOTT,3100
FORD,3000
*/

/*
 游标循环 1
*/
--显示全部雇员的编号和名称。
DECLARE 
 CURSOR emp_cursor is
 select empno, ename from scott.emp;
 begin
   for emp_record in emp_cursor loop
     DBMS_OUTPUT.PUT_LINE(emp_record.empno||emp_record.ename);
     end loop;
 end;
/*
 游标循环 2
 省略游标的定义,游标的SELECT查询语句在循环中直接出现
*/
declare
begin
  for re in(select emp.ename from scott.emp emp) loop
    DBMS_OUTPUT.PUT_LINE(re.ename);
  end loop;
end;


/*
显示游标属性
虽然可以使用前面的形式获得游标数据,但是在游标定义以后使用它的一些属性结构控制是一种更为灵活的方法。
显示游标的属性如表:

游标的属性    返回值类型        意 义
%ROWCOUNT      整型             获得FETCH 语句返回的数据行数
%FOUND         布尔型           最近的FETCH 语句返回一行数据则为真,否则为假
%NOTFOUND      布尔型           与%FOUND 属性返回值相反
%ISOPEN        布尔型           游标已经打开时值为真,否则为假

可按照以下形式取得游标的属性
游标名%属性
要判断游标emp_cursor是否处于打开状态,可以使用属性emp_cursor%ISOPEN。如果游标已经打开,则返回值为"真",否则为"假"
*/
declare
v_ename varchar2(10);
cursor emp_cursor is
select emp.ename from scott.emp emp;
begin
  open emp_cursor;
  if emp_cursor%ISOPEN then
    loop
      fetch emp_cursor into v_ename;
      exit when emp_cursor%NOTFOUND;
      DBMS_OUTPUT.PUT_LINE(to_char(emp_cursor%ROWCOUNT)||'-'||v_ename);
    end loop;
  else
    DBMS_OUTPUT.PUT_LINE('用户信息:游标没有打开!');
  end if;
   close emp_cursor;
  end;

--带参数的游标 打开游标的时候的参数
declare
v_empno number(5);
v_ename varchar2(10);
cursor emp_cursor(p_deptno number, p_job varchar2) is
 select empno, ename from scott.emp emp where emp.deptno=p_deptno and emp.job=p_job;
 begin
   open emp_cursor(10, 'CLERK');
   if emp_cursor%ISOPEN then
     loop
       fetch emp_cursor into v_empno, v_ename;
       dbms_output.put_line(v_empno||'-'|| v_ename);
       exit when emp_cursor%NOTFOUND;
     end loop;
   else
     DBMS_OUTPUT.PUT_LINE('用户信息:游标没有打开!');
   end if;
 end;
 
 --带参数的游标 通过变量向游标传递参数,变量需要先于游标定义,并在游标打开之前赋值
 declare
  v_empno number(5);
  v_ename varchar(10);
  v_depno number(5);
  v_job varchar2(10);
  cursor emp_cursor IS
   select emp.empno, emp.ename from scott.emp emp where emp.deptno=v_depno and emp.job=v_job;
   begin
     v_depno:=10;
     v_job:='CLERK';
     open emp_cursor;
     loop 
       fetch emp_cursor into v_empno, v_ename;
       exit when emp_cursor%NOTFOUND;
       DBMS_OUTPUT.PUT_LINE(v_empno||','||v_ename);
     end loop;
   end;
 --输出结果:7934,MILLER


/*
 动态SELECT语句和动态游标的用法
 
 对于查询结果为一行的select语句,可以用动态生成查询语句字符串的方法,在程序执行阶段临时生成并执行,
 execute immediate 查询语句字符串 into 变量1、、
*/

declare
str varchar2(100);
v_ename varchar2(10);
begin
  str := 'select emp.ename from scott.emp emp where emp.empno=7788';
  execute immediate str into v_ename;
  dbms_output.put_line(v_ename);
  end;


/*
定义游标类型的语句如下:
TYPE 游标类型名 REF CURSOR
声明游标变量的语句如下:
在可执行部分可以如下形式打开一个动态游标
open 游标变量名 for 查询语句字符串;
*/
--按名字中包含的字母顺序分组显示雇员信息
declare
type cur_type is ref cursor;
cur cur_type;--声明为一个未绑定的游标
rec scott.emp%rowtype;
str varchar2(550);
letter char :='A';
begin
  loop
    str:='select emp.ename from scott.emp where emp.ename like ''%'||letter||'%''';
    open cur for str;
    dbms_output.put_line('包含字母'||letter||'的名字:');
    loop
      fetch cur into rec.ename;
      exit when cur%notfound;
      dbms_output.put_line(rec.ename);
    end loop;
    exit when letter='Z';
    letter:=chr(ascii(letter)+1);
    end loop;
 end;
       
 /*
 异常处理
 
 错误是在标准包中由系统预定义的标准错误,或是有用户在程序的说明部分自定义的错误。
 
 */
 
 --查询编号为1234的雇员名字
 declare
 v_name varchar2(10);
 begin
   select emp.ename into v_name from scott.emp emp where emp.empno=1234;
   DBMS_OUTPUT.PUT_LINE('该雇员名字为:'|| v_name);
   EXCEPTION
     WHEN NO_DATA_FOUND THEN
       DBMS_OUTPUT.PUT_LINE('无改用户');
      WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('其他错误');
 end;
 --执行结果:无改用户

  --由程序代码显示系统错误
  DECLARE
  V_TEMP NUMBER(5):=1;
  BEGIN
    V_TEMP:=V_TEMP/0;
    EXCEPTION
      WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('发生系统错误!');
         DBMS_OUTPUT.PUT_LINE('错误代码:'|| SQLCODE( ));  
DBMS_OUTPUT.PUT_LINE('错误信息:' ||SQLERRM( ));
END;


/*
错 误 名 称                      错误代码       错 误 含 义
CURSOR_ALREADY_OPEN          ORA_06511        试图打开已经打开的游标
INVALID_CURSOR               ORA_01001        试图使用没有打开的游标
DUP_VAL_ON_INDEX             ORA_00001        保存重复值到惟一索引约束的列中
ZERO_DIVIDE                  ORA_01476        发生除数为零的除法错误
INVALID_NUMBER               ORA_01722        试图对无效字符进行数值转换
ROWTYPE_MISMATCH             ORA_06504        主变量和游标的类型不兼容
VALUE_ERROR                  ORA_06502        转换、截断或算术运算发生错误
TOO_MANY_ROWS                ORA_01422        SELECT…INTO…语句返回多于一行的数据
NO_DATA_FOUND                ORA_01403        SELECT…INTO…语句没有数据返回
TIMEOUT_ON_RESOURCE          ORA_00051        等待资源时发生超时错误
TRANSACTION_BACKED_OUT       ORA_00060        由于死锁,提交失败
STORAGE_ERROR                ORA_06500        发生内存错误
PROGRAM_ERROR                ORA_06501        发生PL/SQL 内部错误
NOT_LOGGED_ON                ORA_01012        试图操作未连接的数据库
LOGIN_DENIED                 ORA_01017        在连接时提供了无效用户名或口令
www.

*/


--定义新的系统错误类型。

DECLARE
V_ENAME VARCHAR2(10);
NULL_INSERT_ERROR EXCEPTION;
PRAGMA EXCEPTION_INIT(NULL_INSERT_ERROR,-1400);
BEGIN
INSERT INTO EMP(EMPNO) VALUES(NULL);
EXCEPTION
WHEN NULL_INSERT_ERROR THEN
DBMS_OUTPUT.PUT_LINE('无法插入NULL值!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('发生其他系统错误!');
END;
--执行结果为:无法插入NULL值!








已标记关键词 清除标记
相关推荐
课程简介: 历经半个多月的时间,Debug亲自撸的 “企业员工角色权限管理平台” 终于完成了。正如字面意思,本课程讲解的是一个真正意义上的、企业级的项目实战,主要介绍了企业级应用系统中后端应用权限的管理,其中主要涵盖了六大核心业务模块、十几张数据库表。 其中的核心业务模块主要包括用户模块、部门模块、岗位模块、角色模块、菜单模块和系统日志模块;与此同时,Debug还亲自撸了额外的附属模块,包括字典管理模块、商品分类模块以及考勤管理模块等等,主要是为了更好地巩固相应的技术栈以及企业应用系统业务模块的开发流程! 核心技术栈列表: 值得介绍的是,本课程在技术栈层面涵盖了前端和后端的大部分常用技术,包括Spring Boot、Spring MVC、Mybatis、Mybatis-Plus、Shiro(身份认证与资源授权跟会话等等)、Spring AOP、防止XSS攻击、防止SQL注入攻击、过滤器Filter、验证码Kaptcha、热部署插件Devtools、POI、Vue、LayUI、ElementUI、JQuery、HTML、Bootstrap、Freemarker、一键打包部署运行工具Wagon等等,如下图所示: 课程内容与收益: 总的来说,本课程是一门具有很强实践性质的“项目实战”课程,即“企业应用员工角色权限管理平台”,主要介绍了当前企业级应用系统中员工、部门、岗位、角色、权限、菜单以及其他实体模块的管理;其中,还重点讲解了如何基于Shiro的资源授权实现员工-角色-操作权限、员工-角色-数据权限的管理;在课程的最后,还介绍了如何实现一键打包上传部署运行项目等等。如下图所示为本权限管理平台的数据库设计图: 以下为项目整体的运行效果截图: 值得一提的是,在本课程中,Debug也向各位小伙伴介绍了如何在企业级应用系统业务模块的开发中,前端到后端再到数据库,最后再到服务器的上线部署运行等流程,如下图所示:
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页