日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

oracle存储过程的简单学习2

發布時間:2024/9/21 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 oracle存储过程的简单学习2 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.選用何種游標?

顯示游標分為:普通游標,參數化游標和游標變量三種。


create or replace procedure proc(p varchar2)

as

v_rownum number(10) := 1;

cursor c1 is select ename from emp where rownum = 1;

cursor c2 is select ename from emp where rownum = v_rownum;

cursor c3(p_rownum number) is select ename from emp where rownum = p_rownum;

type c_c is ref cursor;

c4 c_c;

v1 varchar2(20);


begin

?open c1;

?fetch c1 into v1;

?dbms_output.put_line('1.' || v1);

?close c1;


?open c2;

?fetch c2 into v1;

?dbms_output.put_line('2.' || v1);

?close c2;


?open c3(1);

?fetch c3 into v1;

?dbms_output.put_line('3.' || v1);

?close c3;


?open c4?for?select ename from emp where rownum = 1;

?fetch c4 into v1;

?dbms_output.put_line('4.' || v1);

?close c4;

end; ?


-- 調用

call ? proc(1);


-- 說明

cursor c1 is select ename from emp where rownum = 1;

這一句是定義了一個最普通的游標,把整個查詢已經寫死,調用時不可以作任何改變。


cursor c2 is select ename from emp where rownum = v_rownum;

這一句并沒有寫死,查詢參數由變量v_rownum來決定。需要注意的是v_rownum必須在這個游標定義之前聲明。


cursor c3(p_rownum number) is select ename from emp where rownum = p_rownum;

這一條語句與第二條作用相似,都是可以為游標實現動態的查詢。但是它進一步的縮小了參數的作用域范圍。但是可讀性降低了不少。


type c_c is ref cursor;

c4 c_c;

先定義了一個引用游標類型,然后再聲明了一個游標變量。

open c4 for select ename from emp where rownum = 1;

然后再用open for 來打開一個查詢。需要注意的是它可以多次使用,用來打開不同的查詢。

從動態性來說,游標變量是最好用的,但是閱讀性也是最差的。

注意,游標的定義只能用使關鍵字IS,它與AS不通用。



2.游標的循環策略

create or replace procedure proc1

as

cursor c1 is select ename,sal from emp ;

v1 varchar2(20);

v2 number(4);

begin

?open c1;

?if?c1%found?= true then

? ?dbms_output.put_line('found true ...');

?elsif?c1%found?= false then

? ?dbms_output.put_line('found false ...');

?else

? ?dbms_output.put_line('found null ...');

?end if;



?--1.loop循環

?loop

? ?fetch c1 into v1,v2;

? ?exit when c1%notfound;

? ?dbms_output.put_line('ename: ' || v1 || ',val:' || v2);

?end loop;

?dbms_output.put_line('--- loop end ...');

?close c1;


/*exit when語句一定要緊跟在fetch之后。必避免多余的數據處理。

處理邏輯需要跟在exit when之后。這一點需要多加小心。

循環結束后要記得關閉游標*/



?--2.while循環

?open c1;

fetch c1 into v1,v2;

?while c1%found loop

? ? ?dbms_output.put_line('ename: ' || v1 || ',val:' || v2);

? ? ?fetch c1 into v1,v2;

?end loop;

?close c1; ?

?dbms_output.put_line('---while end---'); ?


?/*

我們知道了一個游標打開后,必須執行一次fetch語句,游標的屬性才會起作用。

所以使用while 循環時,就需要在循環之前進行一次fetch動作。

而且數據處理動作必須放在循環體內的fetch方法之前。

循環體內的fetch方法要放在最后。否則就會多處理一次。這一點也要非常的小心。

總之,使用while來循環處理游標是最復雜的方法。

?*/



? --3.for循環

? for v in c1 loop

? ? v1 := v.ename;

? ? v2 := v.sal;

? ? dbms_output.put_line('ename: ' || v1 || ',val:' || v2);

? end loop;

? dbms_output.put_line('---for end---'); ?


/*

可見for循環是比較簡單實用的方法。

首先,它會自動open和close游標。解決了你忘記打開或關閉游標的煩惱。

其它,自動定義了一個記錄類型及聲明該類型的變量,并自動fetch數據到這個變量中。

我們需要注意v 這個變量無需要在循環外進行聲明,無需要為其指定數據類型。

它應該是一個記錄類型,具體的結構是由游標決定的。

這個變量的作用域僅僅是在循環體內。

把v看作一個記錄變量就可以了,如果要獲得某一個值就像調用記錄一樣就可以了。

如v.ename

由此可見,for循環是用來循環游標的最好方法。高效,簡潔,安全。

但遺憾的是,常常見到的卻是第一種方法。所以從今之后得改變這個習慣了

*/


end;


--調用

call proc1();


說明:

在打開一個游標之后,馬上檢查它的%found或%notfound屬性,

它得到的結果即不是true也不是false.而是null.

必須執行一條fetch語句后,這些屬性才有值。






3.select into不可忽視的問題

<1.>

我們知道在pl/sql中要想從數據表中向變量賦值,需要使用select into 子句。

但是它會帶動來一些問題,如果查詢沒有記錄時,會拋出no_data_found異常。

