游标的使用

①游标概念

为了处理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 游标的使用的更多相关文章

  1. PL/SQL 游标 (实验七)

    PL/SQL 游标 emp.dept 目标表结构及数据 要求 基于部门表建立游标dept_cursor1,使用记录变量接收游标数据,输出部门表信息: 显示格式: 部 门 号: XXX 部门名称: XX ...

  2. PL/SQL 游标

    本随笔不是原创,只是学习笔记,用于加深记忆,原创地址PL/SQL --> 游标 一.游标的相关概念和特性 1.定义: 映射到结果集中的某一行的特定位置,类似与C语言中的指针.即通过游标方式定位到 ...

  3. Oracle数据库之PL/SQL游标

    1. 游标概念 字面意思是游动的光标,是指向上下文区域的句柄或指针. 在PL/SQL块中执行CRUD操作时,ORACLE会在内存中为其分配上下文区.用数据库语言来描述游标就是:映射在上下文区结果集中一 ...

  4. Oracle PL/SQL 游标

    在PL/SQL块中执行SELECT.INSERT.DELETE和UPDATE语句时,ORACLE会在内存中为其分配上下文区(Context Area),即缓冲区.游标是指向该区的一个指针,或是命名一个 ...

  5. PL/SQL游标详解

    刚打开游标的时候,是位于一个空行,要用fetch into 才能到第一行. 只是要注意用更新游标的时候,不能在游标期间commit. 否则会报ORA-01002: fetch out of seque ...

  6. C#(在WeBAPI)获取Oracle(在PL/SQL)游标类型的存储过程(用到了RefCursor)

    需求:WebAPI服务端,通过Oracle数据库的存储过程,获取数据. 在PL/SQL 建立存储过程:(先来最简单的,就是把整个表都查出来) create or replace procedure S ...

  7. Oracle PL/SQL游标

    游标的提出: SQL是面向集合的,其结果一般是集合量(多条记录),而PL/SQL的变量一本是标量,其一组变量异常一直只能存放一条记录.所以仅仅使用变量并不能完全满足SQL语句向应用程序输出数据的要求. ...

  8. pl/sql游标

    通过游标,我们可以取得返回结果集的任何一行记录,提高效率. 定义游标: type 游标名 is ref cursor 变量名 游标名 打开游标: open 游标变量 for select语句: 取出当 ...

  9. Oracle笔记 九、PL/SQL 游标的使用

    --演示隐式游标,系统自动声明,自动打开,自动使用并且自动关闭 begin update emp set sal = 1000; dbms_output.put_line('影响的行数:' || sq ...

随机推荐

  1. MySQL字符串函数、日期时间函数

    MySQL字符串函数.日期时间函数 一.常见字符串函数: 1.CHAR_LENGTH  获取长度(字符为单位) 2.FORMAT  格式化 3.INSERT  替换的方式插入 4.INSTR  获取位 ...

  2. OCA读书笔记(16) - 执行数据库恢复

    16. Performing Database Recovery 确定执行恢复的必要性访问不同接口(EM以及命令行)描述和使用可用选项,如RMAN和Data Recovery Advisor执行恢复- ...

  3. struts2文件上传限制大小问题

    struts2默认文件上传大小为2M,如需改动默认大小,解决方法例如以下: <struts> <constant name="struts.multipart.maxSiz ...

  4. 探索Oracle之数据库升级七 11gR2 to 12c 升级完毕后插入PDB

    探索Oracle之数据库升级七 11gR2 to 12c 升级完毕后插入PDB 前言:        从Oracle 12c開始,引入了容器数据库的概念,能够实现数据库插拔操作,例如以下图: 如今我们 ...

  5. UVA 10828 - Back to Kernighan-Ritchie(概率+高斯消元)

    UVA 10828 - Back to Kernighan-Ritchie 题目链接 题意:给图一个流程图,有结点的流程,每次进入下一个流程概率是均等的,有q次询问,求出每次询问结点的运行期望 思路: ...

  6. “>>”和“>>>” java

    “>>”算术右移运算符, 表示带符号右移,它使用最高位填充移位后左侧的空位.右移的结果为:每移一位,第一个操作数被2除一次,移动的次数由第二个操作数确定.按二进制形式把所有的数字向右移动对 ...

  7. Android5.0L下因sensorservice crash导致systemserver重新启动的第二种场景分析

    一.出问题的场景 1.Sensorservice线程正在处理compass sensor事件的过程中.检查了一次buffer的指针的有效性,并在稍后会传递到AKM获取数据的函数接口中使用 2.Sens ...

  8. 每天进步一点点——Linux磁盘管理LVM与RAID

    转载请注明出处:http://blog.csdn.net/cywosp/article/details/38965799 1. 传统磁盘管理问题 当分区大小不够用时无法扩展其大小,仅仅能通过加入硬盘. ...

  9. A Game of Thrones(6) - Catelyn

    Of all the rooms in Winterfell’s Great Keep, Catelyn’s bedchambers(['bedtʃeɪmbə]卧室,寝室) were the hott ...

  10. 福利 城市名的python list

    ["上海","北京","北京市","朝阳","朝阳区","海淀","元 ...