Oracle游标简介

游标是数据库编程中必须要熟练掌握的技术,主要实现针对数据集合,进行循环处理,因为SQL本身只能一次性处理,所以当有稍微复杂的查询时,都在存储过程中使用游标进行实现。

静态游标在执行前就能确定对应查询语句,最多只是传递一些查询参数而已,所以比较容易处理。动态游标是在执行前查询SQL是动态拼接的,不确定具体查询那些表和条件。

在MSSQL中,定义动态游标比较麻烦,一般先拼接SQL,然后动态执行存放临时表中,然后定义游标读取临时表;相比ORACLE则强大多了,直接定义游标,然后直接打开就可以实现,感慨其强大。下面通过示例进行说明。

Oracle 静态游标

定义游标的时候select语句是确定的,如

set serveroutput on;
declare cursor cur_po is select name,code,fcode from t_po;
v_name varchar2(150);
v_code varchar2(15);
v_fcode varchar2(15);
begin
 --遍历游标
 open cur_po;
 fetch cur_po into v_name,v_code,v_fcode;
 while cur_po%found loop
    sys.dbms_output.put_line('组织名称='||v_name||' code='||v_code||' fcode='||v_fcode);
    fetch cur_po into v_name,v_code,v_fcode;
 end loop;
 close cur_po;
end;
/

以上v_name,v_code,v_fcode这种类型定义属于显示定义,当t_po表的字段类型改变时,fetch into就会报错,所以一般开发的时候都采用隐示定义。

set serveroutput on;
declare cursor cur_po is select name,code,fcode from t_po;
v_name t_po.name%type;
v_code t_po.code%type;
v_fcode t_po.fcode%type;
begin
 --遍历游标
 open cur_po;
 fetch cur_po into v_name,v_code,v_fcode;
 while cur_po%found loop
    sys.dbms_output.put_line('组织名称='||v_name||' code='||v_code||' fcode='||v_fcode);
    fetch cur_po into v_name,v_code,v_fcode;
 end loop;
 close cur_po;
end;
/

在上面的例子我们定义的是字段类型,我们也可以定义为行类型。只不过行类型需要select *选取所有字段。

set serveroutput on;
declare cursor cur_po is select * from t_po;
po_row t_po%rowtype;--定义行类型
begin
 --遍历游标
 open cur_po;
 fetch cur_po into po_row;
 while cur_po%found loop
    sys.dbms_output.put_line('组织名称='||po_row.name||' code='||po_row.code||' fcode='||po_row.fcode);
    fetch cur_po into po_row;
 end loop;
 close cur_po;
end;
/

隐示游标的其他几种类型

SQL%rowcount 返回类型整型,代表DML语句成功执行的数据行数。

SQL%found 返回布尔类型 true代码插入,删除,更新或者单行查询操作成功。

SQL%notfound 与SQL%found相反

SQL%isopen 返回布尔类型 DML执行过程中为真,结束后为假

set serveroutput on;
declare po_count number;
begin
 select count(*) into po_count from t_po;
 dbms_output.put_line('游标捕获记录数='||sql%rowcount);
end;
/

输出:

游标捕获记录数=1
set serveroutput on;
begin
 update t_po set name='huangbaokang' where code='111';
 if sql%found then
    dbms_output.put_line('已更新');
  else
     dbms_output.put_line('未更新');
  end if;
end;
/

上面的sql%found也可以换成 sql%rowcount。

Oracle动态游标

在Oracle动态游标中,又分强类型动态游标和弱类型动态游标。

动态SQL作为游标执行的语句,定义时仅说明类型,打开时指定SQL

一、强类型动态游标

--查询本区域下的组织,当根节点存在时返回所有组织信息,否则返回当前组织
set serveroutput on;
declare type potype is ref cursor return t_po%rowtype;
current_po potype;--强类型游标
root number;--根节点数量
row_po t_po%rowtype;
begin
 -- 判断根节点是否存在
 select count(*) into root from t_po where code='360724';--章贡区根节点

 if root=0 then
   -- 返回当前组织信息
   open current_po for select * from t_po where code='360727014';--带条件,具体是存储过程的话,为输入参数
 else
   -- 获取所有的组织架构
   open current_po for select * from t_po;
 end if;

 -- current_po可能是一条记录或者多条记录
 --遍历
 fetch current_po into row_po;
 while current_po%found loop
    dbms_output.put_line('组织名称='||row_po.name||' code='||row_po.code||'  fcode='||row_po.fcode);
    fetch current_po into row_po;
 end loop;
 close current_po;
end;
/

以上定义类型的时候指定了t_po%rowtype,这种方式写死了,灵活性比较差,遍历游标的时候用的是同一张表。

declare type potype is ref cursor return t_po%rowtype;

如果我的需求是这样的,如果章贡区的根节点存在的话返回该区域下的所有党员,以上程序就不适应了,这个可以使用Oracle的弱类型动态游标实现。

二、弱类型动态游标

使用弱类型动态游标,可以指向多张表,fetch into的时候定义多个不同表的行记录即可。灵活性大大增强。

--查询本区域下的组织,当根节点存在时返回所有党员信息,否则返回当前组织
set serveroutput on;
declare type mutitype is ref cursor;
Mtype mutitype;--弱类型游标,可以指向组织表,也可以指向党员表
root number;--根节点数量
row_po t_po%rowtype;
row_member t_party_member%rowtype;
begin
 -- 判断根节点是否存在
 select count(*) into root from t_po where code='3607237';--章贡区根节点

 if root=0 then
   -- 返回当前组织信息
   open mtype for select * from t_po where code='360727014';--带条件,具体是存储过程的话,为输入参数
   --强类型由于是同一张表,共用遍历查询语句,弱类型需要分开遍历
   fetch mtype into row_po;
   while mtype%found loop
      dbms_output.put_line('组织名称='||row_po.name||' code='||row_po.code||'  fcode='||row_po.fcode);
      fetch mtype into row_po;
   end loop;
   close mtype;
 else
   -- 获取章贡区下的所有党员
   open mtype for select * from t_party_member;
   fetch mtype into row_member;
   while mtype%found loop
      dbms_output.put_line('党员姓名='||row_member.name||' 党员电话号码='||row_member.mobile_no);
      fetch mtype into row_member;
   end loop;
   close mtype;
 end if;

end;
/