显式游标主要是用于对查询语句的处理,尤其是在查询结果为多条记录的情况下。

显示游标的调用格式

声明一个显式游标后,可以在同一子程序或程序包中对其进行定义,或者同时声明并定义显式游标。

仅声明游标的显式游标声明具有以下语法:

  1. CURSOR cursor_name [ parameter_list ] RETURN return_type;

明确的游标定义语法如下:

  1. CURSOR cursor_name [ parameter_list ] [ RETURN return_type ]
  2. IS select_statement;

显示游标的处理步骤

显式游标处理需四个步骤:

  1. 定义游标

  2. 打开游标

  3. 提取游标数据

  4. 关闭游标

定义游标

定义游标名,以及与其相对应的 SELECT 语句。

格式如下:

  1. CURSOR cursor_name[(parameter[, parameter]…)] IS select_statement;

游标参数只能为输入参数,其格式为:

  1. parameter_name [IN] datatype [{:= | DEFAULT} expression]

注意

在指定数据类型时,不能使用长度约束。如 NUMBER(4)、CHAR(10) 等都是错误的。

打开游标

执行游标所对应的 SELECT 语句,将其查询结果放入工作区,并且指针指向工作区的首部,标识游标结果集合。如果游标查询语句中带有 FOR UPDATE 选项,OPEN 语句还将锁定数据库表中游标结果集合对应的数据行。

格式如下:

  1. OPEN cursor_name[([parameter =>] value[, [parameter =>] value]…)];

在向游标传递参数时,可以使用与函数参数相同的传值方法,即位置表示法和名称表示法。PL 程序不能用 OPEN 语句重复打开一个游标。

提取游标数据

检索结果集合中的数据行,放入指定的输出变量中。

格式如下:

  1. FETCH cursor_name INTO {variable_list | record_variable };

对该记录进行循环处理,直到处理完活动集合中的所有记录。

关闭游标

当提取和处理完游标结果集合数据后,应及时关闭游标,以释放该游标所占用的系统资源,并使该游标的工作区变成无效,这时就不能再使用 FETCH 语句取其中数据。关闭后的游标可以使用 OPEN 语句重新打开。

格式如下:

  1. CLOSE cursor_name;

使用显示游标循环获取记录集的每行记录

下面步骤展示了如何使用显式游标循环获取记录集的每行记录。

  1. 首先在声明部分声明一个游标,参见以下两种方法。
  1. CURSOR cursor_name IS query;
  1. CURSOR cursor_name(para_namedata_type) IS query;
  1. 在声明部分声明一个记录保存游标返回的行记录。
  1. record_name cursor_name%ROWTYPE;
  1. 在执行部分打开游标,参见以下两种方法。
  1. OPEN cursor_name;
  1. OPEN cursor_name(para_name);
  1. 在执行部分从游标记录集中获取行数据。每次一行,结合下面格式的 LOOP 语句一起使用可以获取多行数据。
  1. LOOP
  2. FETCHcursor_name INTO record_name;
  3. EXIT WHENcursor_name%NOTFOUND;
  4. statement;
  5. [ statement; ]...
  6. END LOOP;
  1. 关闭游标。
  1. CLOSE cursor_name;

示例:使用显式游标循环获取记录集的每行记录

  1. delimiter /
  2. CREATE OR REPLACE PACKAGE pkg_ware_mgmt as
  3. PROCEDURE sp_record_print(p_w_id IN ware.w_id%type);
  4. END;
  5. /
  6. delimiter ;
  7. delimiter /
  8. CREATE OR REPLACE PACKAGE BODY pkg_ware_mgmt
  9. AS
  10. PROCEDURE sp_record_print_by_record(p_record IN ware%ROWTYPE)
  11. AS
  12. BEGIN
  13. dbms_output.put_line('Print a record :');
  14. dbms_output.put_line('W_ID : ' || p_record.w_id
  15. || ', W_YTD : ' || p_record.w_ytd
  16. || ', W_TAX : ' || p_record.w_tax
  17. || ', W_NAME : ' || p_record.w_name
  18. || ', W_STREET_1 : ' || p_record.w_street_1
  19. || ', W_STREET_2 : ' || p_record.w_street_2
  20. || ', W_CITY : ' || p_record.w_city
  21. || ', W_STATE : ' || p_record.w_state
  22. || ', W_ZIP : ' || p_record.w_zip )
  23. ;
  24. dbms_output.put_line('');
  25. END;
  26. PROCEDURE sp_record_print(p_w_id IN ware.w_id%TYPE )
  27. IS
  28. CURSOR c1(cp_w_id ware.w_id%TYPE ) IS SELECT * FROM ware WHERE w_id = cp_w_id ;
  29. r_ware ware%ROWTYPE;
  30. BEGIN
  31. OPEN c1(p_w_id);
  32. dbms_output.put_line('Open a cursor with a parameter [ ' || p_w_id || ' ].');
  33. LOOP
  34. FETCH c1 INTO r_ware ;
  35. dbms_output.put_line('Fetch the cursor one time.');
  36. EXIT WHEN c1%NOTFOUND ;
  37. sp_record_print_by_record(r_ware);
  38. END LOOP;
  39. EXCEPTION
  40. WHEN OTHERS THEN
  41. dbms_output.put_line('Raise an unkown exception !');
  42. END ;
  43. END;
  44. /
  45. delimiter ;
  46. obclient> set serveroutput on;
  47. Query OK, 0 rows affected (0.00 sec)
  48. obclient> call pkg_ware_mgmt.sp_record_print(1);
  49. Query OK, 0 rows affected (0.12 sec)
  50. Open a cursor with a parameter [ 1 ].
  51. Fetch the cursor one time.
  52. Print a record :
  53. W_ID : 1, W_YTD : 1200, W_TAX : .1868, W_NAME : W_NAME_1, W_STREET_1 : jTNkXKWXOdh, W_STREET_2 : lf9QXTXXGoF04IZBkCP7, W_CITY : srRq15uvxe5, W_STATE : GQ, W_ZIP : 506811111
  54. Fetch the cursor one time.
  55. obclient>