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;
/