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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

oracle的存储过程

發(fā)布時(shí)間:2024/9/20 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 oracle的存储过程 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

用了兩年Oracle還沒(méi)寫(xiě)過(guò)存儲(chǔ)過(guò)程,真是十分慚愧,從今天開(kāi)始學(xué)習(xí)Oracle存儲(chǔ)過(guò)程,完全零起點(diǎn),爭(zhēng)取每日一篇學(xué)習(xí)筆記,可能開(kāi)始認(rèn)識(shí)的不全面甚至有錯(cuò)誤,但堅(jiān)持下來(lái)一定會(huì)有收獲。

1. 建立一個(gè)存儲(chǔ)過(guò)程

???????? create or replace PROCEDURE firstPro

???????? IS

???????? BEGIN

???????? DBMS_OUTPUT.PUT_LINE('Hello World!');

???????? END;

其中IS關(guān)鍵字替換為AS關(guān)鍵字結(jié)果不會(huì)出現(xiàn)任何變化,大多認(rèn)為他們是等同的,但也有一種說(shuō)法解釋為:一般PACKAGE 或者單獨(dú)的FUNCTION, PROCEDURE 都用AS,PACKAGE 中的FUNCTION, PROCEDURE 用IS。

???????? DBMS_OUTPUT.PUT_LINE('Hello World!'); 是一個(gè)輸出語(yǔ)句。

2. 執(zhí)行存儲(chǔ)過(guò)程

Oracle返回結(jié)果需要使用包,那么存儲(chǔ)過(guò)程似乎只能在數(shù)據(jù)庫(kù)中執(zhí)行或被其他調(diào)用,編程語(yǔ)言似乎并不能直接調(diào)用存儲(chǔ)過(guò)程返回?cái)?shù)據(jù),是否能執(zhí)行他有待研究。那么首先在數(shù)庫(kù)中執(zhí)行上面的存儲(chǔ)過(guò)程。

???????? BEGIN

???????? FirstPro();//注意有括號(hào)

???????? END;

?????? 運(yùn)行后輸出Hello World。

3. 下面寫(xiě)一個(gè)稍復(fù)雜的存儲(chǔ)過(guò)程,他定義了變量,進(jìn)行了運(yùn)算,輸出一個(gè)count操作所用的時(shí)間。

?????? CREATE OR REPLACE procedure testtime??

? ??? is??

? ??? n_start?? number;??

? ??? n_end?? number;?

? ??? samplenum number;

? ??? use_time number;

? ??? begin??

? ?????????? n_start:=dbms_utility.get_time;??

? ?????????? select count(*) into samplenum from emp;?

? ?????????? n_end:=dbms_utility.get_time;??

? ?????????? use_time:=?? n_end?? -?? n_start;??

? ?????????? dbms_output.put_line('This?? statement?? cost?? '|| use_time ||'?? miliseconds');??

? ??? end;??

4. 下面試驗(yàn)下怎么能給存儲(chǔ)過(guò)程賦值

?????? CREATE OR REPLACE procedure test(num in number) is

?????? begin

????????????? dbms_output.put_line('The input numer is:' || num);

?????? end ;

?????? 今天的就到這,明天將調(diào)用這個(gè)存儲(chǔ)過(guò)程,并試驗(yàn)一寫(xiě)對(duì)表的操作。

1. 首先把昨天帶參的存儲(chǔ)過(guò)程執(zhí)行一下

?????? declare

?????? n number;

?????? begin

????????????? n:=1;

????????????? test(num=>n);

?????? end;

?????? 注;在調(diào)用存儲(chǔ)過(guò)程時(shí),=>前面的變量為存儲(chǔ)過(guò)程的形參且必須于存儲(chǔ)過(guò)程中定義的一致,而=>后的參數(shù)為實(shí)際參數(shù)。當(dāng)然也不可以不定義變量保存實(shí)參,可寫(xiě)成如下形式:

?????? Begin

????????????? test(num=>1);

?????? end;

?????? 這樣我們就能更清楚得看到給存儲(chǔ)過(guò)程賦值的格式了。后面打算用存儲(chǔ)過(guò)程操作一些表,按照增刪改查的順序依次建立存儲(chǔ)過(guò)程。

2. 插入

?????? CREATE OR REPLACE

?????? procedure proc_test_Insert_Single(e_no in number,e_name in varchar ,s in varchar,d in ????????????? varchar)

?????? as

?????? begin

????????????? insert into emp (emp_id,emp_name,salary,birthday) values (e_no,e_name,s,d);

?????? end;

?????? 調(diào)用:

?????? DECLARE

????? ?i NUMBER;

????? ?n varchar(5);

? ?????????? s varchar(11);

? ??? d varchar(10);

?????? BEGIN

? ?????????? i:=10;

