oracle游标

 游标(cursor )是一个私有的SQL工作区域,是一个指向上下文区的句柄或指针,位于内存中的 "临时表"

 游标是SQL的一个内存工作区,由系统或用户以变量的形式定义。游标的作用就是用于临时存储从数据库中提取的数据块。在某些情况下,需要把数据从存放在磁盘的表中调到计算机内存中进行处理,最后将处理结果显示出来或最终写回数据库。这样数据处理的速度才会提高,否则频繁的磁盘数据交换会降低效率

游标用来管理从数据源返回的数据的属性(结果集)。这些属性包括并发管理、在结果集中的位置、返回的行数,以及是否能够在结果集中向前和/或向后移动(可滚动性)。

游标跟踪结果集中的位置,并允许对结果集逐行执行多个操作,在这个过程中可能返回至原始表,也可能不返回至原始表

 

原理游标是从数据表中提取出来的数据,以 临时表 的形式存放到 内存中,在游标中有一个 数据指针, 在初始状态下指向的是首记录,利用 fetch 语句可以移动该指针,从而对游标中的数据进行各种操作,然后将操作结果写回到数据库中。
作用

1、用来查询数据库,获取记录集合(结果集)的指针,可以让开发者基于当前的结果集位置检索一行或连续的几行在每     条结果集上作操作,以编 程的方式访问数据。
2、用 ‘牺牲内存’ 来提升 SQL 执行效率,适用于 大数据处理

3.在结果集的当前位置修改行中的数据,对其他用户所做的数据更改定义不同的敏感性级别。

 

程序语言是面向记录的,一组变量一次只能存放一个变量或者一条记录,无法直接接收数据库中的查询结果集引入游标就解决了这个问题

标的类型

REF 游标用于处理运行时才能确定的动态 SQL 查询的结果

隐式游标不易被用户和程序员察觉和意识到,实际上Oracle服务器使用隐式游标来解析和执行我们提交的SQL 语句;而显式游标是程序员在程序中显式声明的;通常我们说的游标均指显式游标

隐式

游标

在 PL/SQL 中使用 DML 和 select into时,会自动创建隐式游标,隐式游标自动声明、打开和关闭(无法手动查看),其名为 SQL,通过检查隐式游标的属性可以获得 最近执行的 DML 和 select into 语句的信息

DML操作和单行SELECT语句会使用隐式游标,它们是: 
* 插入操作:INSERT。 
* 更新操作:UPDATE。 
* 删除操作:DELETE。 
* 单行查询操作:SELECT ... INTO ...。

当系统使用一个隐式游标时,可以通过隐式游标的属性来了解操作的状态和结果,进而控制程序的流程。隐式游标可以使用名字SQL来访问,但要注意,通过SQL游标名总是只能访问前一个DML操作或单行SELECT操作的游标属性。所以通常在刚刚执行完操作之后,立即使用SQL游标名来访问属性

%FOUND语句影响了一行或多行时为 TRUE,前一个 fetch 语句是否有值,true:有,false:没有
%NOTFOUND

语句没有影响任何行时为TRUE,与上述相反,常被用于 退出循环,true:有,false:没有, null : 空。注意哦,只有 为 true 时,才退出(当 第一次 fetch 为 null 时,不会退出!)

EXIT WHEN SQL%NOTFOUND OR SQL%NOTFOUND IS NULL;

