PLSQL遊標使用例項
一、定義:
遊標:指向查詢結果集的指標,指向哪一行,提取哪一行的資料(PLSQL的遊標預設指向結果集的第一行)
遊標的四個屬性
遊標變數 %found: 當最近一次讀入記錄成功時返回true
遊標變數 %notfound:同上 相反
遊標變數 %isopen:判斷遊標是否已經開啟
遊標變數 %rowcount:返回已從遊標中讀取的記錄數
隱示遊標:固定名稱sql
遊標的四個屬性
SQL%FOUND:如果操作有影響行,就為true,否則為false
SQL%NOTFOUND :求反
SQL%ISOPEN:在隱示遊標中,取值永遠為false
SQL%ROWCOUNT:操作影響的行數
必須在事務結束之前讀取遊標屬性,只能讀取最近的一次DML操作的遊標狀態
二、使用步驟
使用遊標分為4個步驟
1,宣告遊標 cursor 遊標變數 is 查詢語句
2,開啟遊標 open 遊標變數(不能重複開啟遊標)
3,提取資料 fetch 遊標變數 into 變數1,變數2,.
4,關閉遊標釋放系統資源 close 遊標變數
請參考以下例項:
(1)查詢輸出所有員工的編號,姓名,工資|
DECLARE
v_empid employees.employee_id%TYPE;
v_name employees.last_name%TYPE;
v_salary employees.salary%TYPE;
CURSOR emp_cursor IS
SELECT employee_id,last_name,salary
FROM employees
WHERE department_id = 90;
BEGIN
OPEN emp_cursor;
FETCH emp_cursor INTO v_empid ,v_name, v_salary;
dbms_output.put_line('編號'|| v_empid);
dbms_output.put_line('姓名'|| v_name);
dbms_output.put_line('工資'|| v_salary);
CLOSE emp_cursor;
END;
(2)查詢輸出所有員工的編號,姓名,工資
DECLARE
v_empid employees.employee_id%TYPE;
v_name employees.last_name%TYPE;
v_salary employees.salary%TYPE;
CURSOR emp_cursor IS
SELECT employee_id,last_name,salary
FROM employees
WHERE department_id = 90;
BEGIN
OPEN emp_cursor;
FETCH emp_cursor INTO v_empid ,v_name, v_salary;
WHILE emp_cursor%FOUND LOOP
dbms_output.put_line('編號'|| v_empid);
dbms_output.put_line('姓名'|| v_name);
dbms_output.put_line('工資'|| v_salary);
dbms_output.put_line('-------------------');
FETCH emp_cursor INTO v_empid ,v_name, v_salary;
END LOOP;
CLOSE emp_cursor;
END;
(3)查詢輸出所有員工編號,姓名,工資(記錄型別)
DECLARE
e employees%ROWTYPE;
CURSOR emp_cursor IS
SELECT *
FROM employees;
BEGIN
OPEN emp_cursor;
FETCH emp_cursor INTO e;
WHILE emp_cursor%FOUND LOOP
dbms_output.put_line('編號' || e.employee_id);
dbms_output.put_line('姓名' || e.last_name);
dbms_output.put_line('工資' || e.salary);
dbms_output.put_line('職務' || e.job_id);
dbms_output.put_line('入職日期' || e.hire_date);
dbms_output.put_line('-----------------------');
FETCH emp_cursor INTO e;
END LOOP;
CLOSE emp_cursor;
END;
(4)查詢輸出所有員工編號,姓名,工資(PLSQL表型別)
DECLARE
TYPE emp_table_type IS TABLE OF employees%ROWTYPE INDEX BY BINARY_INTEGER;
e emp_table_type;
CURSOR emp_cursor IS
SELECT * FROM employees;
BEGIN
OPEN emp_cursor;
FETCH emp_cursor BULK COLLECT
INTO e;
FOR i IN 1 .. e.count LOOP
dbms_output.put_line('編號' || e(i).employee_id);
dbms_output.put_line('姓名' || e(i).last_name);
dbms_output.put_line('工資' || e(i).salary);
dbms_output.put_line('----------------------------');
END LOOP;
CLOSE emp_cursor;
END;
(5)查詢輸出所有員工編號,姓名,工資(通過limit控制提取的資料量)
DECLARE
TYPE emp_table_type IS TABLE OF employees%ROWTYPE
INDEX BY BINARY_INTEGER;
e emp_table_type;
CURSOR emp_cursor IS
SELECT * FROM employees;
BEGIN
OPEN emp_cursor;
FETCH emp_cursor BULK COLLECT INTO e LIMIT 6 ;
FOR i IN 1..e.count LOOP
dbms_output.put_line('編號' || e(i).employee_id);
dbms_output.put_line('姓名' || e(i).last_name);
dbms_output.put_line('工資' || e(i).salary);
dbms_output.put_line('----------------------------');
END LOOP;
CLOSE emp_cursor;
END;
(6)查詢輸出某個部門的員工的編號,姓名,工資(引數化遊標)
DECLARE
v_empid employees.employee_id%TYPE;
v_name employees.last_name%TYPE;
v_salary employees.salary%TYPE;
CURSOR emp_cursor(p_deptid employees.employee_id%TYPE) IS
SELECT employee_id,last_name,salary
FROM employees
WHERE department_id = p_deptid;
BEGIN
OPEN emp_cursor(60);
LOOP
FETCH emp_cursor INTO v_empid,v_name,v_salary ;
EXIT WHEN emp_cursor%NOTFOUND;
dbms_output.put_line('編號:'||v_empid||'姓名:'||v_name||'工資:'||v_salary);
END LOOP;
CLOSE emp_cursor;
dbms_output.put_line('----------------------------');
OPEN emp_cursor(50);
LOOP
FETCH emp_cursor INTO v_empid,v_name,v_salary ;
EXIT WHEN emp_cursor%NOTFOUND;
dbms_output.put_line('編號:'||v_empid||'姓名:'||v_name||'工資:'||v_salary);
END LOOP;
CLOSE emp_cursor;
END;
(7)查詢輸出所有的員工編號,姓名,工資(遊標的for迴圈)
DECLARE
CURSOR emp_cursor IS
SELECT *
FROM employees;
BEGIN
FOR e IN emp_cursor LOOP
dbms_output.put_line('編號:'||e.employee_id||'姓名:'||e.last_name||'工資:'||e.salary);
END LOOP;
END;
(8)查詢輸出所有的員工編號,姓名,工資(帶引數)
DECLARE
CURSOR emp_cursor(p_depid employees.employee_id%TYPE)IS
SELECT *
FROM employees
WHERE department_id=p_depid;
BEGIN
FOR e IN emp_cursor(50) LOOP
dbms_output.put_line('編號:'||e.employee_id||'姓名:'||e.last_name||'工資:'||e.salary);
END LOOP;
END;
(9)查詢輸出所有的員工編號,姓名,工資(最精簡的寫法)
DECLARE
BEGIN
FOR e IN (SELECT * FROM employees) LOOP
dbms_output.put_line('編號:'||e.employee_id||'姓名:'||e.last_name||'工資:'||e.salary);
END LOOP;
END;
(10)輸出每個部門的部門編號,部門名稱以及這個部門的下屬員工的編號,姓名,工資
DECLARE
CURSOR dept_cursor IS
SELECT * FROM departments;
CURSOR emp_cursor(p_deptid NUMBER) IS
SELECT * FROM employees
WHERE department_id = p_deptid;
BEGIN
FOR d IN dept_cursor LOOP
dbms_output.put_line(d.department_id|| ' '||d.department_name);
FOR e IN emp_cursor(d.department_id) LOOP
dbms_output.put_line(' '||e.employee_id||', '||e.last_name|| ', '|| e.salary);
END LOOP;
END LOOP;
END;
(11)使用者輸入一個任意部門的編號,更新這個部門的員工工資
如果有員工更新,輸出‘更新成果,有XX個員工被更新’
如果沒有員工更新,輸出‘這個部門不存在,沒有任何員工被更新’
DECLARE
v_deptid NUMBER :=&input;
BEGIN
UPDATE employees
SET salary = salary +1
WHERE department_id = v_deptid;
IF SQL%FOUND THEN
dbms_output.put_line('更新成!有'||SQL%ROWCOUNT ||'個員工被更新');
ELSE
dbms_output.put_line('這個部門不存在,沒有任何員工被更新');
END IF;
COMMIT;
END;
(12)通過遊標去更新員工的工資,如果低於5000塊,則把工資改為5000
DECLARE
CURSOR emp_cursor IS
SELECT * FROM new_emp FOR UPDATE;
BEGIN
FOR e IN emp_cursor LOOP
IF e.salary<8300 THEN
UPDATE new_emp SET salary =8300 WHERE CURRENT OF emp_cursor;
END IF;
END LOOP;
END;
(13)通過遊標刪除工資=5000的員工
DECLARE
CURSOR emp_cursor IS
SELECT * FROM new_emp FOR UPDATE;
BEGIN
FOR e IN emp_cursor LOOP
IF e.salary = 6000 THEN
DELETE FROM new_emp WHERE CURRENT OF emp_cursor;
END IF;
END LOOP;
END;
(14)使用者輸入一個字母,輸入E,輸出所有員工姓名,如果輸出D,輸出所有部門名稱(遊標變數(動態遊標))
DECLARE
v_cmd CHAR(1):='&input';
v_name VARCHAR2(50);
//宣告自定義的遊標變數型別
TYPE c_type IS REF CURSOR;
//宣告變數
c c_type;
c SYS_REFCURSOR;--相當於 c_type is ref cursor
BEGIN
IF v_cmd = 'E' THEN
dbms_output.put_line('員工姓名');
OPEN c FOR
SELECT last_name FROM employees;
ELSIF v_cmd = 'D' THEN
dbms_output.put_line('部門名稱');
O PEN c FOR
SELECT department_name FROM departments;
ELSE
dbms_output.put_line('請正確輸入');
RETURN;
END IF;
LOOP
FETCH c
INTO v_name;
EXIT WHEN c%NOTFOUND;
dbms_output.put_line(v_name);
END ;