Oracle中游标的使用

Oracle中游标的使用

游标可以看成是指向一个查询结果集的指针,通过游标的移动逐行提取每一行的记录 可以让开发者一次访问一行结果集,在每条结果集上作操作。游标的作用如下:
(1)指定结果集中特定行的位置;
(2)基于当前的结果集位置检索一行或连续的几行;
(3)在结果集的当前位置修改行中的数据;
(4)以编程的方式访问数据库。
由于程序语言是面向记录的,一组变量一次只能存放一个变量或者一条记录,无法直接接收数据库中的查询结果集,而引入游标就解决了这个问题。

一、游标的分类

游标分为两种类型:隐式游标和显式游标。

1、隐式游标

DML操作(INSERT、UPDATE、DELETE)和单行查询操作(SELECT…INTO…)会使用隐式游标。隐式游标不需要用户自己声明,它由系统自动定义,名称为sql。

可以通过隐式游标的属性来了解操作的状态和结果,进而控制程序的流程。但要注意,通过SQL游标名只能访问前一个DML操作或单行SELECT操作的隐式游标属性。所以通常在刚刚执行完操作之后,立即使用SQL游标名来访问属性。游标的属性有四种:标的属性有四种,如下所示。
(1)SQL%ROWCOUNT:代表DML语句成功执行的数据行数 (整型);
(2)SQL%FOUND:值为TRUE代表插入、删除、更新或单行查询操作成功,否则表示操作失败;
(3)SQL%NOTFOUND:与SQL%FOUND属性返回值相反;
(4)SQL%ISOPEN:DML执行过程中为真,结束后为假。

更新失败的例子(没有部门号为21的雇员):

SQL> 
begin
    update emp set comm=100 
    where deptno=21;
    if sql%found then
        dbms_output.put_line('更新成功!');
    else
        dbms_output.put_line('更新失败!');
    end if;
    if sql%isopen then
    dbms_output.put_line('成功更新了'||sql%rowcount||'条记录');
end;
 16  /
更新失败!
成功更新了0条记录

PL/SQL procedure successfully completed.

更新成功的例子:

SQL> 
begin
    update emp set comm=100 
    where deptno=20;
    if sql%found then
        dbms_output.put_line('更新成功!');
    else
        dbms_output.put_line('更新失败!');
    end if;
    dbms_output.put_line('成功更新了'||sql%rowcount||'条记录');
end;
 16  /
更新成功!
成功更新了5条记录

PL/SQL procedure successfully completed.
2、显式游标

如果要提取多行数据,就要由程序员定义一个显式游标,并通过与游标有关的语句进行处理。显式游标对应一个返回结果为多行多列的SELECT语句。 游标一旦打开,数据就从数据库中传送到游标变量中,然后应用程序再从游标变量中分解出需要的数据,并进行处理。 下面介绍显示游标的使用方法。

二、显示游标的使用

显示游标的使用分为4个步骤:(1)声明游标;(2)打开游标;(3)提取数据;(4)关闭游标。

1、声明游标

声明游标的语法如下:

CURSOR 游标名[(参数1 数据类型[,参数2 数据类型...])] 
IS SELECT语句; 

说明:
(1)必须在代码块的DECLEAR部分声明游标;
(2)参数是可选部分,所定义的参数可以出现在SELECT语句的WHERE子句中。如果定义了参数,则必须在打开游标时传递相应的实际参数。
(3)SELECT语句是对表或视图的查询语句,甚至也可以是联合查询。可以带WHERE条件、ORDER BY或GROUP BY等子句,但不能使用INTO子句。在SELECT语句中可以使用在定义游标之前定义的变量。
(4)声明游标时并没有执行Select 语句。

2、打开游标

打开游标的语法如下:

OPEN 游标名[(实际参数1[,实际参数2...])]; 

说明:
(1)必须在代码块的可执行部分打开游标;
(2)打开游标时,执行Select 语句,SELECT语句的查询结果就被传送到了游标工作区。
(3)打开游标后,游标指向结果集头, 而不是第一条记录。

3、提取数据

打开游标之后,就可以在代码块的可执行部分,将游标工作区中的数据取到变量中。格式如下:

FETCH 游标名 INTO 变量名1[,变量名2...];FETCH 游标名 INTO 记录变量; 

说明:
(1)游标打开后有一个指针指向数据区,FETCH语句执行一次返回指针所指的一行数据,要返回多行数据可以使用循环语句来实现。可以通过判断游标的%found或%notfound属性的值来控制循环。
(2)第一种格式中变量的个数和类型应与SELECT语句中的字段变量的个数和类型一致。
(3)第二种格式一次将一行数据取到记录变量中,需要使用%ROWTYPE事先定义记录变量。

4、关闭游标
CLOSE 游标名;

说明:显式游标打开后,必须显式地关闭。游标一旦关闭,游标占用的资源就被释放,游标变成无效,必须重新打开才能使用。

三、遍历循环游标

