一、游标
游标用来处理从数据库中检索的多行记录(使用SELECT语句)。利用游标,程序可以逐个地处理和遍历一次检索返回的整个记录集。
为了处理SQL语句,Oracle将在内存中分配一个区域,这就是上下文区。这个区包含了已经处理完的行数、指向被分析语句的指针,整个区是查询语句返回的数据行集。游标就是指向上下文区句柄或指针。
二、游标的分类:
1、静态游标:静态游标是在编译时知道其SELECT语句的游标。静态游标又分为两种类型,隐式游标和显示游标。
2、动态游标:用户为游标使用的查询直到运行的时候才能确定,可以使用REF游标和游标变量满足这个要求。为了使用引用游标,必须声明游标变量。有两种类型的REF游标:强类型REF游标和弱类型REF游标。
三、显示游标的用法:
显示游标被用于处理返回多行数据的SELECT 语句,游标名通过CURSOR….IS 语句显示地赋给SELECT 语句。
(一)使用步骤;
1)声明游标: CURSOR cursor_name IS select_statement
2)为查询打开游标: OPEN cursor_name
3)取得结果放入PL/SQL变量中;
FETCH cursor_name INTO list_of_variables;
FETCH cursor_name INTO PL/SQL_record;
4)关闭游标。 CLOSE cursor_name
注意:在声明游标时, select_statement不能包含INTO子句。当使用显示游标时,INTO子句是FETCH语句的一部分。
例:显示雇员的名称和薪水
--
使用LOOP遍历游标
DECLARE
v_name emp.ename
%
TYPE;
v_sal emp.sal
%
TYPE;
CURSOR
cus_emp
IS
SELECT
ename,sal
FROM
emp;
--
声明游标
BEGIN
OPEN
cus_emp;
--
打开游标
LOOP
FETCH
cus_emp
INTO
v_name,v_sal;
--
提取游标
EXIT
WHEN
cus_emp
%
NOTFOUND;
dbms_output.put_line(
'
第
'
||
cus_emp
%
ROWCOUNT
||
'
个用户: name:
'
||
v_name
||
'
sal:
'
||
v_sal);
END
LOOP;
CLOSE
cus_emp;
--
关闭游标
END
;
显示游标的属性:
%FOUND:只有在DML语句影响一行或者多行是,则返回TRUE;
%NOTFOUND:没有影响任何行,则返回TRUE。
%ROWCOUNT:返回DML语句影响的行数,没有影响则返回0;
%ISOPEN:返回游标是否打开,在执行SQL之后,Oracle自动关闭SQL游标,所以隐式游标的%isopen属性始终未false;
另一种方式:
--
使用for来简化游标遍历
DECLARE
CURSOR
cus_emp
IS
SELECT
ename,sal
FROM
emp;
BEGIN
FOR
record_emp
IN
cus_emp
LOOP
dbms_output.put_line(
'
第
'
||
cus_emp
%
ROWCOUNT
||
'
个用户: name:
'
||
record_emp.ename
||
'
sal:
'
||
record_emp.sal);
END
LOOP;
END
;
record_emp是plsql声明的的记录变量,此变量的属性为声明为%ROWTYPE类型,作用域在FOR循环之内,即在FOR循环外就不能访问了。
循环游标的特性:
(1)从游标中提取了所有记录之后自动终止。
(2)提取和处理游标中的每一条记录。
(3)如果在提取记录之后%NOTFOUND属性返回TRUE,则终止循环。如果未返回任何行,则不进入循环。
游标案例:
--
给员工加薪,按员工入职时间进行加薪,每年加100,1000封顶
DECLARE
v_date emp.hiredate
%
TYPE;
v_empno emp.empno
%
TYPE;
v_money
NUMBER
;
CURSOR
cur_emp
IS
SELECT
empno,hiredate
FROM
emp;
BEGIN
OPEN
cur_emp;
LOOP
FETCH
cur_emp
INTO
v_empno,v_date;
EXIT
WHEN
cur_emp
%
NOTFOUND;
v_money :
=
100
*
(
1990
-
to_char(v_date,
'
yyyy
'
));
IF
v_money
<
1000
THEN
UPDATE
emp
SET
sal
=
sal
+
v_money
WHERE
empno
=
v_empno;
ELSE
UPDATE
emp
SET
sal
=
sal
+
1000
WHERE
empno
=
v_empno;
END
IF
;
END
LOOP;
END
;
四、隐式游标:
所有的隐式游标都被假设为只返回一条记录。
使用隐式游标时,用户无需进行声明、打开及关闭。PL/SQL隐含地打开、处理,然后关掉游标。多条sql语句 隐式游标SQL永远指的是最后一条sql语句的结果,主要使用在update 和 delete语句上。
隐式游标的四个属性:
| 属性 | 说明 |
| SQL%rowcount | 影响的记录的行数整数(用来判断插入,更新修改是否成功,必须在comit之前,否则提交后结果为0.) |
| SQL%found | 影响到了记录 true() |
| SQL%notfound | 没有影响到记录 true |
| SQL%isopen | 是否打开 布尔值 永远是false |
例如:
DECLARE
row_emp emp
%
ROWTYPE;
BEGIN
SELECT
ename,sal
INTO
row_emp.ename,row_emp.sal
FROM
emp
WHERE
emp.empno
=
7369
;
--
判断是否查到数据
if
(SQL
%
ROWCOUNT
=
1
)
THEN
dbms_output.put_line(
'
找到了
'
);
END
IF
;
--
另一种方式判断
IF
(SQL
%
Found)
THEN
dbms_output.put_line(
'
找到了
'
);
END
IF
;
dbms_output.put_line(
'
ename:
'
||
row_emp.ename
||
'
sal:
'
||
row_emp.sal);
END
;
上述游标自动打开,并把相关值赋给对应变量,然后关闭。执行完后,PL/SQL变量rowemp.ename,rowemp.sal中已经有了值。
五:动态游标
静态游标是在声明就已经确定查询语句,如果用户需要在运行时动态决定游标执行的查询,就需要使用动态游标(REF游标)。
动态游标分为两类: 强类型游标 和 弱类型游标 。
动态游标使用步骤:
1、声明动态游标类型;
2、打开游标,指定游标查询;
3、提取游标。
4、关闭游标。
例:
强类型游标, 使用return声明的游标为强类型游标。在对游标进行绑定查询只能绑定游标返回的类型rowtype。
--
强类型的动态游标,查询emp表中的数据
DECLARE
TYPE ref_cur
IS
REF
CURSOR
--
声明游标类型
RETURN
emp
%
ROWTYPE;
--
带返回值的为强类型动态游标
refcur_emp ref_cur;
--
游标类型对象
v_emp emp
%
ROWTYPE;
BEGIN
OPEN
refcur_emp
FOR
--
将游标绑定到一个查询语句,因为声明的是强类型,所以只能绑定emp;
SELECT
*
FROM
emp;
LOOP
FETCH
refcur_emp
INTO
v_emp;
--
提取游标内容
EXIT
WHEN
refcur_emp
%
NOTFOUND;
dbms_output.put_line(refcur_emp
%
Rowcount
||
'
、name:
'
||
v_emp.ename
||
'
sal:
'
||
v_emp.sal);
END
LOOP;
CLOSE
refcur_emp;
END
;
弱类型游标:可以用来绑定多个查询结果。
例:
--
弱类型游标
DECLARE
TYPE refcur
IS
REF
CURSOR
;
--
未定义返回类型为弱类型游标
rc refcur;
v_name emp.ename
%
TYPE;
v_deptname dept.dname
%
TYPE;
BEGIN
OPEN
rc
FOR
SELECT
ename,dname
FROM
emp e,dept d
WHERE
e.deptno
=
d.deptno;
--
绑定查询
LOOP
FETCH
rc
INTO
v_name,v_deptname;
EXIT
WHEN
rc
%
NOTFOUND;
dbms_output.put_line(
'
name:
'
||
v_name
||
'
deptname:
'
||
v_deptname);
END
LOOP;
CLOSE
rc;
END
;
例:
--
根据输入的内容绑定游标
DECLARE
TYPE refcur
IS
REF
CURSOR
;
rc refcur;
v_tablename
VARCHAR2
(
10
) :
=
'
&tab
'
;
v_id
NUMBER
;
v_name
VARCHAR2
(
20
);
BEGIN
IF
(v_tablename
=
'
e
'
)
THEN
OPEN
rc
FOR
SELECT
e.empno,e.ename
INTO
v_id,v_name
FROM
emp e;
dbms_output.put_line(
'
=========员工信息=============
'
);
Elsif(v_tablename
=
'
d
'
)
THEN
OPEN
rc
FOR
SELECT
d.deptno,d.dname
INTO
v_id,v_name
FROM
dept d;
dbms_output.put_line(
'
=========部门信息=============
'
);
ELSE
dbms_output.put_line(
'
输入错误,请输入e或者d!
'
);
RETURN
;
END
IF
;
LOOP
FETCH
rc
INTO
v_id,v_name;
dbms_output.put_line(
'
#
'
||
rc
%
Rowcount
||
'
id:
'
||
v_id
||
'
name:
'
||
v_name);
EXIT
WHEN
rc
%
NOTFOUND;
END
LOOP;
END
;

