对于编程语言都会有成块的语句用来一次性进行一个较复杂的操作,咱们数据库也有,接下来几篇将会提到游标、存储过程、以及触发器。
本篇讲解游标。
一、介绍
怎么说呢,游标就像在进行单步断点调试中的那个断点,程序进行到哪一步,断点就停在哪一行(可能描述不准确,仅用来解释游标),游标就是数据操作到哪一行就指向哪一行。
二、举例
游标可能对我来说比较陌生,所以我用例子引用的方法来给自己一个大致的样子和了解。(该例为静态显示游标)
--将persons表中某一城市的学生姓名、年龄取出并存入c_p表中
declare
v_city Persons.city %type := &p_city;
v_name Persons.name %type;
v_age Persons.age %type;
cursor c is select name,age from Persons
where city = v_city;
begin
open c;
loop
fetch c into v_name,v_age;
exit when c %notfound;
insert into c_p(name,age) values(v_name,v_age);
end loop;
close c;
commit;
end;
看缩进,有两部分 declare和begin-end。declare中定义了内存变量、游标变量,begin-end中有open 游标、loop-end loop、close 游标、commit,在这其中loop-end loop中就是具体操作。
了解后,我们来详细对游标分类说明。
三、游标分类说明
1、静态
静态是指在编译阶段,数据的结果集已经确定
(1)显示Cursor
主要是用于一条select有多条结果的情况
a.结构:declare + begin-(open-(操作)-close)-end
- 定义:
(内存变量)
v_name1 char;
--类型为char
v_name2 table.name %type;
--类型为table表中name属性的类型
内存变量有变量名、属性即可
(游标变量)
cursor c_name [可加参数] is
select ……;
这样使得游标与select出来的结果建立了关联
- 打开游标:
在这里电脑内部帮我们完成了很多事:
- 执行游标对应的select语句
- 将查询结果放入工作区
- 将游标指针指向工作区首部
open c_name(v1,v2); --定义有参数时加上参数值
- 取值:
操作:
- 将游标对应的数据取出
- 放入到指定的输出变量中
- 游标自动下移一行
fetch c_name into v1,v2;
--取出数据 放入 指定输出变量
或
fetch c_name into pl/sql_record;
--使用记录变量
记录变量定义:(可跳过)
含义:类似结构体变量,其类型为组合类型
re_name c_name %rowtype; --以 c_name游标中的属性类型 为一个组合类型
或
re_name t_name %rowtype; --以 t_name表中的属性类型 为一个组合类型
- 关闭游标:
close c_name;
- 游标属性
可以在操作中使用,来判断游标位置和状态
c_name % isopen --返回布尔型,判断游标是否打开
c_name % notfound --返回布尔型,判断最近一次fetch有无结果,无结果为true
c_name % found --与notfound相对
c_name % rowcount --返回数字型,返回当前为止的记录数
b.整体结构:
declare
v_name2 char;
v_name2 table.name %type;
cursor c_name is
select ……;
begin
open c_name(v1,v2);
fetch c_name into v1,v2;
close c_name;
end;
c.回看举例:
--将persons表中某一城市的学生姓名、年龄取出并存入c_p表中
declare
v_city Persons.city %type := &p_city;
v_name Persons.name %type;
v_age Persons.age %type;
cursor c is select name,age from Persons
where city = v_city;
begin
open c;
loop
fetch c into v_name,v_age;
exit when c %notfound;
insert into c_p(name,age) values(v_name,v_age);
end loop;
close c;
commit;
end;
- loop-end loop:这是一个循环,将fetch放在循环内可依次获得缓冲区的每一行
对于循环c语言学过for(int i=0;i<n;i++),需要确定循环起末以及跨度,例子中起条件为无,跨度条件为fetch自动下移,末条件用exit when 定义 c % notfound(注意循环中语句的位置)
while …… loop-end loop(替代loop-end loop)
fetch c into v_name,v_age;
while c % found loop
insert into c_p(name,age) values(v_name,v_age);
fetch c into v_name,v_age;
end loop;
for …… loop-end loop(替代begin-end中的内容)
for re_name in c loop
insert into c_p(name,age)
values(re_name.name,re_name.age);
end loop;
这里适用于用记录变量来遍历,这里的记录变量为系统隐式定义无需自行定义,这里的格式就很像Python的for …… in……:
- := &p_city:这是通过人机交互的方式给v_city赋值,简单来说就是程序运行时会有弹窗给你输入数值来赋值
这里p_city仅仅是个名称,可变化但不要与其他名称重复
- commit:是一个结束当前事务的操作,目前以我的能力还不太能用到它(可不用)
(2)隐式Cursor
主要用于一条select仅有一条结果的情况
怎么说呢,隐式游标就是你不需要手动去定义游标,系统会自动生成一个游标来辅助你
其中insert、delete、select、update语句都有隐式游标存在
举例:
--清空s表中的数据并输出删了多少行
begin
delete from s;
--输出
dbms_output.put_line(sql%rowcount||'行已清除');
commit;
end;
结果:
- delete:这里隐含了一个游标
- dbms_output.put_line:这是输出语句
- sql%rowcount:%rowcount就是游标属性,sql为隐含游标的统一名称
2、动态
动态与静态相对,即编译阶段还不能确定结果集。
Ref Cursor
举例:
declare
c1 sys_refcursor; --游标定义
v1 varchar2(20);
v2 number;
begin
--打开并定义游标所查的结果集
open c1 for select ename from emp;
loop
fetch c1 into v1;
exit when c1%notfound;
dbms_output.put_line(v1);
end loop;
close c1;
open c1 for select loc from dept;
loop
fetch c1 into v1;
exit when c1%notfound;
dbms_output.put_line(v1);
end loop;
close c1;
open c1 for select count(1) from emp group by deptno;
loop
fetch c1 into v2;
exit when c1%notfound;
dbms_output.put_line(v2);
end loop;
close c1;
end;
未完待续