REF CURSOR

利用REF CURSOR,可以在程序间传递结果集(一个程序里打开游标变量,在另外的程序里处理数据)。
也可以利用REF CURSOR实现BULK SQL,提高SQL性能。


REF CURSOR分两种,Strong REF CURSOR 和 Weak REF CURSOR。


Strong REF CURSOR:指定retrun type,CURSOR变量的类型必须和return type一致。
DECLARE
TYPE strongcurtyp IS REF CURSOR RETURN emp%ROWTYPE;
emp_cv strongcurtyp;


Weak REF CURSOR:不指定return type,能和任何类型的CURSOR变量匹配。
DECLARE
TYPE weakcurtyp IS REF CURSOR;
weak_cv weakcurtyp;
any_cv SYS_REFCURSOR; --使用SYS_REFCURSOR可以使变量any_cv跟任何weak REF CURSOR类型匹配。

 使用Strong REF CURSOR例子

CREATE OR REPLACE PACKAGE emp_data AS
TYPE empcurtyp IS REF CURSOR RETURN emp%rowtype; --定义TYPE as Strong REF CURSOR
PROCEDURE open_emp_cv(emp_cv IN OUT empcurtyp, choice INT); --根据不同的choice选择不同的CURSOR
PROCEDURE retrieve_data(choice INT); --通过调用procedure open_emp_cv,返回指定的结果集。
END emp_data;


=============================================




CREATE OR REPLACE PACKAGE BODY emp_data AS

--procedure open_emp_cv-----------------------------

PROCEDURE open_emp_cv(emp_cv IN OUT empcurtyp, choice INT) IS --emp_cv作为传入/传出的CURSOR PARAMETER
BEGIN
IF choice = 1 THEN
OPEN emp_cv FOR
SELECT * FROM emp WHERE empno < 7800;
ELSIF choice = 2 THEN
OPEN emp_cv FOR
SELECT * FROM emp WHERE SAL < 1000;
ELSIF choice = 3 THEN
OPEN emp_cv FOR
SELECT * FROM emp WHERE ename like 'J%';
END IF;
END;


--procedure retrieve_data----------------------------------

PROCEDURE retrieve_data(choice INT) IS
return_cv empcurtyp; --定义传入open_emp_cv的CURSOR变量
return_row emp%ROWTYPE;
invalid_choice EXCEPTION;
BEGIN
open_emp_cv(return_cv, choice); --调用 procedure OPEN_EMP_CV

IF choice = 1 THEN
DBMS_OUTPUT.PUT_LINE('EMPLOYEES with empno less than 7800');
ELSIF choice = 2 THEN
DBMS_OUTPUT.PUT_LINE('EMPLOYEES with salary less than 1000');
ELSIF choice = 3 THEN
DBMS_OUTPUT.PUT_LINE('EMPLOYEES with name starts with ''J''');
ELSE
RAISE invalid_choice;
END IF;

LOOP
FETCH return_cv
INTO return_row;
EXIT WHEN return_cv%NOTFOUND;

DBMS_OUTPUT.PUT_LINE(return_row.empno || '--' || return_row.ename || '--' ||
return_row.sal);
END LOOP;

EXCEPTION
WHEN invalid_choice THEN
DBMS_OUTPUT.PUT_LINE('The CHOICE should be in one of (1,2,3)!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Errors in procedure RETRIEVE_DATA!');
END;

END emp_data;


================================




执行:
SQL> EXEC emp_data.retrieve_data(1);
EMPLOYEES with empno less than 7800
7369--SMITH--800
7499--ALLEN--1600
7521--WARD--1250
7566--JONES--2975
7654--MARTIN--1250
7698--BLAKE--2850
7782--CLARK--2450
7788--SCOTT--3000
PL/SQL procedure successfully completed

SQL> EXEC emp_data.retrieve_data(2);
EMPLOYEES with salary less than 1000
7369--SMITH--800
7900--JAMES--950
PL/SQL procedure successfully completed

