天天看點

oracle cusor遊标,oracle 遊标cursor

遊标

聲明    不占記憶體

打開    申請記憶體    多行多列

擷取    每次取一行,

關閉

隐式遊标的屬性:

SQL%ROWCOUNT    成功操作的行的數量

SQL%FOUND       發現複合條件的行傳回TRUE

SQL%NOTFOUND    沒有發現複合條件的行回TRUE

SQL%ISOPEN      遊标打開狀态(boolean)

練習 12:列印隐式遊标屬性

declare

v_count number;

begin

select count(*) into v_count from scott.emp;

dbms_output.put_line(chr(10)||'select return '||sql%rowcount||' rows!');

end;

begin

delete emp;

dbms_output.put_line(chr(10)||sql%rowcount||' rows deleted!');

--rollback;

end;

/

顯式遊标使用流程:

1.聲明 declare

cursor c_name is subquery;

2.打開 open

3.擷取 fetch

4.關閉 close

1.簡單遊标的使用

遊标是在open時使用記憶體的.擷取一次,記憶體中就少一行.

declare

cursor c1 is select ename,sal from scott.emp;

v_ename scott.emp.ename%type;

v_sal   scott.emp.sal%type;

begin

open c1 ;

loop

fetch c1 into v_ename,v_sal;

dbms_output.put_line(v_ename||' '||v_sal);

exit when c1%rowcount>5;

end loop;

close c1;

end;

/

declare

cursor c1

is

select employee_id,salary from employees;

v_id employees.employee_id%type;

v_sal employees.salary%type;

begin

open c1;

loop

if c1%notfound then

exit;

end if;

fetch c1 into v_id,v_sal;

dbms_output.put_line('Id is : '||v_id||'  '||'salary is : '||v_sal);

end loop;

close c1;

end;

2.使用遊标取表中的所有行所有列

declare

cursor c1 is select * from scott.dept;

v_deptno dept.deptno%type;

v_dname  dept.dname%type;

v_loc  dept.loc%type;

begin

open c1;

loop

fetch c1 into v_deptno,v_dname,v_loc;

exit when C1%NOTFOUND;

dbms_output.put_line(v_deptno||' '||v_dname||' '||v_loc);

end loop;

close c1;

end;

/

3.遊标for循環:使用for循環來代替loop循環

for循環中的變量根據in關鍵字後面的内容而決定變量的類型

如果in後面是數字 則變量是number類型标量變量

如果in後面是遊标 則變量是record類型複合變量

declare

cursor c1 is select ename,sal from scott.emp;

begin

for r1 in c1 loop

exit when c1%rowcount>5;

dbms_output.put_line(r1.ename||' '||r1.sal);

end loop;

end;

/

4. 使用遊标for循環 可以省略遊标的聲明

但這種遊标for循環不能使用隐式遊标屬性控制 要自己添加計數器

declare

v_num number := 0;

begin

for r1 in (select ename,sal from scott.emp) loop

-- dbms_output.put_line(SQL%rowcount);

v_num := v_num + 1;

exit when v_num > 5;

dbms_output.put_line(r1.ename||' '||r1.sal);

end loop;

end;

/

set serveroutput on

declare

v_number NUMBER:=1;

begin

for r1 in (select * from hr.employees) loop

--     dbms_output.put_line(sql%rowcount);

if v_number > 5 then

exit;

end if;

dbms_output.put_line(r1.last_name);

v_number := v_number+1;

end loop;

end;

/

5. 參數遊标

declare

cursor c1(v_deptno scott.emp.deptno%type)

is

select deptno,ename,sal from scott.emp where deptno=v_deptno;

begin

for r1 in c1 (&deptno) loop

dbms_output.put_line(r1.deptno||' '||r1.ename||' '||r1.sal);

end loop;

end;

/

declare

cursor c1(deptno hr.employees.department_id%type)

is

select last_name,department_id,salary from hr.employees where department_id=deptno;

begin

for emp_rec in c1(&did) loop

dbms_output.put_line('Name: '||emp_rec.last_name||' -- '||'Deptno: '||emp_rec.department_id||' -- '||

'Salary: '||emp_rec.salary);

end loop;

end;

/

練習 1: 基本loop循環+顯式遊标的使用

DECLARE

v_empno employees.employee_id%TYPE;

v_ename employees.last_name%TYPE;

CURSOR emp_cursor IS SELECT employee_id, last_name FROM employees; --聲明

BEGIN

OPEN emp_cursor; --打開

LOOP

FETCH emp_cursor INTO v_empno, v_ename; --擷取

exit when emp_cursor%rowcount>20;

DBMS_OUTPUT.PUT_LINE (TO_CHAR(v_empno)||' '|| v_ename);

END LOOP;

CLOSE emp_cursor; --關閉

END ;

/

練習 2: for循環+顯式遊标的使用

DECLARE

v_empno employees.employee_id%TYPE;

v_ename employees.last_name%TYPE;

CURSOR emp_cursor IS SELECT employee_id, last_name FROM employees;

BEGIN

OPEN emp_cursor;

