• Cursor-----from cyber


    oracle plsql cursor usage

    目录

    一、游标的相关概念及特性

      1.定义

      2.游标的分类

      3.游标使用的一般过程

      4.游标的属性

        (1)公共的属性

        (2)额外的属性

    二、隐式游标

      1.隐式游标定义

      2.隐式游标的属性

      3.SELECT INTO时使用隐式游标

    三、显式游标

      1.显式游标的属性

      2.显式游标的使用步骤

        (1) 声明游标

        (2)打开游标

        (3)读取游标数据

        (4)关闭游标

      3.显式游标完整的使用示例

    四、游标FOR循环

    五、SELECT FOR UPDATE

       1.定义

      2.语法

      3.使用例子

     六、WHERE CURRENT OF 语句

       1.语法

      2.使用例子

    一、游标的相关概念及特性
            1.定义
            映射在结果集中某一行数据的具体位置,类似于C语言中的指针。即通过游标方式定位到结果集中某个特定的行,然后根据业务需求对该行进行相应特定的操作。
            2.游标的分类
            在Oracel中,游标可以分为两大类:静态游标 和 REF游标(动态游标)。REF游标是一种引用类型,类似于指针。而静态游标又分为显式游标和隐式游标两种。
            3.游标使用的一般过程:
            显式游标:声明--->打开--->读取--->关闭。
            隐式游标:直接使用读取,声明、打开、关闭都是系统自动进行的。
            4.游标的属性:
                (1)公共的属性:%FOUND,%NOTFOUND,%ISOPEN,%ROWCOUNT。
           %FOUND 布尔型属性,返回TRUE如果INSERT或UPDATE DELETE语句影响了一行或多行或SELECT INTO语句返回一行或多行;否则,返回FALSE。
           %NOTFOUND 布尔型属性,与%FOUND相反。返回TRUE,如果INSERT或UPDATE DELETE语句没有影响任何行,或SELECT INTO语句没有返回任何行;否则,返回FALSE
           %ISOPEN 布尔型属性,判断游标的状态,当游标已经打开时返回TRUE,游标关闭时则返回FALSE。隐式游标总是返回FALSE,因为系统在执行后自动关闭游标。
           %ROWCOUNT 数字型属性,返回受SQL影响的行数。
           注:当使用隐式游标的属性时,需要在属性前加上SQL。因为Oracle在创建隐式游标时,默认的游标名为SQL。比如:SQL%NOTFOUND;
          (2)额外的属性:%BULK_ROWCOUNT,%BULK_EXCEPTIONS。
              %BULK_ROWCOUNT被用于FORALL语句。此属性的第i个元素存储 FORALL LOOP中第 i个执行中的处理的行数UPDATE或DELETE语句。如果第 i个执行不会影响任何行%BULK_ROWCOUNT(i)返回零。
              %BULK_EXCEPTIONS被用于FORALL语句。此属性存储FORALL LOOP中第i个执行的异常,%BULK_EXCEPTIONS(i).ERROR_CODE对应错误代 码,%BULK_EXCEPTIONS(i).ERROR_INDEX对应错误信息。

    注:

      1.不能比较两个游标变量是否相等或者不等。(cv1   emps_rc;   cv2   emps_rc;  IF cv1 = cv2)

      2.CURSOR 类型不能够用于COLLECTION。(TYPE cvs_t IS TABLE OF SYS_REFCURSOR;)

       3.基于REF CURSOR的游标变量无法在PACKAGE的级别被定义,只能够定义在过程,函数,匿名块或触发器里面。(CREATE OR REPLACE PACKAGE plch_pkg  IS  g_cursor   SYS_REFCURSOR; END;)                                                                                               

    二、隐式游标
        1.隐式游标定义
           隐式游标由系统自动定义,其过程由oracle控制,完全自动化。比如当DML被使用时,Oracle为每一个不属于显式游标的DML语句都创建一个隐式 游标,其声明、打开、关闭都是系统自动进行。另外,隐式游标默认的名称是SQL,不能对SQL游标显式地执行OPEN,FETCH,CLOSE语句。

        2.隐式游标的属性
            类似于显式游标,隐式游标同样具有四种属性,只不过隐式游标以SQL%开头,而显示游标以Cursor_name%开头。
            并且,通过SQL%总是只能访问前一个DML操作或单行SELECT操作的游标属性,用于判断DML执行的状态和结果,进而控制程序的流程。
            SQL%ISOPEN
                    游标是否打开。当执行select into、insert、update、delete这些DML操作时,Oracle会隐含地打开游标,且在该语句执行完毕或隐含地关闭游标。
                    因为是隐式游标,故SQL%ISOPEN总是FALSE。
            SQL%FOUND     
                    判断SQL语句是否成功执行。当有作用行时则成功执行为TRUE,否则为FALSE。
            SQL%NOTFOUND  
                    判断SQL语句是否成功执行。当有作用行时否其值为FALSE,否则其值为TRUE。
            SQL%ROWCOUNT
                    在执行任何DML语句之前,SQL%ROWCOUNT的值都是NULL。
                    对于SELECTINTO语句,如果执行成功,SQL%ROWCOUNT的值为1;
                    如果没有成功,SQL%ROWCOUNT的值为0,同时产生一个异常NO_DATA_FOUND。              
     3.SELECT INTO时使用隐式游标
    SELECT INTO用于将单行结果集放置到变量之中。SELECT INTO处理的结果包括三种情况
                查询结果返回单行,SELECT INTO被成功执行;
                查询结果没有返回行,PL/SQL将抛出no_data_found异常;
                查询结果返回多行,PL/SQL将抛出too_many_rows 异常。
            对于上述两种异常发生时,类似于普通异常处理,程序控制权转移到异常处理部分(如没有异常处理则程序中断)。对于异常被激后发,SQL游标的四个属性在此将不可使用,如下面的例子:

    复制代码
     1      DECLARE  
     2        v_ename emp.ename%TYPE;  
     3      BEGIN  
     4        SELECT ename INTO v_ename FROM emp WHERE empno=&no;  
     5        IF  SQL%ROWCOUNT=0 OR SQL%NOTFOUND THEN  
     6          DBMS_OUTPUT.PUT_LINE('The record '||&no||' is not exist!');  
     7        ELSE  
     8          DBMS_OUTPUT.PUT_LINE('The name for record '||&no||' is '||v_ename );  
     9        END IF;  
    10      EXCEPTION  
    11        WHEN NO_DATA_FOUND THEN  
    12          DBMS_OUTPUT.PUT_LINE('No data found for '||&no);  
    13      END;  
    14   操作及结果:
    15      Enter value for no:70  
    16      No data found for 70  
    17            
    18      Enter value for no:7788  
    19      The name for record 7788 is SCOTT 
    复制代码

    从上面的演示中可以看到,当select into没有返回行时,IF  SQL%ROWCOUNT=0OR SQL%NOTFOUND THEN 语句并没有被执行。
            使用下面改进过的代码来执行,即可以将SQL游标属性判断放置到EXCEPTION部分。

    复制代码
     1     DECLARE  
     2       v_ename emp.ename%TYPE;  
     3     BEGIN  
     4       SELECT ename INTO v_ename FROM emp WHERE empno=&no;  
     5       IF SQL%NOTFOUND THEN  
     6         DBMS_OUTPUT.PUT_LINE('The record '||&no||' is not exist!');  
     7       ELSE  
     8         DBMS_OUTPUT.PUT_LINE('The name for record '||&no||' is '||v_ename );  
     9       END IF;  
    10     EXCEPTION  
    11       WHEN NO_DATA_FOUND THEN  
    12         IF SQL%NOTFOUND THEN  
    13           DBMS_OUTPUT.PUT_LINE('The record '||&no||' is not exist!');  
    14           DBMS_OUTPUT.PUT_LINE('No data found for '||&no);  
    15         ELSE  
    16           DBMS_OUTPUT.PUT_LINE('The name for record '||&no||' is '||v_ename );  
    17         END IF;  
    18     END;  
    19         操作及结果:
    20     Enter value for no:80  
    21     The record 80 is not exist!  
    22     No data found for 80  
    复制代码

                                                                                       

    三、显式游标
           1.显式游标的属性
               显式游标的也是4个属性(%FOUND,%NOTFOUND,%ISOPEN,%ROWCOUNT),与隐式游标的相同。      
       2.显式游标的使用步骤:声明(定义)--->打开--->读取--->关闭。
              (1) 声明游标
              格式如下:

    复制代码
     1  CURSOR cursor_name [(parameter[, parameter]...)]  
     2  [RETURN return_type]  
     3  IS select_statement 
     4  例子:
     5  DECLARE  
     6     CURSOR emp_cursor(department IN number2 DEFAULT 20)
     7  return emp%rowtype  
     8  IS   
     9     SELECT *   
    10     FROM emp   
    11     WHERE deptno=department;
    复制代码

         (2)打开游标
              格式:OPEN cursor_name[(VALUE[,VALUE]...)];
              例子:OPEN emp_cursor;
              (3)读取游标数据
              格式:FETCH cursor_name INTO { variable_list | record_variable };
              例子:FETCH emp_cursor INTO emp_row;

      注:游标使用的参数在执行中变化并不影响结果。如下例中:即使 factor一直在增加,但salary一直是乘2。

    复制代码
     1 DECLARE
     2   my_sal employees.salary%TYPE;
     3   my_job employees.job_id%TYPE;
     4   factor INTEGER := 2;
     5   CURSOR c1 IS
     6     SELECT factor*salary FROM employees WHERE job_id = my_job;
     7 BEGIN
     8    OPEN c1;  -- factor initially equals 2
     9    LOOP
    10       FETCH c1 INTO my_sal;
    11       EXIT WHEN c1%NOTFOUND;
    12       factor := factor + 1;  -- does not affect FETCH
    13    END LOOP;
    14    CLOSe c1;
    15 END;
    16 /
    复制代码

              (4)关闭游标
              格式:CLOSE cursor_name;
              例子:CLOSE emp_cursor;

      3.显式游标完整的使用示例: 

    复制代码
     1         --下面的程序将显示声明一个游标,并在循环中使用SELECT语句提取所有部门为30的员工信息。  
     2         DECLARE  
     3           CURSOR emp_cursor(department IN NUMBER DEFAULT 20) IS  
     4             SELECT empno, ename, job, sal  
     5               FROM emp  
     6              WHERE deptno = department;  
     7           
     8           TYPE employee IS RECORD(  
     9             id   emp.empno%TYPE,  
    10             NAME emp.ename%TYPE,  
    11             job  emp.job%TYPE,  
    12             sal  emp.sal%TYPE);  
    13           emp_row employee;  
    14         BEGIN  
    15           OPEN emp_cursor(30);  
    16           FETCH emp_cursor INTO emp_row;  
    17           WHILE emp_cursor%FOUND LOOP  
    18             dbms_output.put('员工编号 ' || emp_row.id);  
    19             dbms_output.put(' 姓名 ' || emp_row.name);  
    20             dbms_output.put(' 职位 ' || emp_row.job);  
    21             dbms_output.put(' 薪金 ' || emp_row.sal);  
    22             --填充下一条记录  
    23             FETCH emp_cursor INTO emp_row;  
    24           END LOOP;  
    25           CLOSE emp_cursor;  
    26         END; 
    复制代码

                                                                                  

     四、游标FOR循环

           在大多数时候我们在自定义显示游标的时候都遵循下面的步骤:
            1、打开游标
            2、开始循环
            3、从游标中取值
            4、检查那一行被返回
            5、处理
            6、关闭循环
            7、关闭游标
            可以简单的把这一类代码称为游标用于循环。但还有一种循环与这种类型不相同,这就是FOR循环,用于FOR循环的游标按照正常的声明方式声明,它的优点在 于不需要显式的打开、关闭、取数据,测试数据的存在、定义存放数据的变量等等。游标FOR 循环的语法如下:

    复制代码
     1  FOR record_index in cursor_name
     2  LOOP
     3     {...statements...}
     4  END LOOP;
     5    使用例子:
     6  CREATE OR REPLACE Function TotalIncome
     7     ( name_in IN varchar2 )
     8     RETURN varchar2
     9  IS
    10     total_val number(6);
    11     cursor c1 is
    12       SELECT monthly_income
    13       FROM employees
    14       WHERE name = name_in;
    15  BEGIN
    16     total_val := 0;
    17     FOR employee_rec in c1
    18     LOOP
    19        total_val := total_val + employee_rec.monthly_income;
    20     END LOOP;
    21     RETURN total_val;
    22  END;
    复制代码

     五、SELECT FOR UPDATE
        1.定义
        SELECT FOR UPDATE 语句可以锁住游标结果集。直到下一次 COMMIT 或ROLLBACK 操作执行后,才解锁游标。
        2.语法

    复制代码
    1         CURSOR cursor_name
    2         IS
    3       select_statement
    4        FOR UPDATE [OF column_list] [NOWAIT];
    5        
    6        cursor_name: 游标名。
    7         select_statement: SELECT 查询语句。
    8         column_list: 游标结果集中想要更新的字段。
    9         NOWAIT: 选择游标是否等待资源。
    复制代码

    3.使用例子

    1 CURSOR c1
    2         IS
    3          SELECT course_number, instructor
    4       FROM courses_tbl
    5       FOR UPDATE OF instructor; 
    6   注:可以使用 WHERE CURRENT OF 语句 来更新或删除被 SELECT FOR UPDATE 锁住的数据。

                                                                                    

    六、WHERE CURRENT OF 语句
        1.语法

    1         UPDATE table_name
    2       SET set_clause
    3       WHERE CURRENT OF cursor_name;
    4 5       DELETE FROM table_name
    6         WHERE CURRENT OF cursor_name;

            注: WHERE CURRENT OF 语句只更新或删除最后被游标 FETCH 到的记录。
        2.使用例子

    复制代码
     1  (1)Updating using the WHERE CURRENT OF Statement
     2  CREATE OR REPLACE Function FindCourse
     3     ( name_in IN varchar2 )
     4     RETURN number
     5  IS
     6     cnumber number;
     7     CURSOR c1
     8     IS
     9       SELECT course_number
    10       FROM courses_tbl
    11       WHERE course_name = name_in
    12       FOR UPDATE of instructor;
    13  BEGIN
    14     OPEN c1;
    15     FETCH c1 INTO cnumber;
    16     if c1%notfound then
    17        cnumber := 9999;
    18     else
    19        UPDATE courses_tbl
    20          SET instructor = 'SMITH'
    21          WHERE CURRENT OF c1;
    22        COMMIT;
    23     end if;
    24     CLOSE c1;
    25  RETURN cnumber;
    26  END;
    27  
    28  (2)Deleting using the WHERE CURRENT OF Statement
    29  CREATE OR REPLACE Function FindCourse
    30     ( name_in IN varchar2 )
    31     RETURN number
    32  IS
    33     cnumber number;
    34     CURSOR c1
    35     IS
    36       SELECT course_number
    37       from courses_tbl
    38       where course_name = name_in
    39       FOR UPDATE of instructor;
    40  BEGIN
    41     open c1;
    42     fetch c1 into cnumber;
    43     if c1%notfound then
    44        cnumber := 9999;
    45     else
    46        DELETE FROM courses_tbl
    47          WHERE CURRENT OF c1;
    48        COMMIT;
    49     end if;
    50     close c1;
    51  RETURN cnumber;
    52  END;
    复制代码

                                                                                     
     

  • 相关阅读:
    MySQL 5.5版本数据库介绍与二进制安装
    nginx配置文件的基础优化
    yum源是什么
    微服务之间调用token管理
    微服务之间调用事务处理
    idea
    sentry
    infinispan配置
    微服务事务处理
    高并发处理
  • 原文地址:https://www.cnblogs.com/Jeffrey-xu/p/5057654.html
Copyright © 2020-2023  润新知