SQL> EXEC emp_data.retrieve_data(3);
EMPLOYEES with name starts with 'J'
7566--JONES--2975
7900--JAMES--950
PL/SQL procedure successfully completed

SQL> EXEC emp_data.retrieve_data(34);
The CHOICE should be in one of (1,2,3)!
PL/SQL procedure successfully completed

使用Weak REF CURSOR例子

--procedure open_cv---------------------------------------

create or replace procedure open_cv(choice IN INT,
return_cv OUT SYS_REFCURSOR) is
--参数return_cv为weak REF CURSOR,利用SYS_CURSOR来定义
begin
if choice = 1 then
open return_cv for 'select * from emp';
elsif choice = 2 then
open return_cv for 'select * from dept';
end if;
end open_cv;


--procedure retrieve_data------------------------------------

create or replace procedure retrieve_data(choice IN INT) is
emp_rec emp%rowtype;
dept_rec dept%rowtype;
return_cv SYS_REFCURSOR;
invalid_choice exception;
begin
if choice=1 then
dbms_output.put_line('employee information');
open_cv(1,return_cv); --调用procedure open_cv;
loop
fetch return_cv into emp_rec;
exit when return_cv%notfound;
dbms_output.put_line(emp_rec.empno||'-'||emp_rec.ename||'-'||emp_rec.sal);
end loop;
elsif choice=2 then
dbms_output.put_line('department information');
open_cv(2,return_cv);
loop
fetch return_cv into dept_rec;
exit when return_cv%notfound;
dbms_output.put_line(dept_rec.deptno||'-'||dept_rec.dname||'-'||dept_rec.loc);
end loop;
else
raise invalid_choice;
end if;

exception
when invalid_choice then
dbms_output.put_line('The CHOICE should be one of 1 and 2!');
when others then
dbms_output.put_line('Errors in procedure retrieve_data');
end retrieve_data;

-----------------------------------------------------------------

执行:
SQL> exec retrieve_data(1);
employee information
7369-SMITH-800
7499-ALLEN-1600
7521-WARD-1250
7566-JONES-2975
7654-MARTIN-1250
7698-BLAKE-2850
......
PL/SQL procedure successfully completed

SQL> exec retrieve_data(2);
department information
10-ACCOUNTING-NEW YORK
20-RESEARCH-DALLAS
30-SALES-CHICAGO
40-OPERATIONS-BOSTON
PL/SQL procedure successfully completed

用REF CURSOR实现BULK功能

1. To speed up INSERT, UPDATE, and DELETE statements, enclose the SQL statement within a PL/SQL FORALL statement instead of a loop construct.
2. To speed up SELECT statements, include the BULK COLLECT INTO clause in the SELECT statement instead of using INTO.



SQL> create table tab2 as select empno ID, ename NAME, sal SALARY from emp where 1=2;
Table created


-------------------------------------------------------

create or replace procedure REF_BULK is
type empcurtyp is ref cursor;
type idlist is table of emp.empno%type;
type namelist is table of emp.ename%type;
type sallist is table of emp.sal%type;

emp_cv empcurtyp;
ids idlist;
names namelist;
sals sallist;

row_cnt number;
begin
open emp_cv for
select empno, ename, sal from emp;
fetch emp_cv BULK COLLECT
INTO ids, names, sals; --BULK COLLECT INTO instead of INTO
close emp_cv;

for i in ids.first .. ids.last loop
dbms_output.put_line('id=' || ids(i) || ' name=' || names(i) ||
' salary=' || sals(i));
end loop;

forall i in ids.first .. ids.last --FORALL instead of FOR ...LOOP
insert into tab2 values (ids(i), names(i), sals(i));
commit;

select count(*) into row_cnt from tab2;
dbms_output.put_line('-----------------------------------');
dbms_output.put_line('The row number of tab2 is ' || row_cnt);
end REF_BULK;


------------------------------------------------------------

执行:

SQL> exec ref_bulk;