???????????? n := 'text11';

? ?????????? s:='3998';

? ?????????? d:='1998-02-02';

? ?????????? PROc_TEST_Insert_single(e_no => i,e_name=>n,s=>s,d=>d);

?????? END;

?????? 注:調(diào)用存儲(chǔ)過(guò)程聲明varchar時(shí),必須限定長(zhǎng)度,即斜體的部分不能少。同時(shí)如果給變量賦值時(shí)大于限定的長(zhǎng)度了,則會(huì)提示ORA-06502: PL/SQL: 數(shù)字或值錯(cuò)誤 :? 字符串緩沖區(qū)太小。

?

3. 更新

?????? create or replace procedure proc_test_update_Single(e_no in number,s in varchar)

?????? as

?????? begin

?????? ?????? UPDATE emp set salary =s where emp_id=e_no;

?????? end;

?????? 調(diào)用:

?????? DECLARE

? ?????????? n NUMBER;

? ?????????? s varchar(11);

?????? BEGIN

? ?????????? n := 2;

? ?????????? s:=3998;

? ?????????? PROc_TEST_UPdate_single(e_no => n,s=>s);

?????? END;

4. 號(hào)外,今天在開(kāi)發(fā)過(guò)程中正好有個(gè)數(shù)據(jù)庫(kù)更新操作可用存儲(chǔ)過(guò)程實(shí)現(xiàn),順便練習(xí)一下,需求是將一個(gè)表中的ID字段,查出來(lái)更新到另一個(gè)表中,兩個(gè)表通過(guò)b_bs和b_kgh關(guān)聯(lián)。存儲(chǔ)過(guò)程如下:

?????? create or replace procedure update_yygzdbid

?????? as

? ?????????? bs varchar(20);

? ?????????? kgh varchar(20);

? ?????????? bid number;

? ?????????? cursor c_db is select b_id,b_bs,b_kgh from pmdcdb;

?????? begin

? ?????????? for temp in c_db loop

????? ??? update yygz_db set b_id= temp.b_id where g_bs=temp.b_bs and g_bh=temp.b_kgh;

? ?????????? end loop;

?????? end;

?????? 運(yùn)行這個(gè)存儲(chǔ)過(guò)程:

?????? Begin

????????????? update_yygzdbid();

?????? end;

?????? 說(shuō)明:

?????? (1).在沒(méi)有參數(shù)的存儲(chǔ)過(guò)程定義時(shí)存儲(chǔ)過(guò)程的名稱不需要括號(hào),寫(xiě)成update_yygzdbid()是錯(cuò)誤的,

?????? (2). cursor c_db是定義一個(gè)游標(biāo),獲得查詢語(yǔ)句的結(jié)果集,

?????? (3). For temp in c_bd loop

???????????????????? Begin

???????????????????? End;

????????????? End loop

????????????? 是循環(huán)游標(biāo),其形式類似于C#中的foreach,? 獲得字段:temp.b_id。

5. 查詢

?????? 最后我們做一個(gè)查詢的存儲(chǔ)過(guò)程,能夠返回一個(gè)值,注意不是結(jié)果集,結(jié)果集是明天的目標(biāo)。

?????? CREATE OR REPLACE

?????? procedure proc_test_Select_Single(t in varchar,r out varchar )

?????? as

?????? begin

????????????? select salary into r from emp where emp_name=t;

?????? end;

?????? 這個(gè)存儲(chǔ)過(guò)程使用了2個(gè)參數(shù),并分別出現(xiàn)了IN和OUT,in代表輸入,out用于輸出,從下面的語(yǔ)句也可以看到salary寫(xiě)入到變量r中了,這個(gè)r我們可以在調(diào)用存儲(chǔ)過(guò)程后得到。

?????? 這時(shí)編譯后會(huì)出現(xiàn)一個(gè)Warning(1,48): PLW-07203: 使用 NOCOPY 編譯器提示可能對(duì)參數(shù) 'R' 有所幫助,那么nocopy是什么呢,nocopy主要是針對(duì)in|out record/index-by table/varray/varchar2提高效率使用的, 對(duì)于number使用nocopy與否基本沒(méi)有影響.所以在'enable:performance'情況下不會(huì)對(duì)number提示warning.

?????? 我們把第一行改為:procedure proc_test_Select_Single(t in varchar,r out nocopy varchar )

現(xiàn)在即使對(duì)in的varchar沒(méi)有使用nocopy也不會(huì)提示警告,

?????? DECLARE

? ?????????? T varchar2(4);

? ?????????? R VARCHAR2(4);

?????? BEGIN

? ?????????? T := 'zz';

? ?????????? PROC_TEST_SELECT_SINGLE(T => T,R => R );

? ?????????? DBMS_OUTPUT.PUT_LINE('R = ' || R);

