游标的概念
在处理sql语句的时候,oracle必须分配一片名叫上下文(context area)的区域来处理所必须的信息,其中包括要处理的行的数目,被分析后语句的指针以及查询的活动集。
游标是一个指向context area的句柄(handle)或指针,它们可以被指针控制。
| SQL语句 | 游标 |
|
非查询语句 |
隐式 |
|
结果是单行的查询语句 |
隐式或显式 |
|
结果是多行的查询语句 |
显式 |
显式游标
显式游标处理需四个PL/SQL步骤 :
定义游标 :就是定义一个游标名,以及与其相对应的 SELECT 语句。
格式: CURSOR cursor_name[(parameter[, parameter]…)] IS select_statement;
注意:在指定数据类型时,不能使用长度约束 。如 NUMBER(4),CHAR(10) 等都是错误的。
打开游标: |
|
格式: |
|
在向游标传递参数时,可以使用与函数参数相同的传值方法,
提取游标:就是检索结果集合中的数据行,放入指定的输出变量中。格式:
FETCH cursor_name INTO {variable_list | record_variable };
|
关闭游标:当提取和处理完游标结果集合数据后,应及时关闭游标,以释放该游标所占用的系统资源, |
|
并使该游标的工作区变成无效,不能再使用 FETCH语句取其中数据。 |
|
格式: |
|
CLOSE cursor_name; |
|
注:定义的游标不能有 INTO子句。 |
|
|

|
例 2.游标参数的传递方法。 |

或者
%FOUND 布尔型属性,当最近一次读记录时成功返回,则值为TRUE;
%ISOPEN 布尔型属性,当游标已打开时返回TRUE;
%ROWCOUNT 数字型属性,返回已从游标中读取的记录数。
|
例 3:给工资低于 3000的员工工资调为3000。 |
|
游标的 FOR 循环 |
|
FOR循环语句,自动执行游标的 OPEN、FETCH、CLOSE语句和循环语句的功能; |
|
当进入循环时,游标 FOR循环语句自动打开游标,并提取第一行游标数据,当程序处理完当前所提取的数
|
隐式游标
|
显式游标主要是用于对查询语句的处理,尤其是在查询结果为多条记录的情况下; 对于隐式游标的操作,如定义、打开、取值及关闭操作,都由 ORACLE系统自动地完成,无需用户进行处理。用户只能通过隐式游标的相关属性,来完成相应的操作。在隐式游标的工作区中,所存放的数据是与用户自定义的显示游标无关的、
最新处理的一条 SQL语句所包含的数据。 |
|
|
%ISOPEN 布尔型属性,取值总是FALSE。SQL命令执行完毕立即关闭隐式游标;
%ROWCOUNT 数字型属性,返回已从游标中读取的记录数。
|
|