1、使用Loop循环

使用Loop循环遍历游标之前,需要先声明并打开游标,使用完毕需要手动关闭游标。

Loop
    Fatch 游标名 InTo ....;
    Exit When 游标名%NotFound;
End Loop;
2、使用for循环

循环执行时隐式打开游标,自动获取一条记录,并自动创建临时记录类型变量存储记录。处理完后自动关闭游标。格式如下:

For 变量名 In 游标名 Loop
      数据处理语句;
End Loop;

四、游标使用举例

1、利用游标显示10号部门所有雇员的姓名、雇佣日期、工资和奖金
(1)使用Loop循环
SQL> 
declare
    row_emp emp%rowtype;
    cursor cur_emp 
    is select * from emp
    where deptno=10;   --定义游标变量
begin
    open cur_emp;           --打开游标
    loop
        fetch cur_emp into row_emp;
        exit when cur_emp%notfound;
        dbms_output.put_line('雇员姓名:'||rpad((row_emp.ename),7,' ')||
             ',雇佣日期:'||row_emp.hiredate||',工资:'||row_emp.sal||
             ',奖金:'||nvl(row_emp.comm,0));
    end loop;
    close cur_emp;          --关闭游标
end;
/
雇员姓名:MILLER ,雇佣日期:1982-01-23 00:00:00,工资:1300,奖金:100
雇员姓名:CLARK  ,雇佣日期:1981-06-09 00:00:00,工资:2450,奖金:0
雇员姓名:KING   ,雇佣日期:1981-11-17 00:00:00,工资:5000,奖金:0

PL/SQL procedure successfully completed.
(2)使用for循环
SQL> 
begin
    for cur_emp in (select * from emp where deptno=10) loop
        dbms_output.put_line('雇员姓名:'||rpad((cur_emp.ename),7,' ')||
             ',雇佣日期:'||cur_emp.hiredate||',工资:'||cur_emp.sal||
             ',奖金:'||nvl(cur_emp.comm,0));
    end loop;
end;
  8  /
雇员姓名:MILLER ,雇佣日期:1982-01-23 00:00:00,工资:1300,奖金:100
雇员姓名:CLARK  ,雇佣日期:1981-06-09 00:00:00,工资:2450,奖金:0
雇员姓名:KING   ,雇佣日期:1981-11-17 00:00:00,工资:5000,奖金:0

PL/SQL procedure successfully completed.
2、显示每个部门中工资最高的前两名员工的姓名、雇佣日期、工资、奖金
SQL> 
declare 
    emp_count number default 1;
begin
    for cur_dept in (select * from dept order by deptno) loop
        emp_count:=1;
        dbms_output.put_line('部门编号:'||cur_dept.deptno||
             ',部门名称:'||cur_dept.dname);
        for cur_emp in (select ename,hiredate,sal,comm 
            from emp where deptno=cur_dept.deptno 
            order by sal desc) loop
                dbms_output.put_line('===>雇员姓名:'||
                     rpad((cur_emp.ename),7,' ')||
                     ',雇佣日期:'||cur_emp.hiredate||
                     ',工资:'||cur_emp.sal||
                     ',奖金:'||nvl(cur_emp.comm,0));
        exit when emp_count>=2;
        emp_count:=emp_count+1;
        end loop;
    end loop;
end;
 21  /
部门编号:10,部门名称:ACCOUNTING
===>雇员姓名:KING   ,雇佣日期:1981-11-17 00:00:00,工资:5000,奖金:0
===>雇员姓名:CLARK  ,雇佣日期:1981-06-09 00:00:00,工资:2450,奖金:0
部门编号:20,部门名称:RESEARCH
===>雇员姓名:SCOTT  ,雇佣日期:1987-04-19 00:00:00,工资:3000,奖金:100
===>雇员姓名:FORD   ,雇佣日期:1981-12-03 00:00:00,工资:3000,奖金:100
部门编号:30,部门名称:SALES
===>雇员姓名:BLAKE  ,雇佣日期:1981-05-01 00:00:00,工资:2850,奖金:0
===>雇员姓名:ALLEN  ,雇佣日期:1981-02-20 00:00:00,工资:1600,奖金:300
部门编号:40,部门名称:OPERATIONS
===>雇员姓名:TOMMY  ,雇佣日期:2020-02-03 10:59:11,工资:8000,奖金:1200
===>雇员姓名:MARK DO,雇佣日期:2020-02-13 10:59:11,工资:3000,奖金:0

PL/SQL procedure successfully completed.

五、带参数的游标

如果游标带有参数,则打开游标时需要指定参数,带参数的游标格式如下:

CURSOR 游标名[(参数1 数据类型[,参数2 数据类型...])] 
IS SELECT 语句; 

例如:

SQL> 
declare
    row_emp emp%rowtype;
    cursor cur_emp(dept_no number) is
    select * from emp where deptno=dept_no;
