简介
PL/SQL 是用游标来管理 SQL 的 SELECT 语句的 。游标是为了处理这些语句而分配的一大块内存。 它提供了对一个结果集进行逐行处理的能力 , 可看作是一种特殊的指针 . 它与某个查询结果集相关联 , 可以指向结果集的任意位置 , 以便对指定位置的数据进行处理 。使用它可以在查询数据的同时对数据进行处理。
游标类型
隐式游标
1、使用DML语句(增删改)和单行查询语句(赋值)时自动创建隐式游标
2、隐式游标自动声明、打开和关闭,其名为 SQL
3、通过检查隐式游标的属性可以获得最近执行的DML 语句的信息
4、隐式游标的属性:
(1)、%FOUND:SQL 语句影响了一行或多行时为 TRUE。只有在 DML 语句影响一行或多行时,才返回 True。
BEGIN
UPDATE t_student SET sname = '张三丰'
WHERE sid= ‘10001';
IF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('表已更新');
END IF;
END;
(2)、%NOTFOUND : SQL 语句没有影响任何行时为TRUE。如果 DML 语句不影响任何行,则返回 True。
BEGIN
UPDATE emp SET deptno=20 WHERE empno=7839;
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('编号未找到。');
ELSE
DBMS_OUTPUT.PUT_LINE(‘数据已更新');
END IF;
END;
(3)、%ROWCOUNT : SQL 语句影响的行数,没有影响任何行,返回0,在执行任何DML语句前,值为NULL。
如果没有与SELECT INTO语句中的条件匹配的行,将引发NO_DATA_FOUND异常。
DECLARE
v_no emp.empno%type;
v_name emp.ename%type;
BEGIN
v_no:= &职员编号;
SELECT ename INTO v_name
FROM emp WHERE empno=v_no;
IF SQL%ROWCOUNT>0 THEN
DBMS_OUTPUT.PUT_LINE('职员的姓名是 '||v_name);
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('职员未找到');
END;
(4)、%ISOPEN : 游标是否打开,隐式游标始终为FALSE(隐式游标执行时打开,结束时立即关闭)
显示游标
1、显式游标是由PL/SQL程序员定义和命名的游标
2、显式游标用于多行查询
3、显式游标需要在PL/SQL块的声明部分声明,在执行部分或异常处理部分打开,取完数据后将其关闭
声明游标
CURSOR cursor_name IS select_statement;
打开游标(将数据存储到游标)
OPEN cursor_name;
根据游标提取数据
FETCH cursor_name INTO variable[,variable,……]
关闭游标
CLOSE cursor_name;
使用游标循环打印所有学生姓名
Declare
v_name t_student.sname%type;
Cursor cur_stu Is select sname from t_student; --声明游标
begin
Open cur_stu; --打开游标
Loop
Fetch cur_stu Into v_name; --提取游标指向数据给变量
Exit When cur_stu%NotFound;
dbms_output.put_line('学生姓名:'||v_name);
End Loop;
Close cur_stu; --关闭游标
end;
使用游标循环打印所有员工编号,员工姓名及工资
declare
CURSOR c_emp IS
SELECT empno,ename,sal FROM emp ORDER BY sal;
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
v_sal emp.sal%TYPE;
begin
Open c_emp;
Loop
Fetch c_emp Into v_empno,v_ename,v_sal;
Exit When c_emp%NotFound;
dbms_output.put_line(v_empno||’ ’||v_ename||’ ’||v_sal);
End Loop;
Close c_emp;
end;
使用游标循环打印所有员工编号,员工姓名及工资
declare
CURSOR c_emp IS
SELECT empno,ename,sal FROM emp ORDER BY sal;
v_empno emp.empno%TYPE;
v_ename emp.ename%TYPE;
v_sal emp.sal%TYPE;
begin
Open c_emp;
Loop
Fetch c_emp Into v_empno,v_ename,v_sal;
Exit When c_emp%NotFound;
dbms_output.put_line(v_empno||’ ’||v_ename||’ ’||v_sal);
End Loop;
Close c_emp;
end;
使用游标行循环打印员工编号,姓名,工资
declare
CURSOR c_emp IS
SELECT empno,ename,sal FROM emp ORDER BY sal;
r_emp c_emp%ROWTYPE;--游标行
begin
Open c_emp;
Loop
Fetch c_emp Into r_emp;
Exit When c_emp%NotFound;
dbms_output.put_line(r_emp.empno||’ ’||r_emp.ename||’ ’||r_emp.sal);
End Loop;
Close c_emp;
end;
使用游标行循环打印员工编号,姓名,工资
declare
CURSOR c_emp IS
SELECT empno,ename,sal FROM emp ORDER BY sal;
r_emp c_emp%ROWTYPE;--游标行
begin
Open c_emp;
Loop
Fetch c_emp Into r_emp;
Exit When c_emp%NotFound;
dbms_output.put_line(r_emp.empno||’ ’||r_emp.ename||’ ’||r_emp.sal);
End Loop;
Close c_emp;
end;
带参数的显示游标
声明显式游标时可以带参数以提高灵活性
declare
v_deptno emp.deptno%type; --部门编号变量
cursor c_emp(dno number) is
select empno,ename,sal from emp where deptno=dno;
r_emp c_emp%rowtype; --游标行
begin
v_deptno:='&部门编号'; --输入参数值
Open c_emp(v_deptno);--传递参数
Loop
Fetch c_emp Into r_emp;
Exit When c_emp%NotFound;
dbms_output.put_line(r_emp.empno||' '||r_emp.ename||' '||r_emp.sal);
End Loop;
Close c_emp;
end;
循环游标
1、循环游标用于简化游标处理代码
2、当用户需要从游标中提取多行记录时使用
3、循环游标的语法如下:
FOR record_name IN (corsor_name[(parameter[,parameter])...])
| (query_difinition)
LOOP
statements
END LOOP;
DECLARE
CURSOR c_emp IS
SELECT empno,ename,sal FROM emp ORDER BY sal;
BEGIN
FOR r_emp IN c_emp
Loop -- r_emp代表游标行
dbms_output.put_line(r_emp.empno||’’||r_emp.ename||’’||r_emp.sal);
End Loop;
END;
用于FOR循环的游标声明按照正常声明方式声明;不需要显式的打开,取数据,测试数据存在,关闭等;带参数时,in 游标名(参数)。
允许使用游标删除或更新活动集中的行,声明游标时必须使用 SELECT … FOR UPDATE语句
CURSOR <cursor_name> IS
select_statement FOR UPDATE [OF columns];
更新数据格式
UPDATE <table_name>
SET column_name = column_value
WHERE CURRENT OF <cursor_name>
删除数据格式
DELETE FROM <table_name>
WHERE CURRENT OF <cursor_name>
DECLARE
CURSOR c_emp IS
SELECT empno,ename,sal FROM emp ORDER BY sal DESC FOR UPDATE;
v_increase NUMBER:=0; --增加的工资数
v_new_sal NUMBER; --新工资
BEGIN
FOR r_emp IN c_emp LOOP
v_new_sal:=r_emp.sal+v_increase;
UPDATE emp SET sal=v_new_sal WHERE CURRENT OF c_emp;
DBMS_OUTPUT.PUT_LINE(r_emp.empno||' '||r_emp.ename||
' old salary ='||r_emp.sal||' new salary='||v_new_sal);
v_increase:=v_increase+100;
END LOOP;
END;
REF 游标
REF 游标和游标变量用于处理运行时动态执行的 SQL 查询,创建游标变量需要两个步骤:
1、声明 REF 游标类型
TYPE <ref_cursor_name> IS REF CURSOR
[RETURN <return_type>];
2、声明 REF 游标类型的变量
ref_variable ref_cursor_name;
打开游标变量的语法
OPEN ref_variable FOR select_statement;
declare
type refcur is ref cursor;
ref_cur refcur;
r_emp emp%rowtype;
r_dept dept%rowtype;
selection varchar2(1):=upper(substr('&input',1,1));
begin
if selection='E' then
open ref_cur for select * from emp;
dbms_output.put_line('=========员工信息=========');
loop
fetch ref_cur into r_emp;
exit when ref_cur%notfound;
dbms_output.put_line(r_emp.empno||' '||r_emp.ename||' '||r_emp.sal);
end loop;
elsif selection='D' then
open ref_cur for select * from dept;
dbms_output.put_line('=========部门信息=========');
loop
fetch ref_cur into r_dept ;
exit when ref_cur%notfound;
dbms_output.put_line(r_dept.deptno||' '||r_dept.dname||' ');
end loop;
else
dbms_output.put_line('请输入员工信息(E)或 部门信息(D)');
return;
end if;
close ref_cur;
end;
游标变量的优点和限制
1、游标变量的功能强大,可以简化数据处理。
2、游标变量的优点有:
(1)、可从不同的 SELECT 语句中提取结果集
(2)、可以作为过程的参数进行传递
(3)、可以引用游标的所有属性
(4)、可以进行赋值运算
3、使用游标变量的限制:
(1)、不能在程序包中声明游标变量
(2)、FOR UPDATE子句不能与游标变量一起使用
(3)、不能使用比较运算符