1. 程式人生 > 其它 >oracle儲存過程遊標的使用(批號分攤)

oracle儲存過程遊標的使用(批號分攤)

create or replace procedure pf_st2(in_billno in integer) is

begin

delete from kk_bal;

commit;

declare

--型別定義

cursor cur_orderdt is select goodsid,entid,billno,billsn,basenum,0 as temp

from saleorderdt where billno = in_billno;

--定義一個遊標變數

ccrec cur_orderdt%rowtype;

begin

--for迴圈

for ccrec in cur_orderdt loop

declare--型別定義

cursor cur_bal is select a.locatid,a.goodsid,a.ownerid,a.angleid,a.entid

,a.placenum - a.occupnum - nvl(c.basenum,0) as placenum

from anglebalance a

join batchcode b on a.goodsid = b.goodsid

and a.angleid = b.angleid and a.entid = b.entid

left join (select sum(basenum) as basenum,ownerid,goodsid,locatid,entid,angleid

from goodsoccu

group by ownerid,goodsid,locatid,entid,angleid

) c on a.locatid = c.locatid and a.goodsid = c.goodsid

and a.ownerid = c.ownerid and a.angleid = c.angleid

and a.entid = c.entid

where a.goodsid = ccrec.goodsid

order by b.valdate;

temp int default 0;

ccrbl cur_bal%rowtype;--定義遊標變數

begin

open cur_bal;--

開啟遊標

loop --loop迴圈

fetch cur_bal into ccrbl;--提取資料到ccrbl

exit when cur_bal%notfound;--沒有資料時退出

exit when temp >= ccrec.basenum;--資料分攤完成後退出

--批號分攤邏輯

/*

if 1=1 then

else if 2>1 then

else

end if;

*/

if ccrbl.placenum >= ccrec.basenum - temp then

insert into kk_bal(locatid,goodsid,ownerid,angleid,entid,num,billno,billsn)

values(ccrbl.locatid,ccrbl.goodsid,ccrbl.ownerid,ccrbl.angleid

,ccrbl.entid,ccrec.basenum - temp,ccrec.billno,ccrec.billsn);

commit;

temp := temp + ccrec.basenum;

else

insert into kk_bal(locatid,goodsid,ownerid,angleid,entid,num,billno,billsn)

values(ccrbl.locatid,ccrbl.goodsid,ccrbl.ownerid,ccrbl.angleid

,ccrbl.entid,ccrbl.placenum,ccrec.billno,ccrec.billsn);

commit;

temp := temp + ccrbl.placenum;

end if;

--dbms_output.put_line('測試');

--RAISE_APPLICATION_ERROR(-20991, '部門程式碼為空');--錯誤資訊提示,類似sql serverraiseerror

end loop; --loop迴圈結束

close cur_bal;--關閉遊標

end;

end loop;--for 迴圈結束

end;

end;

---------------------------------------相關文件說明

遊標-----記憶體中的一塊區域,存放的是select 的結果

遊標用來處理從資料庫中檢索的多行記錄(使用SELECT語句)。利用遊標,程式可以逐個地處理和遍歷一次檢索返回的整個記錄集。

為了處理SQL語句,Oracle將在記憶體中分配一個區域,這就是上下文區。這個區包含了已經處理完的行數、指向被分析語句的指標,整個區是查詢語句返回的資料行集。遊標就是指向上下文區控制代碼或指標。

兩種遊標:

一、顯示遊標(需要明確定義!)

顯示遊標被用於處理返回多行資料的SELECT 語句,遊標名通過CURSOR.IS 語句顯示地賦給SELECT 語句。

PL/SQL中處理顯示遊標所必需的四個步驟:

1)宣告遊標;CURSOR cursor_name IS select_statement

2)為查詢開啟遊標;OPEN cursor_name

3)取得結果放入PL/SQL變數中;

FETCH cursor_name INTO list_of_variables;

FETCH cursor_name INTO PL/SQL_record;

4)關閉遊標。CLOSE cursor_name

注意:在宣告遊標時,select_statement不能包含INTO子句。當使用顯示遊標時,INTO子句是FETCH語句的一部分。

1、 顯式遊標

select語句上 使用顯式遊標

能明確訪問結果集