%ROWCOUNT语句影响的行数,当前成功执行的数据行数(非总记录数
%ISOPEN游标是否打开,始终为FALSE
SQL> DECLARE
  	v_TOYID TOYS.ID%type := '&TOYID';
  	v_TOYNAME TOYS.NAME%Type := '&TOYNAME';
     BEGIN
  	UPDATE TOYS SET NAME = v_TOYNAME
  	WHERE toyid=v_TOYID;
  	IF SQL%NOTFOUND THEN
    		DBMS_OUTPUT.PUT_LINE('编号未找到。');
 	ELSE
		DBMS_OUTPUT.PUT_LINE(‘表已更新');
	END IF;
     END;
DECLARE
  v_RoomData   rooms%ROWTYPE;
BEGIN
  SELECT *
    INTO v_RoomData FROM rooms WHERE room_id = -1;
  IF SQL%NOTFOUND THEN 
/*注意,这里不执行,以上自动引发select into预定义异常*/
    INSERT INTO temp_table (char_col) VALUES 
('Not found!');
  END IF;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
/*注意,这是真正执行的*/
    INSERT INTO temp_table (char_col)
      VALUES ('Not found, exception handler');
END;
declare
  2    v_rows number;
  3  begin
  4    update emp
  5    set comm=1000
  6    where deptno=30;
  7   v_rows:=SQL%ROWCOUNT;
  8   dbms_output.put_line('给部门30的' 
|| v_rows || '个雇员每人加了1000元奖金');
  9  end;

 

显式游标

显式游标在 PL/SQL 块的声明部分定义查询,该查询可以返回多行

1、一行一行的处理返回的数据。

2、保持当前处理行的一个跟踪,像一个指针一样指示当前的处理的记录。

3、允许程序员在PLSQL块中人为的控制游标的开启、关闭、上下移动

声明游标

划分存储区域,注意此时并没有执行Select 语句

 

CURSOR 游标名[(参数1 数据类型[,参数2 数据类型...])] 
IS SELECT语句; 
参数是可选部分,所定义的参数可以出现在SELECT语句的WHERE子句中。如果定义了参数,则必须在打开游标时传递相应的实际参数。 
SELECT语句是对表或视图的查询语句,甚至也可以是联合查询。可以带WHERE条件、ORDER BY或GROUP BY等子句,但不能使用INTO子句。在SELECT语句中可以使用在定义游标之前定义的变量。 

打开游标

执行Select 语句,获得结果集存储到游标中,此时游标指向结果集头, 而不是第一条记录

在可执行部分,按以下格式打开游标: 
OPEN 游标名[(实际参数1[,实际参数2...])]; 
打开游标时,SELECT语句的查询结果就被传送到了游标工作区。

结果集控制

移动游标取一条记录

在可执行部分,按以下格式将游标工作区中的数据取到变量中。提取操作必须在打开游标之后进行。 
FETCH 游标名 INTO 变量名1[,变量名2...]; 
或 
FETCH 游标名 INTO 记录变量; 
游标打开后有一个指针指向数据区,FETCH语句一次返回指针所指的一行数据,要返回多行需重复执行,可以使用循环语句来实现。控制循环可以通过判断游标的属性来进行。 
下面对这两种格式进行说明: 
第一种格式中的变量名是用来从游标中接收数据的变量,需要事先定义。变量的个数和类型应与SELECT语句中的字段变量的个数和类型一致。 
第二种格式一次将一行数据取到记录变量中,需要使用%ROWTYPE事先定义记录变量,这种形式使用起来比较方便,不必分别定义和使用多个变量。 
定义记录变量的方法如下: 
变量名 表名|游标名%ROWTYPE; 
其中的表必须存在,游标名也必须先定义。

关闭游标

显式游标打开后,必须显式地关闭。游标一旦关闭,游标占用的资源就被释放,游标变成无效,必须重新打开才能使用。

SQL>DECLARE
        my_toy_price toys.toyprice%TYPE;				  
       声明游标
        CURSOR toy_cur IS
	       SELECT toyprice FROM toys
	       WHERE toyprice<250;
    BEGIN
	     OPEN toy_cur;  
	     LOOP
  	       FETCH toy_cur INTO my_toy_price;
  	       EXIT WHEN toy_cur%NOTFOUND;
  	       DBMS_OUTPUT.PUT_LINE 
          ('TOYPRICE=:玩具单价=:'||my_toy_price);
	     END LOOP;
	     CLOSE toy_cur;
   END;

带参数的

DECLARE
		desig    VARCHAR2(20);
		emp_code VARCHAR2(5);
		empnm    VARCHAR2(20);
		CURSOR emp_cur(desigparam VARCHAR2) IS
		 SELECT empno, ename FROM employee
		 WHERE designation=desig;
     BEGIN
		desig:= '&desig';
		OPEN emp_cur(desig);
		LOOP
			FETCH emp_cur INTO emp_code,empnm;
			EXIT WHEN emp_cur%NOTFOUND;
			DBMS_OUTPUT.PUT_LINE(emp_code||' '||empnm);
  		END LOOP;
		CLOSE emp_cur;
     END

 允许使用游标删除或更新活动集中的行
声明游标时必须使用 SELECT … FOR UPDATE语句

所有返回集中的数据行都将处于行级(ROW-LEVEL)独占式锁定,其他对象只能查询这些数据行,

  不能进行UPDATE、DELETE或SELECT...FOR UPDATE操作。

   在多表查询中,使用OF子句来锁定特定的表,如果忽略了OF子句,那么所有表中选择的数据行都将被锁定。

   如果这些数据行已经被其他会话锁定,那么正常情况下ORACLE将等待,直到数据行解锁

SQL> SET SERVEROUTPUT ON
SQL> DECLARE
  new_price NUMBER;
  CURSOR cur_toy IS
    SELECT toyprice FROM toys WHERE toyprice<100
    FOR UPDATE OF toyprice;
BEGIN
  OPEN cur_toy;
  LOOP
    FETCH cur_toy INTO new_price;
    EXIT WHEN cur_toy%NOTFOUND;
    UPDATE toys
    SET toyprice = 1.1*new_price
    WHERE CURRENT OF cur_toy;
  END LOOP;
  CLOSE cur_toy;
  COMMIT;
END;
declare
  2   cursor mycur(dept_no integer) is
  3   select * from dept
  4   where deptno>dept_no for update;
  5  begin
  6    for myreco in mycur(50) loop
  7     delete from dept
  8      where current of mycur;
  9    end loop;
 10  end;

循环游标

declare
  2   cursor c_dept is
  3   select deptno, dname from dept order by deptno;
  4   cursor c_emp(p_dept varchar2) is
  5    select ename,sal from emp where deptno=p_dept order by ename;
  6    v_salary emp.sal%type;
  7  begin
  8     for r_dept in c_dept loop
  9       dbms_output.put_line('Department:' || r_dept.deptno
           ||'-'||r_dept.dname);
 10     v_salary:=0;
 11     for r_emp in c_emp(r_dept.deptno) loop
 12      dbms_output.put_line('Name:'|| r_emp.ename||
           ' salary='||r_emp.sal);
 13       v_salary:=v_salary+r_emp.sal;
 14      end loop;
 15      dbms_output.put_line('total salary for dept:'
           || v_salary);
 16     end loop;
 17* end;

 

动态SELECT

Oracle支持动态SELECT语句和动态游标,动态的方法大大扩展了程序设计的能力。 
对于查询结果为一行的SELECT语句,可以用动态生成查询语句字符串的方法,在程序执行阶段临时地生成并执行,语法是: 
execute immediate 查询语句字符串 into 变量1[,变量2...]; 

SET SERVEROUTPUT ON   
        DECLARE   
        str varchar2(100);  
        v_ename varchar2(10);  
        begin  
        str:='select ename from scott.emp where empno=7788';  
        execute immediate str into v_ename;   
        dbms_output.put_line(v_ename);  
        END;   

 

REF

游标

在变量声明部分定义的游标是静态的,不能在程序运行过程中修改。虽然可以通过参数传递来取得不同的数据,但还是有很大的局限性。通过采用动态游标,可以在程序运行阶段随时生成一个查询语句作为游标。要使用动态游标需要先定义一个游标类型,然后声明一个游标变量,游标对应的查询语句可以在程序的执行过程中动态地说明。

 

REF 游标和游标变量用于处理运行时动态执行的 SQL 查询
创建游标变量需要两个步骤:
声明 REF 游标类型
声明 REF 游标类型的变量

TYPE <ref_cursor_name> IS REF CURSOR
[RETURN <return_type>];

声明强类型的 REF 游标

1、for 后是 SQL语句(而不能是 字符串)
2、cur… 必须和 return 的 类型完全一致
3、无法使用 绑定变量

TYPE my_curtype IS REF CURSOR
  RETURN stud_det%ROWTYPE;
order_cur my_curtype; 

声明弱类型的 REF 游标,系统类型 SYS_REFCURSOR

TYPE my_ctype IS REF CURSOR;
stud_cur my_ctype;
declare
  2    type cursor_type  is ref cursor;
  3    stu_cursor cursor_type;
  4    v_stu 学生表%rowtype;
  5  begin
  6    open stu_cursor for
  7      select * from 学生表 where 性别='男';
  8    loop
  9      fetch  stu_cursor into v_stu;
 10      exit when stu_cursor%notfound;
 11     dbms_output.put_line(v_stu.学号 ||' '||v_stu.姓名||' '
         ||v_stu.性别||' '||v_stu.年龄);
 12    end loop;
 13   close stu_cursor;
 14  end;
declare
  2  type emp_type is ref cursor;
  3  cur emp_type;
  4  name varchar2(20);
  5  salary number(7,2);
  6  begin
  7    open cur for 'select ename,sal from emp where job=:1'
  8    using 'SALESMAN';
  9   loop
 10     fetch cur into name,salary;
 11     exit when cur%notfound;
 12    dbms_output.put_line(name||':'||salary);
 13   end loop;
 14   close cur;
 15  end;
 declare
  2   type empcurtyp is ref cursor;
  3   type idlist is table of emp.empno%type;
  4   type namelist is table of emp.ename%type;
  5   type sallist is table of emp.sal%type;
  6   emp_cv empcurtyp;
  7   ids idlist;
  8   names namelist;  sals sallist;
  9   row_cn number;
 10  begin
 11    open emp_cv for select empno,ename,sal from emp;
 12    fetch emp_cv bulk collect into ids,names,sals;
 13   close emp_cv;
 14   for i in ids.first.. ids.last loop
 15     dbms_output.put_line(ids(i)||' '||names(i)||' '||sals(i));
 16   end loop;
 17* end;

 

游标变量的优点和限制

游标变量的功能强大,可以简化数据处理。
游标变量的优点有:
可从不同的 SELECT 语句中提取结果集
可以作为过程的参数进行传递
可以引用游标的所有属性
可以进行赋值运算
使用游标变量的限制:
不能在程序包中声明游标变量
FOR UPDATE子句不能与游标变量一起使用
不能使用比较运算符

DECLARE
   v_sql VARCHAR(2000);
   v_b1 NUMBER(3) := 3;
   TYPE record_stu IS RECORD(
      v_id system.stu.s_id%TYPE,
      v_xm system.stu.s_xm%TYPE);
   TYPE table_stu IS TABLE OF record_stu;
   v_stu table_stu;
   cur_stu SYS_REFCURSOR;
BEGIN
   v_sql := 'SELECT t.s_id, t.s_xm FROM stu t WHERE t.s_id <= :b1';

   OPEN cur_stu FOR v_sql
      USING v_b1; -- 绑定变量 : 大数据处理常用优化手段

   LOOP
      FETCH cur_stu BULK COLLECT
         INTO v_stu LIMIT 1; -- 数据量太少,仅当前测试使用哦,实际开发 建议 500 左右
      EXIT WHEN v_stu.count = 0;
   
      FOR i IN v_stu.first .. v_stu.last LOOP
         dbms_output.put_line('序号:' || v_stu(i).v_id || ' , ' || '姓名:' || v_stu(i).v_xm);
      END LOOP;
   
   END LOOP;

   CLOSE cur_stu;

EXCEPTION
   WHEN OTHERS THEN
      dbms_output.put_line(SQLCODE || ' : ' || SQLERRM);
      dbms_output.put_line(dbms_utility.format_error_backtrace);
END;

 

%type、%rowtype、record
  • %type:单条 记录类型自动匹配
  • %rowtype:所有 记录类型自动匹配
  • record:部分 记录类型自动匹配,该变量类型允许用户在代码中使用“表”,以便存储多个行数据。记录表类型是对记录类型的扩展,可以处理多个记录或多行数据
集合操作

在 Oracle 中集合中,若想扩充大小有两种方法
方式1:(手动)集合.extend(一次只申请一个空间长度)
方式2:(自动)Type <Type_name> IS TABLE OF <data_type> index by ..
Oracle 下标定义和其他语言有些区别
下标从 1 开始算,而不是 0 哦。

varry 一维数组(设置长度)

type 数组名 is varray(size) of 元素类型 [not null];

size : 数组最大长度,必填项。

DECLARE
   TYPE varry IS VARRAY(4) OF VARCHAR2(30); -- 最大长度是 4
   v_varry varry;
BEGIN
   -- 初始化 3 个下标, 也就只能写 3 个长度,即使定义的 有 4 个长度
   v_varry  := varry('a', 'b', 'c'); -- 构造方法 进行初始化

   FOR i IN v_varry.first .. v_varry.last LOOP
      dbms_output.put_line(v_varry (i));
   END LOOP;

END;
/

table 多维数组

type table_name is table of element_type[not null]
[index by [binary_integer|pls_integer]];

index by : 创建一个主键索引,以便引用记录表变量中的特定行.
-- 下列参数下标自增(无需 显示初始化:extend)
binary_integer :  由 Oracle来 执行,不会出现溢出,但是执行速度较慢,
                  因为它是由 Oracle 模拟执行。
pls_integer    :  由硬件即直接由 CPU 来运算,因而会出现溢出,但其执行速度
                  较前者快许多,数据范围:参考 ‘Oracle 官方解释中的红色字体’

 存储单行多列

(效果同 varry 一维数组)

这个和 VARRAY 类似。但是赋值方式稍微有点不同,不能使用同名的 构造函数 进行赋值。
有个细节:去掉 index by .. 后,是可以使用 构造函数

DECLARE
   -- 此例中  INDEX BY PLS_INTEGER 加不加都可以,具体解释看后面
   TYPE varry_stu IS TABLE OF VARCHAR2(30) INDEX BY PLS_INTEGER;
   v_stu_varry varry_stu;
BEGIN

   -- varry_stu := varry_stu('a', 'b', 'c'); 
   -- 此时 不能像 varry 使用上述 构造函数 进行初始化了哦

   v_stu_varry(1) := 'a';
   v_stu_varry(2) := 'b';
   v_stu_varry(3) := 'c';

   FOR i IN v_stu_varry.first .. v_stu_varry.last LOOP
      dbms_output.put_line(i || ' : ' || v_stu_varry(i));
   END LOOP;

END;
/

存储多行多列TYPE <类型名> IS TABLE OF [%rowtype / record]
若想匹配所有字段,与 %rowtype 最为方便
若想匹配部分字段,与 record 最为方便
下列实例是数据仓库中,表同步 的常见写法
当然,实现功能的写法有很多种,这里,只给出我认为最优的。
DECLARE
   i_stu_id NUMBER(3) := 3; -- 模拟入参 
   v_sql    VARCHAR(2000);
   cur_stu  SYS_REFCURSOR;

   TYPE record_stu IS RECORD(
      v_id   stu.id%TYPE,
      v_name stu.name%TYPE);
   TYPE table_stu IS TABLE OF record_stu; -- 思考:加不加 index by ...?
   v_stu table_stu;

BEGIN
   v_sql := 'SELECT t.id, t.name FROM stu t WHERE t.id <= :b1';

   OPEN cur_stu FOR v_sql
      USING i_stu_id; -- 绑定变量 : 大数据处理常用优化手段

   LOOP
      FETCH cur_stu BULK COLLECT
         INTO v_stu LIMIT 2; -- 数据量太少,仅当前测试使用哦,实际开发 建议 500 左右
         
      EXIT WHEN v_stu.count = 0;
      -- 细节:如果此处使用 cur_stu%notfound 不足 limit n 的数据不会在操作了哦
   
      FOR i IN v_stu.first .. v_stu.last LOOP
         dbms_output.put_line('学号:' || v_stu(i).v_id || ' , ' || 
                              '姓名:' || v_stu(i).v_name);
         -- 模拟表同步(不存在时 insert、存在时 update)
      END LOOP;
   
   END LOOP;

   CLOSE cur_stu;

EXCEPTION
   WHEN OTHERS THEN
      IF cur_stu%ISOPEN THEN
        CLOSE cur_stu;
      END IF;
      dbms_output.put_line(SQLERRM);
      dbms_output.put_line(dbms_utility.format_error_backtrace);
END;
/

 

何时使用 index byPL/SQL 向 集合类型 中插入数据时,必须先扩展 内存空间,有两种方式
  • 手动:extend()
  • 自动:index by …

 

DECLARE
  TYPE string_array IS TABLE OF VARCHAR2(30);
  TYPE string_array_index IS TABLE OF VARCHAR2(30) INDEX BY PLS_INTEGER;

  v_a string_array;
  v_b string_array_index;
BEGIN
  -- 不加 INDEX BY... 是 可以 使用构造函数的
  v_a := string_array('a1', 'a2', 'a3');

  -- 加了 INDEX BY... 是 不能 使用构造函数的
  -- varry_stu := varry_stu('b1', 'b2', 'b3'); 
  v_b(v_b.count) := 'b0'; -- 细节: 刚开始,数组为空,故  v_b.count = 0
  v_b(v_b.count) := 'b1'; -- 之后 count 依次递增(切记:不可指定 count
 哦,不然就不递增了,而是重复修改原记录)
  v_b(v_b.count) := 'b2';

  -- TODO: 分别插入新数据 new1, new2
  -- v_a
  v_a.extend(2);
  v_a(4) := 'new1';
  v_a(5) := 'new2';

  FOR i IN v_a.first .. v_a.last LOOP
     dbms_output.put_line(i || ' : ' || v_a(i));
  END LOOP;

  dbms_output.new_line();

  -- v_b
  v_b(v_b.count) := 'new1';
  v_b(v_b.count) := 'new2';

  FOR i IN v_b.first .. v_b.last LOOP
     dbms_output.put_line(i || ' : ' || v_b(i));
  END LOOP;
END;
/




1 : a1
2 : a2
3 : a3
4 : new1
5 : new2

0 : b0
1 : b1
2 : b2
3 : new1
4 : new2

 

空数组时
  • 没加 index by 的数组必须 初始化
  • 空数组时,array.first = array.last = null;
  • 空数组时,array.count = 0;
DECLARE
   TYPE string_array IS TABLE OF VARCHAR2(30);
   TYPE string_array_index IS TABLE OF VARCHAR2(30) INDEX BY PLS_INTEGER;

   v_a string_array := string_array(); -- 必须先初始化
   v_b string_array_index; -- 加了 index by 相当于 默认初始化
BEGIN
   dbms_output.put_line('v_a.first: ' || v_a.first);
   dbms_output.put_line('v_a.last: ' || v_a.last);
   dbms_output.put_line('v_a.count: ' || v_a.count);

   dbms_output.new_line();

   dbms_output.put_line('v_b.first: ' || v_b.first);
   dbms_output.put_line('v_b.last: ' || v_b.last);
   dbms_output.put_line('v_b.count: ' || v_a.count);
END;
/



v_a.first: 
v_a.last: 
v_a.count: 0

v_b.first: 
v_b.last: 
v_b.count: 0

 

清除数组元素 delete 和 置 null 的区别
  • 置 null:清除数组元素,但 不删除内存空间
  • delete:清除数组元素,并且 删除内存空间
DECLARE
   TYPE string_array_index IS TABLE OF VARCHAR2(30) INDEX BY PLS_INTEGER;

   v_b string_array_index;
BEGIN
   v_b(v_b.count) := 'b1'; -- 因为 数组为空,故而 v_b.count = 0
   v_b(v_b.count) := 'b2';
   v_b(v_b.count) := 'b3';

   -- TODO:置 null 方式,清除数组元素
   dbms_output.put_line('原数组长度:' || v_b.count);

   v_b(0) := NULL;

   dbms_output.put_line('置 null 后的长度:' || v_b.count);

   FOR i IN v_b.first .. v_b.last LOOP
      dbms_output.put_line(i || ' : ' || v_b(i));
   END LOOP;

   dbms_output.new_line();
   -- TODO:delete 方式,清除数组元素
   v_b.delete(0);

   dbms_output.put_line('delete 后的长度:' || v_b.count);

   FOR i IN v_b.first .. v_b.last LOOP
      dbms_output.put_line(i || ' : ' || v_b(i));
   END LOOP;
END;
/


原数组长度:3
置 null 后的长度:3
0 : 
1 : b2
2 : b3

delete 后的长度:2
1 : b2
2 : b3

 

数组遍历时,不连续下标异常

数组遍历时,是严格按照下标顺序来的,若中间出现 断层(找不到下标),就会报错

DECLARE
   TYPE string_array_index IS TABLE OF VARCHAR2(30) INDEX BY PLS_INTEGER;

   v_b string_array_index;
BEGIN
   v_b(v_b.count) := 'b1'; -- 因为 数组为空,故而 v_b.count = 0
   v_b(v_b.count) := 'b2';
   v_b(v_b.count) := 'b3';

   v_b.delete(1); -- 删除 'b2'

   FOR i IN v_b.first .. v_b.last LOOP
      -- 测试时,请去掉 IF,直接 dbms_output 即可。
      IF v_b.exists(i) THEN
         dbms_output.put_line(i || ' : ' || v_b(i));
      END IF;
   
   END LOOP;
END;
/


0 : b1
2 : b3

 

 

数组属性和函数属性/函数    描述
count    返回集合中元素的个数
delete    删除集合中 所有 的元素及 extend
delete(x)    删除元素下标为 x 的元素(对 varry 非法)
delete(x, y)    删除元素下标从 x 到 y 的元素(对 varry 非法)
trim    从集合末端开始删除一个元素(对 index by 非法)
trim(x)    从集合末端开始删除 x 个元素 (对 index by 非法)
exists(x)    如果集合元素 x 已经 初始化(extend) ,则返回 true,否则返回 false
extend    在集合 末尾 添加一个元素(对 index by 非法)
extend(x)    在集合 末尾 添加 x个元素 (对 index by 非法)
extend(x, n)    在集合 末尾 添加元素 x 个下标为n 的 副本(对 index by 非法)
first    返回集合中第一个元素的下标号,对 varry 集合 始终 返回 1(除非 未初始化 则为 空)
last    返回集合中最后一个元素的下标号,对 varry 集合 值始终 等于 count (除非 未初始化 则为 空)
limit    返回 varry 集合的最大的元素个数,对 index by 无效
next(x)    返回在第 x 个元素之后紧挨着它的元素下标(x+1),若 x 是最后一个元素,则返回 null
prior(x)    返回在第x个元素之前紧挨着它的 元素下标(x-1),如果 x 是第一个元素,则返回 null
Cursor与 Ref Cursor区别从技术底层看,两者是相同的。普通plsql cursor在定义时是“静态”的。而Ref cursors可以动态打开。
 
Ref cursor根据逻辑动态打开;而游标cursor定义好了就无法修改了
ref cursor可以返回给客户端,cursor则不行。
cursor可以是全局的global ,ref cursor则必须定义在过程或函数中。
ref cursor可以在子程序间传递,cursor则不行。
cursor中定义的静态sql比ref cursor效率高,所以ref cursor通常
 ①静态游标是静态定义,REF 游标是动态关联;

 ②使用REF 游标需REF 游标变量。

 ③REF 游标能做为参数进行传递,而静态游标是不可能的。

总结游标用于处理查询结果集中的数据
游标类型有:隐式游标、显式游标和 REF 游标
隐式游标由 PL/SQL 自动定义、打开和关闭
显式游标用于处理返回多行的查询
显式游标可以删除和更新活动集中的行
要处理结果集中所有记录时,可使用循环游标
在声明 REF 游标时,不需要将 SELECT 语句与 其关联 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凤舞飘伶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值