什么是游标?
①从表中检索出结果集,从中每次指向一条记录进行交互的机制。
②关系数据库中的操作是在完整的行集合上执行的。
由 SELECT 语句返回的行集合包括满足该语句的 WHERE 子句所列条件的所有行。由该语句返回完整的行集合叫做结果集。
应用程序,尤其是互动和在线应用程序,把完整的结果集作为一个单元处理并不总是有效的。
这些应用程序需要一种机制来一次处理一行或连续的几行。而游标是对提供这一机制的结果集的扩展。
游标是通过游标库来实现的。游标库是常常作为数据库系统或数据访问 API 的一部分而得以实现的软件,用来管理从数据源返回的数据的属性(结果集)。这些属性包括并发管理、在结果集中的位置、返回的行数,以及是否能够在结果集中向前和/或向后移动(可滚动性)。
游标跟踪结果集中的位置,并允许对结果集逐行执行多个操作,在这个过程中可能返回至原始表,也可能不返回至原始表。
换句话说,游标从概念上讲基于数据库的表返回结果集。
由于它指示结果集中的当前位置 ,就像计算机屏幕上的光标指示当前位置一样,“游标”由此得名。
游标有什么作用?
①指定结果集中特定行的位置。
②基于当前的结果集位置检索一行或连续的几行。
③在结果集的当前位置修改行中的数据。
④对其他用户所做的数据更改定义不同的敏感性级别。
⑤可以以编程的方式访问数据库。
一、游标:
1、概念:
游标的本质是一个结果集resultset,主要用来临时存储从数据库中提取出来的数据块。
二、游标的分类:
1、显式游标:
由用户定义,需要的操作:定义游标、打开游标、提取数据、关闭游标,主要用于对查询语句的处理。
属性:%FOUND %NOTFOUND %ISOPEN %ROWCOUNT
Example:打印emp表的员工信息
DECLARE
CURSOR
emp_cursor
IS
SELECT
empno,ename,job
FROM
emp;
v_empno emp.empno%TYPE;
v_name emp.ename%TYPE;
v_job emp.job%TYPE;
BEGIN
OPEN
emp_cursor;
LOOP
FETCH
emp_cursor
INTO
v_empno,v_name,v_job;
DBMS_OUTPUT.PUT_LINE(
‘员工号为:‘
||v_empno||
‘姓名是‘
||v_name||
‘职位:‘
||v_job);
EXIT
WHEN
emp_cursor%NOTFOUND;
END
LOOP;
CLOSE
emp_cursor;
END
;
这里严格按照显示游标的书写规则:DECLARE emp_cursor定义游标OPEN emp_cursor打开游标FETCH emp_cursor INTO...提取数据CLOSE emp_cursor关闭游标,因为提取出来的数据属于多行,所以通过loop循环打印即可。
Example2:检验游标是否打开,如果打开显示提取行数
DECLARE
CURSOR
emp_cursor
IS
SELECT
empno,ename,job
FROM
emp;
v_empno emp.empno%TYPE;
v_name emp.ename%TYPE;
v_job emp.job%TYPE;
BEGIN
OPEN
emp_cursor;
LOOP
FETCH
emp_cursor
INTO
v_empno,v_name,v_job;
EXIT
WHEN
emp_cursor%NOTFOUND;
END
LOOP;
IF emp_cursor%ISOPEN
THEN
DBMS_OUTPUT.PUT_LINE(
‘游标已打开‘
);
DBMS_OUTPUT.PUT_LINE(
‘读取了‘
||emp_cursor%ROWCOUNT||
‘行‘
);
ELSE
DBMS_OUTPUT.PUT_LINE(
‘游标没有打开‘
);
END
IF;
CLOSE
emp_cursor;
END
;
-- 游标(光标cursor)
--在写Java程序中有集合的概念, 那么在pl/sql中也会用到多条记录, 这时候我们就要用到游标, 游标可以存储查询返回的多条数据。
-- 语法:cursor 游标名(参数 数据类型,参数 数据类型) is select 语句;
-- 列如 cursor c1 is select ename from emp;
-- 游标使用步骤
-- 打开游标:open c1
-- 取一行游标值 fetch c1 into pjob;(取一行数据到变量中)
-- 关闭游标 close c1
-- 游标结束方式 exit when c1%notfound
-- 查询姓名和工资
declare
cursor vrows is select * from emp;
vrow emp%Rowtype;
begin
open vrows;
loop
fetch vrows into vrow;
exit when vrows%notfound;
dbms_output.put_line(‘姓名:‘||vrow.ename||‘ ‘||‘工资:‘||vrow.sal);
end loop;
close vrows;
end;
-- 指定部门下的员工工资
declare
cursor deptSal(dno number) is select * from emp where deptno=dno;
dep emp%rowtype;
begin
open deptSal(10);
loop
fetch deptSal into dep;
exit when deptSal%notfound;
dbms_output.put_line(‘员工姓名:‘||dep.ename||‘ ‘||‘工资:‘||dep.sal);
end loop;
close deptSal;
end;
-- 引用系统游标
declare
vrows sys_refcursor; -- 引用系统游标
vrow emp%rowtype; -- 记录一行数据
begin
open vrows for select * from emp;
loop
fetch vrows into vrow;
exit when vrows%notfound;
dbms_output.put_line(‘姓名:‘||vrow.ename||‘ ‘||‘工资:‘||vrow.sal);
end loop;
close vrows;
end;
-- 使用for循环遍历游标
declare
-- 申明游标
cursor vrows is select * from emp;
begin
for vrow in vrows loop
dbms_output.put_line(‘姓名为:‘||vrow.ename||‘工资为:‘||vrow.sal);
end loop;
end;
-- 按员工的工种长工资,总裁1000元,经理长800元其, 他人员长400元
declare
cursor vrows is select * from emp;
vrow emp%rowtype;
begin
open vrows;
loop
fetch vrows into vrow;
exit when vrows%notfound;
if vrow.job=‘PRESIDENT‘ then
update emp set sal=sal+1000 where empno=vrow.empno;
elsif vrow.job=‘MANAGER‘ then
update emp set sal=sal+800 where empno=vrow.empno;
else
update emp set sal=sal+400 where empno=vrow.empno;
end if;
dbms_output.put_line(‘姓名为:‘||vrow.ename||‘工资为:‘||vrow.sal);
end loop;
close vrows;
end;
2、隐式游标:由系统定义并为它创建工作区域,并且隐式的定义打开提取关闭,隐式游标的游标名就是‘SQL‘,属性和显示游标相同,主要用于对单行select语句或dml操作进行处理。Example:又用户输入员工号修改员工工资如成功则打印输出成功标志。
3、参数游标:
在定义游标时加入参数的游标,可以配合游标for循环快速找到需要的数据。这里先讲一下游标for循环
A、游标FOR循环:
隐含的执行了打开提取关闭数据,代码精简很多。Expression:
FOR table_record IN table_cursor LOOP
STATEMENT;
END LOOP;
三、使用游标修改数据的注意事项
1、使用游标修改数据时,为防止他人在自己操作数据时对数据进行修改,oracle提供for update子句进行加锁。
同时在你使用update或delete时,必须使用where current of+name_cursor语句,以及在最后记得提交。如果是级联操作则可以使用for update of 来进行相关表的加锁。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
声明游标;CURSOR cursor_name IS select_statement
--For 循环游标
--(1)定义游标
--(2)定义游标变量
--(3)使用for循环来使用这个游标
declare
--类型定义
cursor c_job
is
select empno,ename,job,sal
from emp
where job=‘MANAGER‘;
--定义一个游标变量v_cinfo c_emp%ROWTYPE ,该类型为游标c_emp中的一行数据类型
c_row c_job%rowtype;
begin
for c_row in c_job loop
dbms_output.put_line(c_row.empno||‘-‘||c_row.ename||‘-‘||c_row.job||‘-‘||c_row.sal);
end loop;
end;
--Fetch游标
--使用的时候必须要明确的打开和关闭
declare
--类型定义
cursor c_job
is
select empno,ename,job,sal
from emp
where job=‘MANAGER‘;
--定义一个游标变量
c_row c_job%rowtype;
begin
open c_job;
loop
--提取一行数据到c_row
fetch c_job into c_row;
--判读是否提取到值,没取到值就退出
--取到值c_job%notfound 是false
--取不到值c_job%notfound 是true
exit when c_job%notfound;
dbms_output.put_line(c_row.empno||‘-‘||c_row.ename||‘-‘||c_row.job||‘-‘||c_row.sal);
end loop;
--关闭游标
close c_job;
end;
--1:任意执行一个update操作,用隐式游标sql的属性%found,%notfound,%rowcount,%isopen观察update语句的执行情况。
begin
update emp set ENAME=‘ALEARK‘ WHERE EMPNO=7469;
if sql%isopen then
dbms_output.put_line(‘Openging‘);
else
dbms_output.put_line(‘closing‘);
end if;
if sql%found then
dbms_output.put_line(‘游标指向了有效行‘);--判断游标是否指向有效行
else
dbms_output.put_line(‘Sorry‘);
end if;
if sql%notfound then
dbms_output.put_line(‘Also Sorry‘);
else
dbms_output.put_line(‘Haha‘);
end if;
dbms_output.put_line(sql%rowcount);
exception
when no_data_found then
dbms_output.put_line(‘Sorry No data‘);
when too_many_rows then
dbms_output.put_line(‘Too Many rows‘);
end;
declare
empNumber emp.EMPNO%TYPE;
empName emp.ENAME%TYPE;
begin
if sql%isopen then
dbms_output.put_line(‘Cursor is opinging‘);
else
dbms_output.put_line(‘Cursor is Close‘);
end if;
if sql%notfound then
dbms_output.put_line(‘No Value‘);
else
dbms_output.put_line(empNumber);
end if; dbms_output.put_line(sql%rowcount);