游标的使用

①游标概念

为了处理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. linux下修改hostid

    linux下修改hostid 网上有很多版本,总结了这几点. 1> 一个以16进制显示的int字符串: 2> 配置文件: /etc/hostid; 如果有值,输出, 结束. 3> 从 ...

  2. TCP连接的建立(二)

    被动打开 SYN cookies TCP协议开辟了一个比較大的内存空间请求连接队列来存储连接请求块,当SYN请求不断添加,请求连接数目到达上限时,会致使系统丢弃SYN连接请求.SYN cookies技 ...

  3. 部署到Linux使用VS Code 开发.NET Core 应用程序

    使用VS Code 开发.NET Core 应用程序 部署到Linux 跨平台 使用VS Code 开发.NET Core 应用程序 部署到Linux 跨平台. 前面讲解了VSCode开发调试 .NE ...

  4. LINUX编程学习笔记(十三) 遍历目录的两种方法

    1 默认情况下  实际用户和有效用户是一样的 实际用户:执行用户   有效用户:权限用户 getuid()  实际用户 geteuid() 有效用户 chmod u+s 之后 ,其他人执行文件时,实际 ...

  5. UVa 10286 - Trouble with a Pentagon

    题目:如图在正五边形中画一个正方形,一直正五边形边长,求正方形边长. 分析:计算几何,解析几何.求出边长的比例关系带入求解就可以. 设正五边形边长为1,在顶点建立直角坐标系,则左上角坐标为:B(-co ...

  6. POJ 2318 TOYS(计算几何)

    跨产品的利用率推断点线段向左或向右,然后你可以2分钟 代码: #include <cstdio> #include <cstring> #include <algorit ...

  7. HDU 4022 Bombing (map + multiset)

    题意: 在x,y坐标范围为10 ^ -9 ~~ 10 ^ 9的坐标轴之中,有 10W个点(注意有些点可能在同一坐标上),然后有10W个询问,处理询问按照输入顺序处理,对于每个询问a,b    a == ...

  8. Androidclient和server端数据交互的第一种方法

    网上有非常多样例来演示Android客户端和server端数据怎样实现交互只是这些样例大多比較繁杂,对于刚開始学习的人来说这是不利的.如今介绍几种代码简单.逻辑清晰的交互样例,本篇博客介绍第一种: 一 ...

  9. 服务器编程入门(7)I/O复用

    问题聚焦:     前篇提到了I/O处理单元的四种I/O模型.     本篇详细介绍实现这些I/O模型所用到的相关技术.     核心思想:I/O复用 使用情景: 客户端程序要同时处理多个socket ...

  10. SpringMVC @ResponseBody 415错误处理

    在查看下面部分内容之前,请先检查你的请求蚕食是否正确,如果全部正确,请继续往下看 刚开始用SpringMVC, 页面要使用jQuery的ajax请求Controller. 但总是失败,主要表现为以下两 ...