?????? END;

?????? 運(yùn)行后即可在輸出中看到結(jié)果了。

三、

1. 今天我們首先寫(xiě)一個(gè)漲工資的存儲(chǔ)過(guò)程,給每個(gè)低于5k工資的人漲點(diǎn)錢(qián)。

?????? CREATE OR REPLACE PROCEDURE p_test(forRaise in number)

?????? as

??? begin

????? for v_emp in (select * from emp) loop

????? ??? if(v_emp.salary<'5000') then

??????? update emp set salary =(v_emp.salary+forRaise) where emp_id=v_emp.emp_id;

??????? end if;

????? end loop;

?????? end;

?????? 調(diào)用:

?????? DECLARE

? ?????????? FORRAISE NUMBER;

?????? BEGIN

? ?????????? FORRAISE :=1;

????????????? P_TEST(FORRAISE => FORRAISE);

?????? END;

?????? 這里要注意兩個(gè)地方:

(1)?????? 循環(huán)中begin和end不是必須的

(2)?????? 這里增加了if語(yǔ)句,其格式比較簡(jiǎn)單就不細(xì)說(shuō)了。

(3)?????? 這里沒(méi)有定義游標(biāo),在游標(biāo)的位置直接用select語(yǔ)句代替了。

?????? 2. 這里順便介紹下另外一種循環(huán),while循環(huán),實(shí)現(xiàn)同樣的功能

????????????? CREATE OR REPLACE PROCEDURE p_test(forRaise in number)

????????????? as

???????????????????? cursor c is select * from emp;

???????????????????? v_row emp%rowtype;

????????????? begin

? ?????????? open c;

? ?????????? fetch c into v_row;

? ?????????? while? c%found Loop

??? ????????????? if(v_row.salary<'5000') then

????? ????????????????? update emp set salary =(v_row.salary+forRaise) where emp_id=v_row.emp_id;

??? ????????????? end if;

??? ?????? fetch c into v_row;

? ?????????? end loop;

? ?????????? close c;

????????????? end;

????????????? 說(shuō)明:

(1)?????? 這里需要定義一個(gè)游標(biāo),還要定義一個(gè)emp%rowtype類型的變量,%前面是表名,后面表示這個(gè)表的一行,

(2)?????? 在使用游標(biāo)前還要顯示的打開(kāi)游標(biāo),并將其賦值到row中,使用后關(guān)閉游標(biāo)。

(3)?????? C%found表示只有row中有值的時(shí)候才會(huì)進(jìn)行循環(huán)。

(4)?????? 經(jīng)過(guò)對(duì)比發(fā)現(xiàn)于while循環(huán)相比,for循環(huán)更像是C#中的foreach,使用起來(lái)方便很多。

