zoukankan      html  css  js  c++  java
  • 游标

    一、    游标的定义

    1.      游标概念

    ①  从表中检索出结果集,从中每次指向一条记录进行交互的机制。

    ②  关系数据库中的操作是在完整的行集合上执行的。 由SELECT 语句返回的行集合包括满足该语句的WHERE 子句所列条件的所有行。由该语句返回完整的行集合叫做结果集。

    ③  游标是通过游标库来实现的。游标库是常常作为数据库系统或数据访问API 的一部分而得以实现的软件。

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

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

        换句话说,游标从概念上讲基于数据库的表返回结果集。

             由于它指示结果集中的当前位置 ,就像计算机屏幕上的光标指示当前位置一样,“游标”由此得名。

       %NotFound : 最后一条记录是否提取出True or False。

      作用

        ①指定结果集中特定行的位置。

        ②基于当前的结果集位置检索一行或连续的几行。

        ③在结果集的当前位置修改行中的数据。

        ④可以以编程的方式访问数据库。

    2.      主要事项

     因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该改写;如果使用了游标,就要尽量避免在游标循环中再进行表连接的操作。

    3.      游标类型

    
    
    静态游标:结果集已经确实(静态定义)的游标。分为隐式和显示游标。
    
    
    (1)隐式游标:所有DML语句为隐式游标,通过隐式游标属性可以获取SQL语句信息。 一次只能从数据库中提取一行数据,对于这种形式的查询和DML操作,系统都会使用一个隐式游标。
        * 插入操作:INSERT。              
    * 更新操作:UPDATE。
                  
    * 删除操作:DELETE。
                  
    * 单行查询操作:SELECT ... INTO ...。
    (2)隐式游标的属性 返回值类型  
         SQL%ROWCOUNT    整型  代表DML语句成功执行的数据行数  
       SQL%FOUND   布尔型 值为TRUE代表插入、删除、更新或单行查询操作成功  
    SQL%NOTFOUND    布尔型 与SQL%FOUND属性返回值相反  
    SQL%ISOPEN  布尔型 DML执行过程中为真,结束后为假 

    (3)显示游标:用户显示声明的游标,即指定结果集。当查询返回结果超过一行时,就需要一个显式游标。
    显式游标对应一个返回结果为多行多列的SELECT语句。
            REF游标:动态关联结果集的临时对象。 

    5.      游标属性

    
    
        %Found :Fetch语句(获取记录)执行情况True or False。
    
    
        %NotFound : 最后一条记录是否提取出True or False。
    
    
        %ISOpen : 游标是否打开True or False。
    
    
        %RowCount :游标当前提取的行数 。

    二、    游标的使用方式

     1 1.单条处理 
     2 open 游标; 
     3 LOOP   
     4 FETCH 游标 INTO 变量; 
     5 EXIT WHEN  条件; 
     6 END LOOP; 
     7 CLOSE 游标; 
     8   
     9 2.批量处理 
    10 open 游标; 
    11 FETCH 游标 BULK COLLECT INTO 集合变量; 
    12 CLOSE 游标; 
    13   
    14 3.隐式游标 
    15 for x in (sql语句) loop 
    16 ...--逻辑处理 
    17 end loop;

    1cursor游标使用

     1 /*简单cursor游标  
     2  *students表里面有name字段,你可以换做其他表测试   */  
     3 declare 
     4  --定义游标并且赋值(is 不能和cursor分开使用)  
     5  cursor stus_cur is select * from students;  
     6  --定义rowtype  
     7  cur_stu students%rowtype;  
     8  /*开始执行*/  
     9  begin 
    10  --开启游标  
    11  open stus_cur;  
    12   --loop循环  
    13   loop  
    14   --循环条件  
    15   exit when stus_cur%notfound;  
    16   --游标值赋值到rowtype  
    17   fetch stus_cur into cur_stu;  
    18   --输出  
    19   dbms_output.put_line(cur_stu.name);  
    20   --结束循环  
    21   end loop;  
    22  --关闭游标  
    23  close stus_cur;  
    24  /*结束执行*/  
    25  end;

    2ref cursor 游标使用

    1)介绍

      像游标cursor一样,游标变量ref cursor指向指定查询结果集当前行。游标变量显得更加灵活因为其声明并不绑定指定查询。其主要运用于PLSQL函数或存储过程以及其他编程语言java等程序之间作为参数传递。    不像游标的一点,游标变量没有参数。    游标变量具有以下属性:    (%FOUND, %NOTFOUND, %ISOPEN, and %ROWCOUNT)

    2)用法介绍:

    1、声明格式:

    1   DECLARE TYPE DeptCurTyp IS REF CURSOR RETURN  departments%ROWTYPE;

    2、游标变量又分为强类型strong(with a return type)和弱类型(with no return type)

    DECLARE
       TYPE empcurtyp IS REF CURSOR RETURN employees%ROWTYPE; -- 强类型
       TYPE genericcurtyp IS REF CURSOR; -- 弱类型
       cursor1 empcurtyp;
       cursor2 genericcurtyp;
       my_cursor SYS_REFCURSOR; -- 使用预定义游标变量sys_refcursor
       TYPE deptcurtyp IS REF CURSOR RETURN departments%ROWTYPE;
       dept_cv deptcurtyp; -- 声明游标变量或是返回record类型:
       DECLARE
       TYPE EmpRecTyp IS RECORD (
       employee_id NUMBER,
       last_name VARCHAR2(25),
       salary NUMBER(8,2));
       TYPE EmpCurTyp IS REF CURSOR RETURN EmpRecTyp;
       emp_cv EmpCurTyp; -- declare cursor variable 

    3、使用游标熟悉检查游标变量是否打开

    DECLARE
    TYPE empcurtyp IS REF CURSOR RETURN employees%ROWTYPE;
    emp_cv empcurtyp;
    BEGIN
    IF NOT emp_cv%ISOPEN THEN -- open cursor variable
    OPEN emp_cv FOR SELECT * FROM employees;
    END IF;
    CLOSE emp_cv;
    END;

    4、使用游标变量作为参数传递 

     1 DECLARE
     2 TYPE empcurtyp IS REF CURSOR RETURN employees%ROWTYPE;
     3 emp empcurtyp;
     4 -- after result set is built, process all the rows inside a single procedure
     5 -- rather than calling a procedure for each row
     6 PROCEDURE process_emp_cv (emp_cv IN empcurtyp) IS
     7 person employees%ROWTYPE;
     8 BEGIN
     9 DBMS_OUTPUT.PUT_LINE('-----');
    10 DBMS_OUTPUT.PUT_LINE('Here are the names from the result set:');
    11 LOOP
    12 FETCH emp_cv INTO person;
    13 EXIT WHEN emp_cv%NOTFOUND;
    14 DBMS_OUTPUT.PUT_LINE('Name = ' || person.first_name ||
    15 ' ' || person.last_name);
    16 END LOOP;
    17 END;
    18 BEGIN
    19 -- First find 10 arbitrary employees.
    20 OPEN emp FOR SELECT * FROM employees WHERE ROWNUM < 11;
    21 process_emp_cv(emp);
    22 CLOSE emp;
    23 -- find employees matching a condition.
    24 OPEN emp FOR SELECT * FROM employees WHERE last_name LIKE 'R%';
    25 process_emp_cv(emp);
    26 CLOSE emp;
    27 END;
    28 /

    5、在包package中声明游标变量:

     1 CREATE PACKAGE emp_data AS
     2 TYPE empcurtyp IS REF CURSOR RETURN employees%ROWTYPE;
     3 PROCEDURE open_emp_cv (emp_cv IN OUT empcurtyp);
     4 END emp_data;
     5 /
     6 CREATE PACKAGE BODY emp_data AS
     7 PROCEDURE open_emp_cv (emp_cv IN OUT EmpCurTyp) IS
     8 BEGIN
     9 OPEN emp_cv FOR SELECT * FROM employees;
    10 END open_emp_cv;
    11 END emp_data;
    12 /

    6、提取游标变量到集合类型collection

     1 DECLARE
     2 TYPE empcurtyp IS REF CURSOR;
     3 TYPE namelist IS TABLE OF employees.last_name%TYPE;
     4 TYPE sallist IS TABLE OF employees.salary%TYPE;
     5 emp_cv empcurtyp;
     6 names namelist;
     7 sals sallist;
     8 BEGIN
     9 OPEN emp_cv FOR SELECT last_name, salary FROM employees
    10 WHERE job_id = 'SA_REP';
    11 FETCH emp_cv BULK COLLECT INTO names, sals;
    12 CLOSE emp_cv;
    13 -- loop through the names and sals collections
    14 FOR i IN names.FIRST .. names.LAST
    15 LOOP
    16 DBMS_OUTPUT.PUT_LINE('Name = ' || names(i) || ', salary = ' || sals(i));
    17 END LOOP;
    18 END;
    19 /

    3游标变量的使用限制:

     1、不能再包说明中声明游标变量;

     2、不能用“=”运算符比较游标变量相等性、不等性及是否为空;

     3、不能存储于表列中;

     4、不能将游标变量存在于关联数组、嵌套表或数组; 

     5、游标和游标变量之前是不可互操作的!

    1、强类型游标:

     1 CREATE OR REPLACE PACKAGE strongly_typed IS
     2 
     3 TYPE return_cur IS REF CURSOR RETURN all_tables%ROWTYPE;
     4 PROCEDURE child(p_return_rec OUT return_cur);
     5 PROCEDURE parent(p_NumRecs PLS_INTEGER);
     6 
     7 END strongly_typed;
     8 /
     9 CREATE OR REPLACE PACKAGE BODY strongly_typed IS
    10 PROCEDURE child(p_return_rec OUT return_cur) IS
    11 
    12 BEGIN
    13   OPEN p_return_rec FOR 
    14   SELECT * FROM all_tables; 
    15 END child;
    16 --==================================================
    17 PROCEDURE parent (p_NumRecs PLS_INTEGER) IS 
    18  p_retcur return_cur;
    19  at_rec   all_tables%ROWTYPE;
    20 BEGIN
    21   child(p_retcur);
    22 
    23   FOR i IN 1 .. p_NumRecs
    24   LOOP
    25     FETCH p_retcur
    26     INTO at_rec;
    27 
    28     dbms_output.put_line(at_rec.table_name || 
    29     ' - ' || at_rec.tablespace_name || 
    30     ' - ' || TO_CHAR(at_rec.initial_extent) || 
    31     ' - ' || TO_CHAR(at_rec.next_extent));
    32   END LOOP;
    33 END parent;
    34 END strongly_typed;
    35 /
    38 set serveroutput on
    39 
    40 exec strongly_typed.parent(1);
    41 exec strongly_typed.parent(8);

    2、弱类型游标:

     1 CREATE OR REPLACE PROCEDURE child (
     2  p_NumRecs IN PLS_INTEGER,
     3  p_return_cur OUT SYS_REFCURSOR)
     4 IS
     5 
     6 BEGIN
     7   OPEN p_return_cur FOR
     8   'SELECT * FROM all_tables WHERE rownum <= ' || p_NumRecs ;
     9 END child;
    10 /
    11 
    12 CREATE OR REPLACE PROCEDURE parent (pNumRecs VARCHAR2) IS
    13  p_retcur  SYS_REFCURSOR;
    14  at_rec    all_tables%ROWTYPE;
    15 BEGIN
    16   child(pNumRecs, p_retcur);
    17 
    18   FOR i IN 1 .. pNumRecs
    19   LOOP
    20     FETCH p_retcur
    21     INTO at_rec;
    22 
    23     dbms_output.put_line(at_rec.table_name ||
    24     ' - ' || at_rec.tablespace_name ||
    25     ' - ' || TO_CHAR(at_rec.initial_extent) ||
    26     ' - ' || TO_CHAR(at_rec.next_extent));
    27   END LOOP;
    28 END parent;
    29 /
    30 
    31 set serveroutput on
    32 
    33 exec parent(1);
    34 exec parent(17);

    3、预定义游标变量:

    CREATE TABLE employees (
    empid   NUMBER(5),
    empname VARCHAR2(30));
    
    INSERT INTO employees (empid, empname) VALUES (1, 'Dan Morgan');
    INSERT INTO employees (empid, empname) VALUES (2, 'Hans Forbrich');
    INSERT INTO employees (empid, empname) VALUES (3, 'Caleb Small');
    COMMIT;
    CREATE OR REPLACE PROCEDURE pass_ref_cur(p_cursor SYS_REFCURSOR) IS
    
    TYPE array_t IS TABLE OF VARCHAR2(4000)
    INDEX BY BINARY_INTEGER;
    
    rec_array array_t;
    
    BEGIN
      FETCH p_cursor BULK COLLECT INTO rec_array;
    
      FOR i IN rec_array.FIRST .. rec_array.LAST
      LOOP
        dbms_output.put_line(rec_array(i));
      END LOOP;
    END pass_ref_cur;
    /
    set serveroutput on
    
    DECLARE
     rec_array SYS_REFCURSOR;
    BEGIN
      OPEN rec_array FOR
      'SELECT empname FROM employees';
    
      pass_ref_cur(rec_array);
      CLOSE rec_array;
    END;

    三、    游标循环方式

    1、补充一种循环条件

     1 declare 
     2  stu_cur sys_refcursor;  
     3  stuone students%rowtype;  
     4  begin 
     5   open stu_cur for select * from students;  
     6   fetch stu_cur into stuone;  
     7   --特别注意循环条件的改变  
     8   --这个条件是发现了在循环  
     9   --与上一个notfound不同的  
    10   while stu_cur%found loop  
    11   dbms_output.put_line(stuone.name||' '||stuone.hobby);  
    12   fetch stu_cur into stuone;  
    13       end loop;  
    14  end;    

     

    2、普通的fetch into

     1 /*普通方式*/  
     2 declare 
     3 cursor myemp_cur is select * from myemp;  
     4 v_myemp myemp%rowtype;  
     5 begin 
     6  open myemp_cur;  
     7  fetch myemp_cur into v_myemp;  
     8  while myemp_cur%found loop  
     9  dbms_output.put_line(v_myemp.ename);  
    10  fetch myemp_cur into v_myemp;  
    11  end loop;  
    12 end;

    3高效的bulk collect

     1 /*高效bulk collect for*/  
     2 declare 
     3 cursor myemp_cur  
     4 is select * from myemp;  
     5 type myemp_tab is table of myemp%rowtype;  
     6 myemp_rd myemp_tab;  
     7 begin 
     8  open myemp_cur;  
     9  loop  
    10  fetch myemp_cur bulk collect into myemp_rd limit 20;  
    11  for i in 1..myemp_rd.count loop  
    12   dbms_output.put_line('姓名:'||myemp_rd(i).ename);  
    13  end loop;  
    14  exit when myemp_cur%notfound;  
    15  end loop;  
    16 end;
  • 相关阅读:
    file is universal (3 slices) but does not contain a(n) armv7s slice error for static libraries on iOS
    WebImageButton does not change images after being enabled in Javascript
    ajax OPTION
    编程遍历页面上所有TextBox控件并给它赋值为string.Empty?
    获取海洋天气预报
    C#线程系列教程(1):BeginInvoke和EndInvoke方法
    js控制只能输入数字和小数点
    Response.AddHeader(,)
    ManualResetEvent的理解
    Convert.ToInt32、int.Parse(Int32.Parse)、int.TryParse、(int) 区别
  • 原文地址:https://www.cnblogs.com/yuarvin/p/7275731.html
Copyright © 2011-2022 走看看