id=7369 name=SMITH salary=800
id=7499 name=ALLEN salary=1600
id=7521 name=WARD salary=1250
id=7566 name=JONES salary=2975
id=7654 name=MARTIN salary=1250
id=7698 name=BLAKE salary=2850
id=7782 name=CLARK salary=2450
id=7788 name=SCOTT salary=3000
id=7839 name=KING salary=5000
id=7844 name=TURNER salary=1500
id=7876 name=ADAMS salary=1100
id=7900 name=JAMES salary=950
id=7902 name=FORD salary=3000
id=7934 name=MILLER salary=1300
-----------------------------------
The row number of tab2 is 14

PL/SQL procedure successfully completed

__________________
i have a good job and hope to have a great career,
i have a nice girl friend and hope to have a great marriage,
i have a wonderful parents and hope to be a good parent too,
i have a rented house and i hope to have a home of my own,
i travel in taxi and i hope to have and drive my own car,

i wonder when i have all i want .........what's next in my needs list,
i wonder when i have all i want..........will i still be a happy man in the world,
i wonder when i have all i want..........will this world be still a happy place to live in....?

### Refcursor vs Cursor in PostgreSQL Differences and Usage In PostgreSQL, both `REFCURSOR` and cursors serve similar purposes but differ significantly in their implementation and use cases. #### Definition and Basic Characteristics A **cursor** allows retrieval of multiple rows from a query one at a time or in blocks. This feature is particularly useful when dealing with large datasets that cannot fit into memory all at once[^1]. Cursors can be declared within PL/pgSQL functions or procedures directly using the `DECLARE CURSOR` syntax. On the other hand, a **REFCURSOR** represents an abstract handle to a cursor rather than being a cursor itself. It acts more like a pointer or reference to a cursor object created elsewhere. Unlike regular cursors, `REFCURSOR`s do not require explicit declaration inside procedural code; instead, they get associated dynamically through function calls returning such references. #### Syntax Examples Here’s how each type gets defined: For standard cursors: ```sql BEGIN; DECLARE my_cursor SCROLL CURSOR FOR SELECT * FROM employees WHERE department_id = 50; FETCH ALL IN my_cursor; CLOSE my_cursor; COMMIT; ``` Using REFCURSORS involves creating stored procedures/functions that open cursors internally before passing back handles via OUT parameters. ```plpgsql CREATE OR REPLACE FUNCTION fetch_employee_data(dept integer, refcur refcursor) RETURNS refcursor AS $$ BEGIN OPEN refcur FOR SELECT * FROM employees WHERE department_id = dept; RETURN refcur; END; $$ LANGUAGE plpgsql; -- Calling the above-defined procedure would look something like this: BEGIN; SELECT fetch_employee_data(50, 'my_ref_cursor'); FETCH ALL IN "my_ref_cursor"; CLOSE "my_ref_cursor"; COMMIT; ``` #### Key Distinctions Between REF_CURSOR and Regular Cursors - **Scope**: Standard cursors exist only during transaction boundaries while `REFCURSOR`s persist beyond transactions since these act merely as pointers passed around between different parts of applications. - **Usage Contexts**: While direct manipulation (open/fetch/close) works fine for simple scripts or interactive sessions involving plain SQL commands, complex logic requiring dynamic queries benefits greatly from employing `REFCURSOR`. - **Portability Across Sessions/Connections**: Since `REFCURSOR` essentially serves as opaque identifiers pointing towards actual server-side resources allocated upon invocation, sharing across separate client connections becomes feasible without exposing underlying details about internal structures involved. #### Practical Implications on Application Design Choices Choosing whether to implement traditional cursors versus leveraging `REFCURSOR` depends largely on specific requirements surrounding data access patterns alongside architectural considerations regarding session management strategies employed throughout software stacks interfacing with relational databases managed under PostgreSQL environments. --related questions-- 1. How does Spring Batch address performance issues related to handling massive volumes of records? 2. What changes were made to alter column definitions specifically concerning storage characteristics in Oracle tables? 3. Can DelimitedLineTokenizer process CSV files containing quoted strings properly?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值