(5)?????? 另從9i開(kāi)始提供的動(dòng)態(tài)游標(biāo)類型sys_refcursor,以前的版本必須要先創(chuàng)建一個(gè)ref cursor的類型,現(xiàn)在多個(gè)

  • ?????? 現(xiàn)在我們使用程序調(diào)用下漲工資的存儲(chǔ)過(guò)程,這個(gè)存儲(chǔ)過(guò)程是沒(méi)有返回值的。
  • OracleConnection conn = new OracleConnection();?? //創(chuàng)建一個(gè)新連接

    conn.ConnectionString = "Data Source='ds';user id='id ';password='pwd';"; OracleCommand cmd = new OracleCommand("P_TEST", conn);

    cmd.CommandType = CommandType.StoredProcedure;

    OracleParameter p1 = new OracleParameter("forRaise", OracleType.UInt32);

    p1.Value = 1;

    p1.Direction = System.Data.ParameterDirection.Input;

    cmd.Parameters.Add(p1);

    conn.Open();

    int r=cmd.ExecuteNonQuery();

    ??? conn.Close();

    ??? 這樣我們就可以給員工漲工資了,說(shuō)明:

    (1)???????? 雖然給多個(gè)人漲了公司,但r的值是1,他只調(diào)用了1個(gè)存儲(chǔ)過(guò)程,或者說(shuō)受影響的只是1個(gè)。

    (2)???????? 參數(shù)P1的名字必須和存儲(chǔ)過(guò)程中的一樣否則會(huì)提示:調(diào)用 'P_TEST' 時(shí)參數(shù)個(gè)數(shù)或類型錯(cuò)誤。

  • ??????? 現(xiàn)在我們?cè)囍鴱拇鎯?chǔ)過(guò)程中得到點(diǎn)結(jié)果吧,我先看看我給幾個(gè)人漲了工資,我每個(gè)月一共要多付多少錢(qián)了。
  • ???????? 改動(dòng)存儲(chǔ)過(guò)程:

    ???????? CREATE OR REPLACE PROCEDURE p_test(forRaise in number,res out number)

    ???????? is

    ??? begin

    ????? res:=0;

    ????? for v_emp in (select * from emp) loop

    ????? ?????? if(v_emp.salary<'4000') then

    ????????? update emp set salary =(v_emp.salary+forRaise) where emp_id=v_emp.emp_id;

    ????????? res:=res+1;

    ??????? end if;

    ????? end loop;

    ???????? end;

    ???????? 增加了一個(gè)out 的number型,記錄改動(dòng)的次數(shù)。然后相應(yīng)的調(diào)整C#程序,獲得這個(gè)改動(dòng)的次數(shù)。

    OracleCommand cmd = new OracleCommand("P_TEST", conn);

    cmd.CommandType = CommandType.StoredProcedure;

    OracleParameter p1 = new OracleParameter("forRaise", OracleType.UInt32);

    p1.Value = 4;

    p1.Direction = System.Data.ParameterDirection.Input;

    OracleParameter p2 = new OracleParameter("res", OracleType.UInt32);

    p2.Value = 10;

    p2.Direction = System.Data.ParameterDirection.Output;

    cmd.Parameters.Add(p1);

    cmd.Parameters.Add(p2);

    conn.Open();

    int r=cmd.ExecuteNonQuery();

    ?conn.Close();

    MessageBox.Show(“你已經(jīng)給:”+p2.Value.ToString()+“人漲了工資”);

    好了,今天就到這,下次返回?cái)?shù)據(jù)集。

    Oracle使用存儲(chǔ)過(guò)程返回結(jié)果集必須使用包,包包括包頭和包體兩部分,包頭是定義部分包體是具體的實(shí)現(xiàn)

    ??? 包頭:

    ??? CREATE OR REPLACE

    ??? PACKAGE pkg_test_select_mul

    ??? AS

    ??? TYPE myrctype IS REF CURSOR;?

    ??? PROCEDURE proc(s number, res OUT myrctype);

    END pkg_test_select_mul;

    ??? 這里定義了個(gè)一個(gè)游標(biāo)和一個(gè)存儲(chǔ)過(guò)程。

    ??? 包體:

    ??? CREATE OR REPLACE

    ??? PACKAGE BODY "PKG_TEST_SELECT_MUL" AS

    ??? ??? PROCEDURE proc(s in number,res OUT myrctype)

    ??? ??? IS???????

    ??? ??? BEGIN???????

    ????????? OPEN res FOR Select? emp_id,emp_Name, salary,birthday From ?? ??? ??? emp where salary> s;

    ??? ??? END proc;???

    ??? END PKG_TEST_SELECT_MUL;

    ??? 這里實(shí)現(xiàn)里包頭中定義的存儲(chǔ)過(guò)程,實(shí)現(xiàn)了查詢工資超過(guò)一定數(shù)額的人的信息,而游標(biāo)則不用重新定義了,且存儲(chǔ)過(guò)程中的參數(shù)名必須和定義中的一致。下面我們看一下C#的調(diào)用部分。

    ??? OracleConnection conn = new OracleConnection();?? //創(chuàng)建一個(gè)新連接

    ??????????? conn.ConnectionString = "Data Source='" + "MyTest" + "';user id='" + "azkaser" + "';password='" + "sti" + "';";?? //寫(xiě)連接串?

    ??????????? OracleCommand cmd = new OracleCommand("PKG_TEST_SELECT_MUL.proc", conn);

    ??????????? cmd.CommandType = CommandType.StoredProcedure;

    ??????????? OracleParameter p1 = new OracleParameter("s", OracleType.Number);

    ??????????? p1.Value = 4000;

    ??????????? p1.Direction = ParameterDirection.Input;

    ??????????? OracleParameter p2 = new OracleParameter("res", OracleType.Cursor);

    ??????????? p2.Direction = ParameterDirection.Output;

    ?

    ??????????? cmd.Parameters.Add(p1);

    ??????????? cmd.Parameters.Add(p2);

    ??????????? conn.Open();

    ??????????? OracleDataReader myReader = cmd.ExecuteReader();

    ??????????? while (myReader.Read())

    ??????????? {

    ??????????????? MessageBox.Show(myReader.GetString(1));

    ??????????? }

    ?????????? ?conn.Close();

    ??? 程序?qū)⒌玫降慕Y(jié)果存放在OracleDataReader的對(duì)象中。

    ??? 到此簡(jiǎn)單的Oracle存儲(chǔ)過(guò)程操作就此就全部完成了,程序?qū)懙暮茈S便,目的就是實(shí)現(xiàn)功能,將來(lái)有時(shí)間會(huì)進(jìn)一步

    總結(jié)

    以上是生活随笔為你收集整理的oracle的存储过程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。