begin
    open cur_emp(10);
    loop
        fetch cur_emp into row_emp;
        exit when cur_emp%notfound;
        dbms_output.put_line('雇员编号:'||row_emp.empno||
            ',  姓名:'||row_emp.ename);
    end loop;
    close cur_emp;
end;
 15  /
雇员编号:7934,  姓名:MILLER
雇员编号:7782,  姓名:CLARK
雇员编号:7839,  姓名:KING

PL/SQL procedure successfully completed.

使用for循环:

SQL> 
declare
    cursor cur_emp(dept_no number) is
    select * from emp where deptno=dept_no;
begin
    for r in cur_emp(20) loop
        dbms_output.put_line('雇员编号:'||r.empno||
            ',  姓名:'||r.ename);
    end loop;
end;
 10  /
雇员编号:7788,  姓名:SCOTT
雇员编号:7876,  姓名:ADAMS
雇员编号:7566,  姓名:JONES
雇员编号:7902,  姓名:FORD
雇员编号:7369,  姓名:SMITH

PL/SQL procedure successfully completed.

改变游标的参数:

SQL> 
declare
    cursor cur_emp(dept_no number) is
    select * from emp where deptno=dept_no;
begin
    for r in cur_emp(10) loop
        dbms_output.put_line('雇员编号:'||r.empno||
            ',  姓名:'||r.ename);
    end loop;
end;
 10  /
雇员编号:7934,  姓名:MILLER
雇员编号:7782,  姓名:CLARK
雇员编号:7839,  姓名:KING

PL/SQL procedure successfully completed.

六、动态游标的用法

对于查询结果为一行的SELECT语句,可以用动态生成查询语句字符串的方法,在程序执行阶段临时地生成并执行。
语法如下:

execute immediate 查询语句字符串 into 变量1[,变量2...];

例如:

SQL> 
declare
    str varchar2(200);
    v_ename varchar2(10);
begin
    str:='select ename from emp where empno=7788';
    execute immediate str into v_ename;
    dbms_output.put_line('name:'||v_ename);
end;
/
name:SCOTT

PL/SQL procedure successfully completed.

使用动态游标可以在程序运行阶段随时生成一个查询语句作为游标。要使用动态游标需要先定义一个游标类型,然后声明一个游标变量,游标对应的查询语句可以在程序的执行过程中动态地说明。

1、定义动态游标类型

语法如下:

TYPE 游标类型名 REF CURSOR;
2、声明游标变量

语法如下:

游标变量名 游标类型名;
3、打开动态游标

在代码块的执行部分打开一个动态游标。语法如下:

OPEN 游标变量名 FOR 查询语句字符串;
4、动态游标应用举例

查询姓名以某个字母开头的雇员,并把雇员编号和姓名显示出来:

SQL> 
declare    
    type cur_type is ref cursor;  --声明一个动态游标
    cur_emp cur_type;
    row_emp emp%rowtype;
    str varchar2(50);
    letter char:='M';
begin  
    str:= 'select * from emp where ename like '''||letter||'%''';  --字符串中如果包含单引号('),用两个单引号代替
    open cur_emp for str;   --打开动态游标
    loop
        fetch cur_emp into row_emp;
            exit when cur_emp%notfound;
        dbms_output.put_line('雇员编号:'||row_emp.empno||
             ',姓名:'||row_emp.ename);
    end loop;
end;  
 17  /
雇员编号:7934,姓名:MILLER
雇员编号:7654,姓名:MARTIN
雇员编号:8101,姓名:MARK DOWN

PL/SQL procedure successfully completed.
  • 6
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
游标是一种用于在数据库处理查询结果集的数据结构。在Oracle,可以使用游标在存储过程处理查询结果。引用\[1\]的代码是一个示例,展示了如何在Oracle存储过程使用游标。在这个示例,存储过程selectStudent接受一个输入参数v_id,并返回两个输出参数v_result和v_list。存储过程的v_list是一个SYS_REFCURSOR类型的游标,用于存储查询结果。通过调用存储过程时,可以设置输入参数的值,并注册输出参数的类型。然后,执行存储过程,并通过getInt方法获取输出参数v_result的值。最后,通过getObject方法获取游标v_list,并遍历结果集进行操作。引用\[2\]的代码展示了如何通过连接调用Oracle存储过程,并获取存储过程的输出结果。在这个示例使用CallableStatement对象调用存储过程selectStudent,并设置输入参数和注册输出参数的类型。然后,执行存储过程,并通过getInt方法获取输出参数的值,通过getObject方法获取游标,并遍历结果集进行操作。引用\[3\]的代码展示了一个数据库操作工具类JdbcUtil,用于获取数据库连接。这个工具类可以在Java程序使用,以便连接到Oracle数据库并执行相应的操作。 #### 引用[.reference_title] - *1* *2* *3* [Java调用Oracle存储过程,以及Oracle游标使用](https://blog.csdn.net/it_boy_elite/article/details/77711682)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

睿思达DBA_WGX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值