NO_DATA_FOUND和 %NOTFOUND的区别
|
SELECT …
INTO语句触发NO_DATA_FOUND;
|
|
游标修改和删除操作是指在游标定位下,修改或删除表中指定的数据行。这时,要求游标查询语句中 必须使用 FOR UPDATE选项,以便在打开游标时锁定游标结果集合在表中对应数据行的所有列和部分列。 为了对正在处理(查询)的行不被另外的用户改动,ORACLE提供一个 FOR UPDATE子句来对所选择的行 进行锁住。该需求迫使 ORACLE锁定游标结果集合的行,可以防止其他事务处理更新或删除相同的行,直到 |
|
|
|
如果另一个会话已对活动集中的行加了锁,那么 SELECT FOR UPDATE操作一直等待到其它的会话释放这 些锁后才继续自己的操作,对于这种情况,当加上 NOWAIT子句时,如果这些行真的被另一个会话锁定,
则 OPEN立即返回并给出:
|
以下为尚硅谷的讲解习题。
http://www.atguigu.com 宋红康
*********************************************************************************************************
12.1 使用游标
要求: 打印出 80 部门的所有的员工的工资:salary: xxx
declare
--1. 定义游标
cursor salary_cursor is select salary from employees where department_id = 80;
v_salary employees.salary%type;
begin
--2. 打开游标
open salary_cursor;
--3. 提取游标
fetch salary_cursor into v_salary;
--4. 对游标进行循环操作: 判断游标中是否有下一条记录
while salary_cursor%found loop
dbms_output.put_line('salary: ' || v_salary);
fetch salary_cursor into v_salary;
end loop;
--5. 关闭游标
close salary_cursor;
end;
12.2 使用游标
要求: 打印出 80 部门的所有的员工的工资: Xxx 's salary is: xxx
declare
cursor sal_cursor is select salary ,last_name from employees where department_id = 80;
v_sal number(10);
v_name varchar2(20);
begin
open sal_cursor;
fetch sal_cursor into v_sal,v_name;
while sal_cursor%found loop
dbms_output.put_line(v_name||'`s salary is '||v_sal);
fetch sal_cursor into v_sal,v_name;
end loop;
close sal_cursor;
end;
13. 使用游标的练习:
打印出 manager_id 为 100 的员工的 last_name, email, salary 信息(使用游标, 记录类型)
declare
--声明游标
cursor emp_cursor is select last_name, email, salary from employees where manager_id = 100;
--声明记录类型
type emp_record is record(
name employees.last_name%type,
email employees.email%type,
salary employees.salary%type
);
-- 声明记录类型的变量
v_emp_record emp_record;
begin
--打开游标
open emp_cursor;
--提取游标
fetch emp_cursor into v_emp_record;
--对游标进行循环操作
while emp_cursor%found loop
dbms_output.put_line(v_emp_record.name || ', ' || v_emp_record.email || ', ' || v_emp_record.salary );
fetch emp_cursor into v_emp_record;
end loop;
--关闭游标
close emp_cursor;
end;
(法二:使用for循环)
declare
cursor emp_cursor is
select last_name,email,salary
from employees
where manager_id = 100;
begin
for v_emp_record in emp_cursor loop
dbms_output.put_line(v_emp_record.last_name||','||v_emp_record.email||','||v_emp_record.salary);
end loop;
end;
14. 利用游标, 调整公司中员工的工资:
工资范围 调整基数
0 - 5000 5%
5000 - 10000 3%
10000 - 15000 2%
15000 - 1%
declare
--定义游标
cursor emp_sal_cursor is select salary, employee_id from employees;
--定义基数变量
temp number(4, 2);
--定义存放游标值的变量
v_sal employees.salary%type;
v_id employees.employee_id%type;
begin
--打开游标
open emp_sal_cursor;
--提取游标
fetch emp_sal_cursor into v_sal, v_id;
--处理游标的循环操作
while emp_sal_cursor%found loop
--判断员工的工资, 执行 update 操作
--dbms_output.put_line(v_id || ': ' || v_sal);
if v_sal <= 5000 then
temp := 0.05;
elsif v_sal<= 10000 then
temp := 0.03;
elsif v_sal <= 15000 then
temp := 0.02;
else
temp := 0.01;
end if;
--dbms_output.put_line(v_id || ': ' || v_sal || ', ' || temp);
update employees set salary = salary * (1 + temp) where employee_id = v_id;
fetch emp_sal_cursor into v_sal, v_id;
end loop;
--关闭游标
close emp_sal_cursor;
end;
使用SQL中的 decode 函数
update employees set salary = salary * (1 + (decode(trunc(salary/5000), 0, 0.05,
1, 0.03,
2, 0.02,
0.01)))
15. 利用游标 for 循环完成 14.
declare
--定义游标
cursor emp_sal_cursor is select salary, employee_id id from employees;
--定义基数变量
temp number(4, 2);
begin
--处理游标的循环操作
for c in emp_sal_cursor loop
--判断员工的工资, 执行 update 操作
--dbms_output.put_line(v_id || ': ' || v_sal);
if c.salary <= 5000 then
temp := 0.05;
elsif c.salary <= 10000 then
temp := 0.03;
elsif c.salary <= 15000 then
temp := 0.02;
else
temp := 0.01;
end if;
--dbms_output.put_line(v_id || ': ' || v_sal || ', ' || temp);
update employees set salary = salary * (1 + temp) where employee_id = c.id;
end loop;
end;
16*. 带参数的游标
declare
--定义游标
cursor emp_sal_cursor(dept_id number, sal number) is
select salary + 1000 sal, employee_id id
from employees
where department_id = dept_id and salary > sal;
--定义基数变量
temp number(4, 2);
begin
--处理游标的循环操作
for c in emp_sal_cursor(sal => 4000, dept_id => 80) loop
--判断员工的工资, 执行 update 操作
--dbms_output.put_line(c.id || ': ' || c.sal);
if c.sal <= 5000 then
temp := 0.05;
elsif c.sal <= 10000 then
temp := 0.03;
elsif c.sal <= 15000 then
temp := 0.02;
else
temp := 0.01;
end if;
dbms_output.put_line(c.sal || ': ' || c.id || ', ' || temp);
--update employees set salary = salary * (1 + temp) where employee_id = c.id;
end loop;
end;
17. 隐式游标: 更新指定员工 salary(涨工资 10),如果该员工没有找到,则打印”查无此人” 信息
begin
update employees set salary = salary + 10 where employee_id = 1005;
if sql%notfound then
dbms_output.put_line('查无此人!');
end if;
end;