如果有多條記錄時,會拋出too_many_rows異常。

這個是比較糟糕的。一旦拋出了異常,就會讓過程中斷。

特別是no_data_found這種異常,沒有嚴重到要讓程序中斷的地步,可以完全交給由程序進行處理。 ?


eg1:

create or replace procedure proc2

AS

? ? ?v varchar2(20);

begin

?dbms_output.put_line('---開始:================');

select ename into v from emp where 1 = 0;

?dbms_output.put_line('---' || v);

exception

?when no_data_found then

? ? ?dbms_output.put_line('no data found...。。。');

end;



--調用

call proc2();



<2.>

說明:加exception → 這樣做換湯不換藥,程序仍然被中斷。

? ? ?可能這樣不是我們所想要的。

select into做為一個獨立的塊,在這個塊中進行異常處理 。

? 這是一種比較好的處理方式了。不會因為這個異常而引起程序中斷。

? 如下面的例子:

eg2:

create or replace procedure proc3

as

? ? ?v varchar2(20);

begin

begin

? ?dbms_output.put_line('---begin...========');

select ename into v from emp where 1 = 0;

? ?dbms_output.put_line('---' || v);

exception

? ?when no_data_found then

? ? ?dbms_output.put_line('no data found...give new value...');

? ? ?v := '';

end; ? ?

? dbms_output.put_line('v :' || v);

end;


-- 調用:

call proc3();



<3.>使用游標:這樣就完全的避免了no_data_found異常。完全交由程序員來進行控制了。

eg3:

create or replace procedure proc4

as

? ? ? v varchar2(20);

cursor c is select ename from emp where 1=0;

begin

?open c;

? ?dbms_output.put_line('---begin...========');

fetch c into v;

? ?dbms_output.put_line('v :' || v);

?close c;

? ?dbms_output.put_line('end...v :' || v);

end;


--

call proc4(); ? ?



4. ?too_many_rows 異常的問題。 ?

Too_many_rows 這個問題比起no_data_found要復雜一些。

給一個變量賦值時,但是查詢結果有多個記錄。


處理這種問題也有兩種情況:

<1>. 多條數據是可以接受的,也就是說從結果集中隨便取一個值就行。

這種情況應該很極端了吧,如果出現這種情況,也說明了程序的嚴謹性存在問題。

<2>. 多條數據是不可以被接受的,在這種情況肯定是程序的邏輯出了問題,也說是說原來根本就不會想到它會產生多條記錄。

對于第一種情況,就必須采用游標來處理,而對于第二種情況就必須使用內部塊來處理,重新拋出異常。

多條數據可以接受,隨便取一條,這個跟no_data_found的處理方式一樣,使用游標。

我這里僅說第二種情況,不可接受多條數據,但是不要忘了處理no_data_found哦。

這就不能使用游標了,必須使用內部塊。


需要注意的是一定要加上對no_data_found的處理,對出現多條記錄的情況則繼續拋出異常,讓上一層來處理。

總之對于select into的語句需要注意這兩種情況了。需要妥當處理啊。



eg4:

create or replace procedure proc5

as

? ? ? v varchar2(20);

begin

begin

select ename into v from emp where rownum < 5;

exception

? ? ?when no_data_found then

? ? ? ?v := null;

when too_many_rows then ?

? ? ? raise_application_error('-20000','對v賦值時,找到多行記錄!');

? ?end;

? ?dbms_output.put_line(v);

end; ?


--

call proc5(); ? ?




5.在存儲過程中返回結果集

見參考文章吧:→ 【http://www.cnblogs.com/chinafine/archive/2010/07/12/1776102.html】


------------------demo---------------------

create or replace procedure proc6(v1 varchar2,v2 number)

as

? ? ? total number(4) := 0;

? ? ? cursor c is select * from empa ;-- where 1=0;


begin

?if v1is not null??and v2?!= 0?then

? ?dbms_output.put_line('ok' || v1 || v2); ? ?

?elsif v1?is null?then

? ? ?dbms_output.put_line('v1 is null'); ?

-- elsif v1 = '' then

?-- ? ?dbms_output.put_line('v1 is kong...'); ?

?elsif v2 = 0 then

? ? ?dbms_output.put_line('v2 is 0'); ? ? ?

?end if;


for varObj in c loop

total := c%Rowcount ;

? ? dbms_output.put_line(c%Rowcount || 'empno :' || varObj.empno || 'ename: ' || varObj.ename || 'sal:' || varObj.sal);

? end loop;


? dbms_output.put_line('total:' || total);

? if?total <= 0?then

? ? ?dbms_output.put_line('total:' || total);

?raise_application_error('ORA-00973','rownumber is zero!');

? end if;

end;



--

call proc6(null,1);

call proc6('',1);-- ''會被認為是null

call proc6('tom',0);



==========================2013-12-17-說明===================

1.texit用來跳出循環 ?2.return跳出存儲過程.參考地址:http://sunrise-king.iteye.com/blog/391374

http://www.jb51.net/article/34230.htm




? ? ?本文轉自韓立偉 51CTO博客,原文鏈接:http://blog.51cto.com/hanchaohan/1340791,如需轉載請自行聯系原作者




總結

以上是生活随笔為你收集整理的oracle存储过程的简单学习2的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。