PL/SQL 游标的使用
游标的使用
①游标概念
为了处理SQL 语句,ORACLE 必须分配一片叫上下文( context area )的区域来处理所必需的信息,
当中包含要处理的行的数目。一个指向语句被分析以后的表示形式的指针以及查询的活动集(active set)。
游标是一个指向上下文的句柄( handle)或指针。
通过游标,PL/SQL能够控制上下文区和处理语句时上下文区会发生些什么事情
②显式游标处理
1.显式游标处理需四个PL/SQL步骤:
定义游标:就是定义一个游标名,以及与其相相应的SELECT 语句。
格式:
CURSOR cursor_name[(parameter[, parameter]…)] IS select_statement;
游标參数仅仅能为输入參数,其格式为:
parameter_name [IN] datatype [{:= | DEFAULT} expression]
在指定数据类型时,不能使用长度约束。如NUMBER(4)、CHAR(10) 等都是错误的。
打开游标:就是运行游标所相应的SELECT 语句。将其查询结果放入工作区。而且指针指向工作区的首部,标识游标结果集合。
假设游标查询语句中带有FOR UPDATE选项。OPEN 语句还将锁定数据库表中游标结果集合相应的数据行。
格式:
OPEN cursor_name[([parameter =>] value[, [parameter =>] value]…)];
在向游标传递參数时,能够使用与函数參数同样的传值方法。即位置表示法和名称表示法。PL/SQL 程序不能用OPEN 语句反复打开一个游标。
提取游标数据:就是检索结果集合中的数据行。放入指定的输出变量中。
格式:
FETCH cursor_name INTO {variable_list | record_variable };
对该记录进行处理。
继续处理。直到活动集合中没有记录。
关闭游标:当提取和处理完游标结果集合数据后,应及时关闭游标,以释放该游标所占用的系统资源。并使该游标的工作区变成无效,
不能再使用FETCH 语句取当中数据。关闭后的游标能够使用OPEN 语句又一次打开。
格式:
CLOSE cursor_name;
注:定义的游标不能有INTO 子句。
2.游标属性
%FOUND 布尔型属性。当近期一次读记录时成功返回,则值为TRUE。
%NOTFOUND 布尔型属性,与%FOUND相反;
%ISOPEN 布尔型属性。当游标已打开时返回TRUE;
%ROWCOUNT 数字型属性。返回已从游标中读取的记录数。
3.游标的FOR循环
PL/SQL语言提供了游标FOR循环语句。自己主动运行游标的OPEN、FETCH、CLOSE语句和循环语句的功能;当进入循环时,游标FOR循环语句自己主动打开游标。并提取第一行游标数据。当程序处理完当前所提取的数据而进入下一次循环时。游标FOR循环语句自己主动提取下一行数据供程序处理,当提取完结果集合中的全部数据行后结束循环,并自己主动关闭游标。
格式:
FOR index_variable IN cursor_name[value[, value]…] LOOP
--游标数据处理代码
END LOOP;
当中:
index_variable为游标FOR 循环语句隐含声明的索引变量,该变量为记录变量。其结构与游标查询语句返回的结构集合的结构同样。在程序中能够通过引用该索引记录变量元素来读取所提取的游标数据,
index_variable中各元素的名称与游标查询语句选择列表中所制定的列名同样。
假设在游标查询语句的选择列表中存在计算列,则必须为这些计算列指定别名后才干通过游标FOR 循环语句中的索引变量来訪问这些列数据。
注:不要在程序中对游标进行人工操作。不要在程序中定义用于控制FOR 循环的记录。
③处理隐式游标
显式游标主要是用于对查询语句的处理,尤其是在查询结果为多条记录的情况下;
而对于非查询语句,如改动、删除操作,则由ORACLE 系统自己主动地为这些操作设置游标并创建其工作区,
这些由系统隐含创建的游标称为隐式游标。隐式游标的名字为SQL,这是由ORACLE 系统定义的。
对于隐式游标的操作,
如定义、打开、取值及关闭操作,都由ORACLE 系统自己主动地完毕。无需用户进行处理。用户仅仅能通过隐式游标的相关属性。来完毕对应的操作。
在隐式游标的工作区中,所存放的数据是与用户自己定义的显示游标无关的、最新处理的一条SQL 语句所包括的数据。
格式调用为:SQL%
隐式游标属性
SQL%FOUND 布尔型属性,当近期一次读记录时成功返回,则值为TRUE;
SQL%NOTFOUND 布尔型属性,与%FOUND相反。
SQL %ROWCOUNT 数字型属性, 返回已从游标中读取得记录数。
SQL %ISOPEN 布尔型属性, 取值总是FALSE。SQL命令运行完成马上关闭隐式游标。
④关于NO_DATA_FOUND 和%NOTFOUND的差别
SELECT … INTO 语句触发NO_DATA_FOUND。(EXCEPTION when NO_DATA_FOUND then ......)
当一个显式游标的WHERE子句未找到时触发%NOTFOUND。
当UPDATE或DELETE 语句的WHERE 子句未找到时触发SQL%NOTFOUND。
在提取循环中要用%NOTFOUND 或%FOUND 来确定循环的退出条件,不要用NO_DATA_FOUND.
⑤游标改动和删除操作
游标改动和删除操作是指在游标定位下,改动或删除表中指定的数据行。
这时。要求游标查询语句中必须使用FOR UPDATE选项。以便在打开游标时锁定游标结果集合在表中相应数据行的全部列和部分列。
为了对正在处理(查询)的行不被另外的用户修改。ORACLE 提供一个FOR UPDATE 子句来对所选择的行进行锁住。
该需求迫使ORACLE锁定游标结果集合的行。能够防止其它事务处理更新或删除同样的行。直到您的事务处理提交或回退为止。
语法:
SELECT . . . FROM … FOR UPDATE [OF column[, column]…] [NOWAIT]
假设还有一个会话已对活动集中的行加了锁。那么SELECT FOR UPDATE操作一直等待到其他的会话释放这些锁后才继续自己的操作。
对于这样的情况,当加上NOWAIT子句时,假设这些行真的被还有一个会话锁定,则OPEN马上返回并给出:
ORA-0054 :resource busy and acquire with nowait specified.
假设使用FOR UPDATE 声明游标,则可在DELETE和UPDATE 语句中使用WHERE CURRENT OF cursor_name子句。
改动或删除游标结果集合当前行相应的数据库表中的数据行
⑥例:使用游标
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;
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;
3.打印出 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;
4. 利用游标, 调整公司中员工的工资:
工资范围 调整基数
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)))
5. 利用游标 for 循环完毕 4.
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;
6*. 带參数的游标
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;
7. 隐式游标: 更新指定员工 salary(涨工资 10),假设该员工没有找到,则打印”查无此人” 信息
begin
update employees set salary = salary + 10 where employee_id = 1005;
if sql%notfound then
dbms_output.put_line('查无此人!');
end if;
end;
PL/SQL 游标的使用的更多相关文章
- PL/SQL 游标 (实验七)
PL/SQL 游标 emp.dept 目标表结构及数据 要求 基于部门表建立游标dept_cursor1,使用记录变量接收游标数据,输出部门表信息: 显示格式: 部 门 号: XXX 部门名称: XX ...
- PL/SQL 游标
本随笔不是原创,只是学习笔记,用于加深记忆,原创地址PL/SQL --> 游标 一.游标的相关概念和特性 1.定义: 映射到结果集中的某一行的特定位置,类似与C语言中的指针.即通过游标方式定位到 ...
- Oracle数据库之PL/SQL游标
1. 游标概念 字面意思是游动的光标,是指向上下文区域的句柄或指针. 在PL/SQL块中执行CRUD操作时,ORACLE会在内存中为其分配上下文区.用数据库语言来描述游标就是:映射在上下文区结果集中一 ...
- Oracle PL/SQL 游标
在PL/SQL块中执行SELECT.INSERT.DELETE和UPDATE语句时,ORACLE会在内存中为其分配上下文区(Context Area),即缓冲区.游标是指向该区的一个指针,或是命名一个 ...
- PL/SQL游标详解
刚打开游标的时候,是位于一个空行,要用fetch into 才能到第一行. 只是要注意用更新游标的时候,不能在游标期间commit. 否则会报ORA-01002: fetch out of seque ...
- C#(在WeBAPI)获取Oracle(在PL/SQL)游标类型的存储过程(用到了RefCursor)
需求:WebAPI服务端,通过Oracle数据库的存储过程,获取数据. 在PL/SQL 建立存储过程:(先来最简单的,就是把整个表都查出来) create or replace procedure S ...
- Oracle PL/SQL游标
游标的提出: SQL是面向集合的,其结果一般是集合量(多条记录),而PL/SQL的变量一本是标量,其一组变量异常一直只能存放一条记录.所以仅仅使用变量并不能完全满足SQL语句向应用程序输出数据的要求. ...
- pl/sql游标
通过游标,我们可以取得返回结果集的任何一行记录,提高效率. 定义游标: type 游标名 is ref cursor 变量名 游标名 打开游标: open 游标变量 for select语句: 取出当 ...
- Oracle笔记 九、PL/SQL 游标的使用
--演示隐式游标,系统自动声明,自动打开,自动使用并且自动关闭 begin update emp set sal = 1000; dbms_output.put_line('影响的行数:' || sq ...
随机推荐
- ubuntu12.04安装搜狗输入法配置,安装packettracer字体设置,软件推荐
装上系统,后的各种配置,各种出错之后的解决. 一.安装搜狗输入法 如果系统以前安装了先卸载: sudo apt-get remove fcitx* #删除配置文件 sudo apt-get purge ...
- 并发编程实践五:ReentrantLock
ReentrantLock是一个可重入的相互排斥锁,实现了接口Lock,和synchronized相比,它们提供了同样的功能.但ReentrantLock使用更灵活.功能更强大,也更复杂.这篇文章将为 ...
- OpenCV HaarTraining代码解析(二)cvCreateMTStumpClassifier(建立决策树)
HaarTraining关键的部分是建立基分类器classifier,OpenCV中所採用的是CART(决策树的一种):通过调用cvCreateMTStumpClassifier来完毕. 这里我讨论利 ...
- 《Python学习手册》读书笔记
之前为了编写一个svm分词的程序而简单学了下Python,觉得Python很好用,想深入并系统学习一下,了解一些机制,因此开始阅读<Python学习手册(第三版)>.如果只是想快速入门,我 ...
- JAVA进阶----主线程等待子线程各种方案比较(转)
创建线程以及管理线程池基本理解 参考原文链接:http://www.oschina.net/question/12_11255?sort=time 一.创建一个简单的java线程 在 Java 语言中 ...
- HDU 4611 Balls Rearrangement (数学-思维逻辑题)
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4611 题意:给你一个N.A.B,要你求 AC代码: #include <iostream> ...
- 【VB/.NET】Converting VB6 to VB.NET 【Part II】【之四】
第四部分 原文 DLLs, DAO, RDO, ADO, and AD.NET; the History of VB DBs In the early versions of VB, there we ...
- VSTO 学习笔记(十二)自定义公式与Ribbon
原文:VSTO 学习笔记(十二)自定义公式与Ribbon 这几天工作中在开发一个Excel插件,包含自定义公式,根据条件从数据库中查询结果.这次我们来做一个简单的测试,达到类似的目的. 即在Excel ...
- 深入java并发Lock一
java有像syncronized这种内置锁,但为什么还须要lock这种外置锁? 性能并非选择syncronized或者lock的原因,jdk6中syncronized的性能已经与lock相差不大. ...
- C#的百度地图开发(三)依据坐标获取位置、商圈及周边信息
原文:C#的百度地图开发(三)依据坐标获取位置.商圈及周边信息 我们得到了百度坐标,现在依据这一坐标来获取相应的信息.下面是相应的代码 public class BaiduMap { /// < ...