FOR i IN 1..10 LOOP

FETCH emp_cursor INTO v_empno, v_ename;

DBMS_OUTPUT.PUT_LINE (TO_CHAR(v_empno)||' '|| v_ename);

END LOOP;

CLOSE emp_cursor;

END ;

/

遊标for循環:

declare

cursor emp_cursor is select rownum,employee_id,last_name from employees; --聲明

begin

for emp_record in emp_cursor loop --隐式打開隐式擷取

exit when emp_cursor%rowcount>23;

dbms_output.put_line(emp_record.rownum||' '||

emp_record.employee_id||' '||

emp_record.last_name);

end loop; --隐式關閉

end;

/

省略遊标定義:

begin

for r in (select last_name from employees) loop

dbms_output.put_line(r.last_name);

end loop;

end;

/

進階顯式遊标(帶參數的遊标):

練習 1:通過傳入不同的參數使打開遊标時取到不同的結果集

declare

cursor c1 (p_deptno number,p_job varchar2)

is

select empno,ename

from emp

where deptno=p_deptno

and job=p_job;

begin

Dbms_output.put_line('first fetch cursor!');

for r_c1 in c1(10,'MANAGER') loop --open cursor時傳入不同的實際參數得到不同的遊标上下文!

Dbms_output.put_line(r_c1.empno||' '||r_c1.ename);

end loop;

Dbms_output.put_line('second fetch cursor!');

for r_c1 in c1(20,'MANAGER') loop

Dbms_output.put_line(r_c1.empno||' '||r_c1.ename);

end loop;

Dbms_output.put_line('third fetch cursor!');

for r_c1 in c1(30,'MANAGER') loop

Dbms_output.put_line(r_c1.empno||' '||r_c1.ename);

end loop;

end;

/

練習:擷取每個部門前兩個雇員的資訊

擷取10部門前兩個人的資訊

declare

cursor c1 is select * from scott.emp

where deptno=10;

begin

for r1 in c1 loop

exit when c1%rowcount=3 or c1%notfound;

dbms_output.put_line(r1.ename||' '||r1.deptno);

end loop;

end;

/

使用替代變量取指定部門的前兩個人的資訊

declare

cursor c1 is select * from scott.emp

where deptno=&p_deptno;

begin

for r1 in c1 loop

exit when c1%rowcount=3 or c1%notfound;

dbms_output.put_line(r1.ename||' '||r1.deptno);

end loop;

end;

/

顯示所有部門的工資最高的前兩位員工的資訊;

declare

cursor dept

is

select distinct department_id from employees order by department_id;

cursor emp(deptno number)

is

select employee_id,department_id,last_name,salary from employees

where department_id = deptno order by salary;

begin

for d in dept loop

for e in emp(d.department_id) loop

exit when emp%rowcount > 2 or emp%notfound;

dbms_output.put_line(e.employee_id||' : ' ||e.department_id ||' : '||e.last_name||' : ' || e.salary);

end loop;

end loop;

end;

/

使用進階遊标代替替代變量

declare

cursor c1(p_deptno number) is select * from scott.emp

where deptno=p_deptno;

begin

for r1 in c1(10) loop

exit when c1%rowcount=3 or c1%notfound;

dbms_output.put_line(r1.ename||' '||r1.deptno);

end loop;

for r1 in c1(20) loop

exit when c1%rowcount=3 or c1%notfound;

dbms_output.put_line(r1.ename||' '||r1.deptno);

end loop;

for r1 in c1(30) loop

exit when c1%rowcount=3 or c1%notfound;

dbms_output.put_line(r1.ename||' '||r1.deptno);

end loop;

end;

/

使用循環嵌套簡化上面的代碼

declare

cursor c2 is select distinct deptno from scott.emp;

cursor c1(p_deptno number) is

select * from scott.emp

where deptno=p_deptno;

begin

for r2 in c2 loop

for r1 in c1(r2.deptno) loop

exit when c1%rowcount=3 or c1%notfound;

dbms_output.put_line(r1.ename||' '||r1.deptno);

end loop;

end loop;

end;

/

練習 2:将每個部門工資小于2000的職員工資漲10%

declare

cursor c1 is select deptno from scott.dept;

cursor c2 (p_deptno number,p_job varchar2)

is

select empno,ename,sal

from emp

where deptno=p_deptno

and job=p_job

for update of sal;

begin

for r_c1 in c1 loop

dbms_output.put_line('第'||c1%rowcount||'次擷取遊标c1' || '修改'||r_c1.deptno||'部門職員的工資');

for r_c2 in c2(r_c1.deptno,'CLERK') loop  

if r_c2.sal<2000 then

update scott.emp set sal=sal*1.1

where current of c2;  

end if;

end loop;

end loop;

end;

/

declare

cursor d1 is select distinct department_id from hr.e;

cursor e1(deptno hr.e.department_id%type)

is

select employee_id,salary from hr.e

where department_id=deptno;

begin

for d_info in d1 loop

for e_info in e1(d_info.department_id) loop

if e_info.salary 

