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;
  • 相关阅读:
    bzoj 2878: [Noi2012]迷失游乐园
    端口安全检查shell脚本
    Linux安全基线检查脚本
    kali修改时区
    Elasticsearch+Kibana+Logstash安装
    go基础语法
    windows server 2012泛域名解析配置
    域名解析知识总结
    DDOS防护原理
    kali 2.0下搭建DVWA环境
  • 原文地址:https://www.cnblogs.com/yuarvin/p/7275731.html
Copyright © 2011-2022 走看看