for循環遊標

引數遊標

解決多行記錄的查詢問題

fetch遊標

二、隱式遊標

所有的隱式遊標都被假設為只返回一條記錄。

使用隱式遊標時,使用者無需進行宣告、開啟及關閉。PL/SQL隱含地開啟、處理,然後關掉遊標。

例如:

…….

SELECT studentNo,studentName

INTO curStudentNo,curStudentName

FROM StudentRecord

WHERE name=gg;

上述遊標自動開啟,並把相關值賦給對應變數,然後關閉。執行完後,PL/SQL變數curStudentNo,curStudentName中已經有了值。

2、 隱式遊標

單條sql語句所產生的結果集合

用關鍵字SQL表示隱式遊標

4個屬性 %rowcount 影響的記錄的行數 整數

%found 影響到了記錄 true

%notfound 沒有影響到記錄 true

%isopen 是否開啟 布林值 永遠是false

多條sql語句 隱式遊標SQL永遠指的是最後一條sql語句的結果

主要使用在update delete語句上

實際操作和例子:

(1)FOR循環遊標 (常用的一種遊標)

--<1>定義遊標

--<2>定義遊標變數

--<3>使用for迴圈來使用這個遊標

--前向遊標 只能往一個方向走

--效率很高

declare

--型別定義

cursor cc is select empno,ename,job,sal

from emp where job = 'MANAGER';

--定義一個遊標變數

ccrec cc%rowtype;

begin

--for迴圈

for ccrec in cc loop

dbms_output.put_line(ccrec.empno||'-'||ccrec.ename||'-'||ccrec.job||'-'||ccrec.sal);

end loop;

end;

(2) fetch遊標

--使用的時候 必須要明確的開啟和關閉

declare

--型別定義

cursor cc is select empno,ename,job,sal

from emp where job = 'MANAGER';

--定義一個遊標變數

ccrec cc%rowtype;

begin

--開啟遊標

open cc;

--loop迴圈

loop

--提取一行資料到ccrec

fetch cc into ccrec;

--判斷是否提取到值,沒取到值就退出

--取到值cc%notfound false

--取不到值cc%notfound true

exit when cc%notfound;

dbms_output.put_line(ccrec.empno||'-'||ccrec.ename||'-'||ccrec.job||'-'||ccrec.sal);

end loop;

--關閉遊標

close cc;

end;

遊標的屬性4

%notfound fetch是否提到資料 沒有true 提到false

%found fetch是否提到資料 有true 沒提到false

%rowcount 已經取出的記錄的條數

%isopen 布林值 遊標是否開啟

(3)引數遊標

按部門編號的順序輸出部門經理的名字

declare

--部門

cursor c1 is select deptno from dept;

--引數遊標c2,定義引數的時候

--只能指定型別,不能指定長度

--引數只能出現在select語句=號的右側

cursor c2(no number,pjob varchar2) is select emp.* from emp

where deptno = no and job=pjob;

c1rec c1%rowtype;

c2rec c2%rowtype;

--定義變數的時候要指定長度

v_job varchar2(20);

begin

--部門

for c1rec in c1 loop

--引數在遊標中使用

for c2rec in c2(c1rec.deptno,'MANAGER') loop

dbms_output.put_line(c1rec.deptno||'-'||c2rec.ename);

end loop;

end loop;

end;

(4)引用遊標/動態遊標

-- select語句是動態的

declare

--定義一個型別(ref cursor)弱型別

type cur is ref cursor;

--強型別(返回的結果集有要求)

type cur1 is ref cursor return emp%rowtype;

--定義一個ref cursor型別的變數

cura cur;

c1rec emp%rowtype;

c2rec dept%rowtype;

begin

DBMS_output.put_line('輸出員工') ;

open cura for select * from emp;

loop

fetch cura into c1rec;

exit when cura%notfound;

DBMS_output.put_line(c1rec.ename) ;

end loop ;

DBMS_output.put_line('輸出部門') ;

open cura for select * from dept;

loop

fetch cura into c2rec;

exit when cura%notfound;

DBMS_output.put_line(c2rec.dname) ;

end loop;

close cura;

end;

好的程式碼像粥一樣,都是用時間熬出來的