update hr.e set salary=salary*1.1 where employee_id=e_info.employee_id;

end if;

end loop;

end loop;

end;

動态遊标:ref遊标

強類型的動态遊标

弱類型的動态遊标

強類型的動态遊标的樣例:

declare

type emp_record_type is record(

empno employees.employee_id%type,

ename employees.last_name%type);

type emp_cursor is REF CURSOR return emp_record_type;

v_employee emp_record_type;

v_empno employees.salary%type := &no;

v_emp_cursor emp_cursor;

begin

if v_empno > 150 then

open v_emp_cursor for

select employee_id,last_name from employees

where employee_id > 150;

else

open v_emp_cursor for

select employee_id,last_name from employees

where employee_id <= 150;

end if;

fetch v_emp_cursor into v_employee;

while v_emp_cursor%found loop

dbms_output.put_line(v_employee.empno||' : '||v_employee.ename);

fetch v_emp_cursor into v_employee;

end loop;

close v_emp_cursor;

end;

弱類型的動态遊标的樣例:

declare

type emp_record_type is record(

empno number,

ename varchar2(100));

type emp_cursor is REF CURSOR;

v_employee emp_record_type;

v_no employees.salary%type := &no;

v_emp_cursor emp_cursor;

v_dname varchar2(50);

begin

if v_no > 150 then

open v_emp_cursor for

select employee_id,last_name from employees

where employee_id > 150;

else

open v_emp_cursor for

select department_name from departments

where department_id <= 150;

end if;

if v_no > 150 then

fetch v_emp_cursor into v_employee;

while v_emp_cursor%found loop

dbms_output.put_line(v_employee.empno||' : '||v_employee.ename);

fetch v_emp_cursor into v_employee;

end loop;

close v_emp_cursor;

else

fetch v_emp_cursor into v_dname;

while v_emp_cursor%found loop

dbms_output.put_line(v_dname);

fetch v_emp_cursor into v_dname;

end loop;

close v_emp_cursor;

end if;

end;

有定義遊标結構(用return定義)的就是強類型 使用時必須按定義去取值 取值數量與定義比對

弱類型沒有定義遊标結構 随SQL傳回結果而建構遊标的結構 特點是靈活 完全依賴于SQL 容易出錯 SQL錯遊标就錯

參照類型(ref cursor 程式間傳遞結果集)

create or replace package ref_package

as

TYPE emp_record_type IS RECORD

(ename VARCHAR2(25),

job VARCHAR2(10),

sal NUMBER(7,2));

TYPE weak_ref_cursor IS REF CURSOR;--弱類型,不規定傳回值

TYPE strong_ref_cursor IS REF CURSOR return emp%rowtype;--強類型,規定傳回值

TYPE strong_ref2_cursor IS REF CURSOR return emp_record_type;--強類型,規定傳回值

end ref_package;

/

弱類型ref測試: 沒有指定遊标結構

create or replace procedure test_ref_weak

(p_deptno emp.deptno%type, p_cursor out ref_package.weak_ref_cursor)

is

begin

case p_deptno

when 10 then

open p_cursor for

select empno,ename,sal,deptno

from emp where deptno=p_deptno;

when 20 then

open p_cursor for

select *

from emp where deptno=p_deptno;

end case;

end;

/

var c refcursor

exec test_ref_weak(10,:c); --傳入不同形式參數,走不同分支,傳回不同結果集!

print c

exec test_ref_weak(20,:c);

print c

*oracle 9i 中定義了系統弱遊标類型 sys_refcursor  可以和任何查詢相關聯

create or replace procedure test_p

( p_deptno number, p_cursor out sys_refcursor)

is

begin

open p_cursor for

select *

from   emp

where  deptno = p_deptno;

end test_p;

/

create or replace function getemp

return sys_refcursor

as

emp_cursor sys_refcursor;

begin

open emp_cursor for select * from scott.emp;

return  emp_cursor;

end;

/

select getemp from dual;

強類型ref測試:查詢結構必須符合遊标傳回值結構,否則報錯:

PLS-00382: expression is of wrong type

create or replace procedure test_ref_strong

(p_deptno emp.deptno%type, p_cursor out ref_package.strong_ref_cursor)

is

begin

open p_cursor for

select *

from emp where deptno=p_deptno;

end test_ref_strong;

/

var c refcursor

exec test_ref_strong(10,:c);

create or replace procedure test_call

is

c_cursor ref_package.strong_ref_cursor;

r_emp  emp%rowtype;

begin

test_ref_strong(10,c_cursor);

loop

fetch c_cursor into r_emp;

exit when c_cursor%notfound;

dbms_output.put_line(r_emp.ename);

end loop;

close c_cursor;

end test_call;

/

exec test_call;

強類型ref測試:

create or replace procedure test_ref2_strong

(p_deptno emp.deptno%type, p_cursor out ref_package.strong_ref2_cursor)

is

begin

open p_cursor for

select ename,job,sal

from emp where deptno=p_deptno;

end test_ref2_strong;

/

var c refcursor

exec test_ref2_strong(10,:c);