一、游标的概念
游标是一种访问机制,它允许用户访问单独的数据行(对数据逐行进行操作),而非对整个结果行集进行操作.
简而言之:游标就是位于内存中的数据集,加快对数据的操作
使用游标的步骤:
- 创建游标
- 打开游标
- 存取游标
- 关闭游标
--创建表
SQL> create table stu(id number(5),name varchar(10));
SQL> insert into stu values(1,'zhangsan');
SQL> insert into stu values(2,'lisi');
--游标
declare
-- 1 声明游标
cursor cur_stu is select * from stu;
v_stu cur_stu%rowtype;--声明变量v_stu,和stu和行属性同类型
begin
-- 2 开启游标
open cur_stu;
-- 3 获取数据(一次获取一行)
fetch cur_stu
into v_stu;
dbms_output.put_line(v_stu.id || ' : ' || v_stu.name);
-- 4 关闭游标
close cur_stu;
end;
- %TYPE说明
为了使一个变量的数据类型与另一个已经定义了的变量(尤其是表的某一列)的数据类型相一致,Oracle提供了%TYPE定义方式。当被参照的那个变量的数据类型改变了之后,这个新定义的变量的数据类型会自动跟随其改变,容易保持一致,也不用修改PL/SQL程序了。当不能确切地知道被参照的那个变量的数据类型时,就只能采用这种方法定义变量的数据类型。- %ROWTYPE说明
如果一个表有较多的列,使用%ROWTYPE来定义一个表示表中一行记录的变量,比分别使用%TYPE来定义表示表中各个列的变量要简洁得多,并且不容易遗漏、出错。这样会增加程序的可维护性。
为了使一个变量的数据类型与一个表中记录的各个列的数据类型相对应、一致,Oracle提供%ROWTYPE定义方式。当表的某些列的数据类型改变了之后,这个新定义的变量的数据类型会自动跟随其改变,容易保持一致,也不用修改PL/SQL程序了。当不能确切地知道被参照的那个表的结构及其数据类型时,就只能采用这种方法定义变量的数据类型。
一行记录可以保存从一个表或游标中查询到的整个数据行的各列数据。一行记录的各个列与表中一行的各个列有相同的名称和数据类型。
二、游标的属性
游标的属性(同样也有 %ROWCOUNT、%NOTFOUND、%ISOPEN 、%FOUND)
属性 | 返回值类型 | 作用 |
---|---|---|
sql%isopen | 布尔型 | 判断游标是否 ‘开启’ |
sql%found | 布尔型 | 判断游标是否 ‘获取’ 到值 |
sql%notfound | 布尔型 | 判断游标是否 ‘没有获取’ 到值(常用于 “退出循环”) |
sql%rowcount | 整型 | ‘当前’ 成功执行的数据行数(非 “总记录数”) |
--显示所有的员工姓名
create or replace procedure showEmpEname as
cursor emp_cur is select ename from emp;
v_name emp.ename%type;
begin
open emp_cur;
fetch emp_cur into v_name;
while emp_cur%FOUND loop
dbms_output.put_line('name is: ' || v_name);
fetch emp_cur into v_name ;
end loop;
close emp_cur;
end;
三、使用 fetch bulk collect into 批量提取数据
fetch bulk collect into 的使用格式是:
fetch some_cursor bulk collect into col1, col2 limit xxx。
- col1、col2 是声明的集合类型变量,xxx 为每次取数据块的大小(记录数),
- 相当于缓冲区的大小,可以不指定 limit xxx 大小
--使用 fetch bulk collect into 批量提取数据
--type ... is recard :定义一个记录行类型
--type...is table of :定义一个存放记录行类型元素的集合类型即表
declare
cursor emp_cur is select ename from emp;
type emp_name_type is table of emp.ename%type;
emp_name emp_name_type;
begin
open emp_cur;
fetch emp_cur bulk collect into emp_name;
for i in 1..emp_name.count loop
dbms_output.put_line('name: ' || emp_name(i));
end loop;
close emp_cur;
end;
--用游标方式显示姓名和工资
create or replace procedure ShowEmpNameSal is
cursor emp_cursor is select ename,sal from emp;
v_name emp.ename%type;
v_sal emp.sal%type;
begin
open emp_cursor;
loop
fetch emp_cursor into v_name,v_sal;
exit when emp_cursor%NOTFOUND ;
dbms_output.put_line('Name: ' || v_name || ' Sal: ' || v_sal);
end loop;
close emp_cursor;
end;
--用游标方式显示姓名和工资(批量提取)
create or replace procedure showEmpNameSal is
cursor emp_cursor is select ename,sal from emp;
TYPE emp_record_type is record(v_name emp.ename%type,v_sal emp.sal%type);
TYPE emp_table_type is table of emp_record_type;
emp_table emp_table_type;
begin
open emp_cursor;
fetch emp_cursor bulk collect into emp_table;
for i in 1..emp_table.count loop
dbms_output.put_line('Name: ' || emp_table(i).v_name || ' Sal: ' || emp_table(i).v_sal);
end loop;
close emp_cursor;
end;
--使用基于游标定义的记录变量
--用游标方式显示姓名和工资(批量提取)
declare
cursor emp_cur_ename_sal is select ename,sal from emp;
type emp_table_ename_sal is table of emp_cur_ename_sal%rowtype;
emp_table emp_table_ename_sal;
begin
open emp_cur_ename_sal;
fetch emp_cur_ename_sal bulk collect into emp_table;
for i in 1..emp_table.count loop
dbms_output.put_line('name: ' || emp_table(i).ename || ' sal: ' || emp_table(i).sal);
end loop;
close emp_cur_ename_sal;
end;
四、通过游标修改数据
- 声明时要加for update
- 更改数据时要加where current of cursor_name
--根据部门编号给低于100的人增加工资
create or replace procedure updateSalByDeptno(dno emp.deptno%type,addSal emp.sal%type) is
cursor emp_cursor is select sal from emp where deptno = dno for update;
v_sal emp.sal%type;
begin
open emp_cursor;
loop
fetch emp_cursor into v_sal;
exit when emp_cursor%NOTFOUND ;
if v_sal < 100 then
update emp set sal = v_sal + addSal where current of emp_cursor;
end if;
end loop;
close emp_cursor;
end;
--删除数据
--删除某个部门的工资低于1000的员工
create or replace procedure deleteEmpInfoBydeptno(dno emp.deptno%type) is
cursor emp_cursor is select sal from emp where deptno = dno for update;
v_sal emp.sal%type;
begin
open emp_cursor;
loop
fetch emp_cursor into v_sal;
exit when emp_cursor%NOTFOUND ;
if v_sal < 1000 then
delete from emp where current of emp_cursor;
end if;
end loop;
close emp_cursor;
end;
--游标for 循环
declare
cursor emp_cursor is select empno,ename,sal from emp;
begin
for emp_record in emp_cursor loop--自动打开,且不用定义变量
dbms_output.put_line('Name: ' || emp_record.ename || ' Sal: ' || emp_record.sal );
end loop; --自动关闭
end;
--更简洁的写法
begin
for emp_record in (select ename,sal from emp) loop
dbms_output.put_line('Name: ' || emp_record.ename || ' Sal: ' || emp_record.sal);
end loop;
end;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)