一 游標變量
與游標一樣,游標變量也是一個指向多行查詢結果集合中當前數據行的指針。但與游標不同的是,游標變量是動態的,而游標是靜態的。游標只能與指定的查詢相連,即固定指向一個查詢的內存處理區域,而游標變量則可與不同的查詢語句相連,它可以指向不同查詢語句的內存處理區域(但不能同時指向多個內存處理區域,在某一時刻只能與一個查詢語句相連),只要這些查詢語句的返回類型兼容即可。
1 聲明游標變量
TYPE ref_type_name IS REF CURSOR
[ RETURN return_type];
其中:ref_type_name為新定義的游標變量類型名稱;
return_type為游標變量的返回值類型,它必須為記錄變量。
在定義游標變量類型時,可以采用強類型定義和弱類型定義兩種。強類型定義必須指定游標變量的返回值類型,而弱類型定義則不說明返回值類型。
聲明一個游標變量的兩個步驟:
步驟一:定義一個REF CURSOU數據類型,如:
TYPE ref_cursor_type IS REF CURSOR;
步驟二:聲明一個該數據類型的游標變量,如:
cv_ref REF_CURSOR_TYPE;
例子:
創建兩個強類型定義游標變量和一個弱類型游標變量:
DECLARE
TYPE deptrecord IS RECORD(
Deptno departments.department_id%TYPE,
Dname departments.department_name%TYPE,
Loc departments.location_id%TYPE
);
TYPE deptcurtype IS REF CURSOR RETURN departments%ROWTYPE; --強類型
TYPE deptcurtyp1 IS REF CURSOR RETURN deptrecord; --強類型
TYPE curtype IS REF CURSOR; --弱類型
Dept_c1 deptcurtype;
Dept_c2 deptcurtyp1;
Cv curtype;
二 游標變量的操作
與游標一樣,游標變量操作也包括打開、提取和關閉三個步驟。
1 打開游標變量
打開游標變量時使用的是 OPEN…FOR 語句。格式為:
OPEN {cursor_variable_name | :host_cursor_variable_name}
FOR select_statement;
其中:cursor_variable_name為游標變量,host_cursor_variable_name為PL/SQL主機環境(如OCI: ORACLE Call Interface,Pro*c 程序等)中聲明的游標變量。
OPEN…FOR 語句可以在關閉當前的游標變量之前重新打開游標變量,而不會導致CURSOR_ALREAD_OPEN異常錯誤。新打開游標變量時,前一個查詢的內存處理區將被釋放。
2 提取游標變量數據
使用FETCH語句提取游標變量結果集合中的數據。格式為:
FETCH {cursor_variable_name | :host_cursor_variable_name}
INTO {variable [, variable]…| record_variable};
其中:cursor_variable_name和host_cursor_variable_name分別為游標變量和宿主游標變量名稱;variable和record_variable分別為普通變量和記錄變量名稱。
3 關閉游標變量
CLOSE語句關閉游標變量,格式為:
CLOSE {cursor_variable_name | :host_cursor_variable_name}
其中:cursor_variable_name和host_cursor_variable_name分別為游標變量和宿主游標變量名稱,如果應用程序試圖關閉一個未打開的游標變量,則將導致INVALID_CURSOR異常錯誤。
例子:
強類型參照游標變量類型
DECLARE
TYPE emp_job_rec IS RECORD(
Employee_id employees.employee_id%TYPE,
Employee_name employees.first_name%TYPE,
Job_title employees.job_id%TYPE
);
TYPE emp_job_refcur_type IS REF CURSOR RETURN emp_job_rec;
Emp_refcur emp_job_refcur_type ;
Emp_job emp_job_rec;
BEGIN
OPEN emp_refcur FOR
SELECT employees.employee_id, employees.first_name||employees.last_name, employees.job_id
FROM employees
ORDER BY employees.department_id;
FETCH emp_refcur INTO emp_job;
WHILE emp_refcur%FOUND LOOP
DBMS_OUTPUT.PUT_LINE(emp_job.employee_id||': '||emp_job.employee_name||' is a '||emp_job.job_title);
FETCH emp_refcur INTO emp_job;
END LOOP;
END;
弱類型參照游標變量類型
PROMPT
PROMPT 'What table would you like to see?'
ACCEPT tab PROMPT '(D)epartment, or (E)mployees:'
DECLARE
Type refcur_t IS REF CURSOR;
Refcur refcur_t;
TYPE sample_rec_type IS RECORD (
Id number,
Description VARCHAR2 (30)
);
sample sample_rec_type;
selection varchar2(1) := UPPER (SUBSTR ('&tab', 1, 1));
BEGIN
IF selection='D' THEN
OPEN refcur FOR
SELECT departments.department_id, departments.department_name FROM departments;
DBMS_OUTPUT.PUT_LINE('Department data');
ELSIF selection='E' THEN
OPEN refcur FOR
SELECT employees.employee_id, employees.first_name||' is a '||employees.job_id FROM employees;
DBMS_OUTPUT.PUT_LINE('Employee data');
ELSE
DBMS_OUTPUT.PUT_LINE('Please enter ''D'' or ''E''');
RETURN;
END IF;
DBMS_OUTPUT.PUT_LINE('----------------------');
FETCH refcur INTO sample;
WHILE refcur%FOUND LOOP
DBMS_OUTPUT.PUT_LINE(sample.id||': '||sample.description);
FETCH refcur INTO sample;
END LOOP;
CLOSE refcur;
END;
使用游標變量(沒有RETURN子句)
DECLARE
--定義一個游標數據類型
TYPE emp_cursor_type IS REF CURSOR;
--聲明一個游標變量
c1 EMP_CURSOR_TYPE;
--聲明兩個記錄變量
v_emp_record employees%ROWTYPE;
v_reg_record regions%ROWTYPE;
BEGIN
OPEN c1 FOR SELECT * FROM employees WHERE department_id = 20;
LOOP
FETCH c1 INTO v_emp_record;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_emp_record.first_name||'的雇佣日期是'
||v_emp_record.hire_date);
END LOOP;
--將同一個游標變量對應到另一個SELECT語句
OPEN c1 FOR SELECT * FROM regions WHERE region_id IN(1,2);
LOOP
FETCH c1 INTO v_reg_record;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_reg_record.region_id||'表示'
||v_reg_record.region_name);
END LOOP;
CLOSE c1;
END;
使用游標變量(有RETURN子句)
DECLARE
--定義一個與employees表中的這幾個列相同的記錄數據類型
TYPE emp_record_type IS RECORD(
f_name employees.first_name%TYPE,
h_date employees.hire_date%TYPE,
j_id employees.job_id%TYPE);
--聲明一個該記錄數據類型的記錄變量
v_emp_record EMP_RECORD_TYPE;
--定義一個游標數據類型
TYPE emp_cursor_type IS REF CURSOR
RETURN EMP_RECORD_TYPE;
--聲明一個游標變量
c1 EMP_CURSOR_TYPE;
BEGIN
OPEN c1 FOR SELECT first_name, hire_date, job_id
FROM employees WHERE department_id = 20;
LOOP
FETCH c1 INTO v_emp_record;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('雇員名稱:'||v_emp_record.f_name
||' 雇佣日期:'||v_emp_record.h_date
||' 崗位:'||v_emp_record.j_id);
END LOOP;
CLOSE c1;
END;