Oracle 數據庫(十四)—— Oracle 存儲過程、函數

一、Oracle 存儲過程

存儲過程是一種命名的PL/SQL程序塊,它既可以沒有參數,也可以有若干個輸入、輸出參數,甚至可以有多個既作輸入又作輸出的參數,但它通常沒有返回值。存儲過程被保存在數據庫中,它不可以被SQL語句直接執行或調用,只能通過EXECUT命令執行或在PL/SQL程序塊內部被調用。由於存儲過程是已經編譯好的代碼,所以在被調用或引用時,其執行效率非常高。

1.1 創建存儲過程

1.1.1 創建存儲過程介紹
創建一個存儲過程與編寫一個普通的PL/SQL程序塊有很多相似的地方,比如,兩者都包括聲明部分、執行部分和異常處理三部分。但這二者之間的實現細節還是有很多差別的,比如創建存儲過程需要使用PROCEDURE關鍵字,在關鍵字後面就是過程名和參數列表;創建存儲過程不需要使用DECLARE關鍵字,而是使用CREATE或REPLACE關鍵字

1.1.2 存儲過程語法格式

create [or replace] procedure pro_name [(parameter1[,parameter2])] is|as
begin
    plsql_sentences;
[exception]
    [dowith _ sentences;]
end [pro_name];
  • pro_name:存儲過程的名稱,如果數據庫中已經存在了此名稱,則可以指定“or replace”關鍵字,這樣新的存儲過程將覆蓋掉原來的存儲過程。
  • parameter1:存儲過程的參數。
    若是輸入參數,則需要在其後指定in關鍵字;
    若是輸出參數,則需要在其後面指定out關鍵字。
    在in或out關鍵字的後面是參數的數據類型,但不能指定該類型的長度。
  • plsql_sentences:PL/SQL語句,它是存儲過程功能實現的主體。
  • dowith _ sentences:異常處理語句,也是PL/SQL語句,這是一個可選項。

上面語法中的parameter1是存儲過程被調用/執行時用到的參數,而不是存儲過程內定義的內部變量,內部變量要在is|as關鍵字後面定義,並使用分號;結束。

1.1.3 創建存儲過程示例
示例

create procedure pro_insertDept is
begin
	insert into dept values(77,'市場拓展部','JILIN');     --插入數據記錄
	commit;                                               --提交數據
	dbms_output.put_line('插入新記錄成功!');             --提示插入記錄成功
end pro_insertDept;
/

執行結果
在這裏插入圖片描述
在存儲過程中,is關鍵字也可以用as關鍵字來代替。

如果在當前模式下,數據庫中已經存在pro_insertDept這個存儲過程,而要運行上述代碼,有兩種方法:
第一種就是修改現有的存儲過程名稱,重新創建,這個不必過多解釋;
第二種就是使用or replace關鍵字覆蓋掉原有的存儲過程。

or replace示例

create or replace procedure pro_insertDept is
begin
	insert into dept values(99,'市場拓展部','BEIJING');   --插入數據記錄
	commit;                                               --提交數據
	dbms_output.put_line('插入新記錄成功!');             --提示插入記錄成功
end pro_insertDept;
/

執行結果
在這裏插入圖片描述
從運行結果中可以看出,無論在數據庫中是否存在名稱爲pro_insertDept的存儲過程,上面的代碼都可以成功地創建一個存儲過程。如果在創建存儲過程中發生了錯誤,則用戶還可以使用“show error”命令來查看錯誤信息。

1.1.4 調用存儲過程
上面兩個存儲過程中的主體代碼都可以實現向數據表dept中插入一行記錄,但主體代碼insert語句僅僅是被編譯了,並沒有被執行。若要執行這個INSERT語句,則需要在SQL*Plus環境中使用EXECUTE命令來執行該存儲過程,或者在PL/SQL程序塊中調用該存儲過程。 使用EXECUTE命令的執行方式比較簡單,只需要在該命令後面輸入存儲過程名即可。
使用EXECUTE命令調用存儲過程

execute pro_insertDept;

在一個PL/SQL程序塊中調用某個存儲過程

set serverout on
begin
	pro_insertDept;
end;
/

1.2 存儲過程參數

1.2.1 存儲過程參數
Oracle爲了增強存儲過程的靈活性,提供向存儲過程傳入參數的功能。參數是一種向程序單元輸入和輸出數據的機制,存儲過程可以接受多個參數,參數模式包括IN、OUT和IN OUT三種。

1.2.2 IN模式參數
這是一種輸入類型的參數,參數值由調用方傳入,並且只能被存儲過程讀取。這種參數模式是最常用的,也是默認的參數模式,關鍵字IN位於參數名稱之後。

示例

create or replace procedure insert_dept(
	num_deptno in number,                    --定義 in 模式的變量,它存儲部門編號
	var_ename in varchar2,                   --定義 in 模式的變量,它存儲部門名稱
	var_loc in varchar2) is
begin
	insert into dept
	values(num_deptno,var_ename,var_loc);    --向 dept 表中插入記錄
	commit;                                  --提交數據庫
end insert_dept;
/

執行結果
在這裏插入圖片描述
需要注意的是:參數的類型不能指定長度。在調用或執行這種in模式的存儲過程時,用戶需要向存儲過程中傳遞若干參數值,以保證執行部分(即begin部分)有具體的數值參與數據操作。

向存儲過程傳入參數可以有如下3種方式。
(1)指定名稱傳遞
指定名稱傳遞是指在向存儲過程傳遞參數時需要指定參數名稱,即參數名稱在左側,中間是賦值符號“=>”,右側是參數值,其語法格式如下:

pro_name(parameter1=>value1[,parameter2=>value2])
  • parameter1:參數名稱。在傳遞參數值時,這個參數名稱與存儲過程中定義的參數順序無關。
  • value1:參數值。在它的左側不是常規的賦值符號“=”,而是一種新的賦值符號“=>”,需要注意參數值的類型要與參數的定義類型兼容。

指定名稱傳遞示例

begin
insert_dept(var_ename=>'採購部',var_loc=>'成都',num_deptno=>15);
end;
/

執行結果
在這裏插入圖片描述
(2)按位置傳遞
指定名稱傳遞參數雖然直觀易讀,但也有缺點,就是參數過多時,會顯得代碼冗長,反而變得不容易閱讀。這樣用戶就可以採取按位置傳遞參數,採用這種方式時,用戶提供的參數值順序必須與存儲過程中定義的參數順序相同。

按位置傳遞示例

begin
	insert_dept(28,'工程部','洛陽');
end;
/

執行結果
在這裏插入圖片描述

(3)混合方式傳遞
混合方式就是將前兩種方式結合到一起,這樣就可以兼顧二者的優點。

混合方式傳遞示例

exec insert_dept(38,var_loc=>'濟南',var_ename=>'測試部');

執行結果
在這裏插入圖片描述

1.2.3 OUT模式參數
這是一種輸出類型的參數,表示這個參數在存儲過程中已經被賦值,並且這個參數值可以傳遞到當前存儲過程以外的環境中,關鍵字OUT位於參數名稱之後。

create or replace procedure select_dept(
	num_deptno in number,                              --定義 in 模式變量,要求輸入部門編號
	var_dname out dept.dname%type,                     --定義 out 模式變量,可以存儲部門名稱並輸出
	var_loc out dept.loc%type) is
begin
	select dname,loc
	into var_dname,var_loc
	from dept
	where deptno= num_deptno;                          --檢索某個部門編號的部門信息
exception
	when no_data_found then                            --若 select 語句無返回記錄
		dbms_output.put_line('該部門編號的不存在');    --輸出信息
end select_dept;
/

執行結果
在這裏插入圖片描述
在上面的存儲過程(即select_dept)中,定義了兩個OUT參數,由於存儲過程要通過out參數返回值,所以當調用或執行這個存儲過程時,都需要定義變量來保存這兩個OUT參數值。
(1)在PL/SQL塊中調用OUT模式的存儲過程。
這種方式需要在PL/SQL塊的DECLARE部分定義與存儲過程中OUT參數兼容的若干變量。

示例

set serverout on
declare
	var_dname dept.dname%type;                           --聲明變量,對應過程中的 out 模式的 var_dname
	var_loc dept.loc%type;                               --聲明變量,對應過程中的 out 模式的 var_loc
begin
	select_dept(99,var_dname,var_loc);                   --傳入部門編號,然後輸出部門名稱和位置信息
	dbms_output.put_line(var_dname||'位於:'||var_loc);  --輸出部門信息
end;
/

執行結果
在這裏插入圖片描述
在上面的代碼中,把聲明的兩個變量傳入到存儲過程中,當存儲過程執行時,其中的out參數會被賦值,當存儲過程執行完畢,OUT參數的值會在調用處返回,這樣定義的兩個變量就可以得到out參數被賦予的值,最後這兩個值就可以在存儲過程外任意使用了。

(2)使用EXEC命令
使用EXEC命令執行OUT模式的存儲過程,需要在SQL*Plus環境中使用variable關鍵字聲明兩個變量,用以存儲OUT參數的返回值。

variable var_dname varchar2(50);
variable var_loc varchar2(50);
exec select_dept(15,:var_dname,:var_loc);

執行結果
在這裏插入圖片描述
但是通過上面代碼的執行結果,用戶看不到變量var_dname和var_loc的值,這時用戶可以通過PRINT命令或SELECT語句來輸出變量的值。

(3)使用PRINT命令打印輸出綁定的變量值。

print var_dname var_loc;

執行結果

(4)使用SELECT語句檢索綁定的變量值。

select :var_dname,:var_loc
from dual;

執行結果
在這裏插入圖片描述
如果在存儲過程中聲明瞭out模式的參數,則在執行存儲過程時,必須爲out參數提供變量,以便接收out參數的返回值,否則,程序執行後將出現錯誤。

1.2.4 IN OUT模式參數
在執行存儲過程時,IN參數不能夠被修改,它只能根據被傳入的指定值(或是默認值)爲存儲過程提供數據,而OUT類型的參數只能等待被賦值,而不能像IN參數那樣爲存儲過程本身提供數據。

但IN OUT參數可以兼顧其他兩種參數的特點,在調用存儲過程時,可以從外界向該類型的參數傳入值;在執行完存儲過程之後,可以將該參數的返回值傳給外界。

示例

create or replace procedure pro_square(
	num in out number,              --計算它的平方或平方根,這是一個“in out”參數
	flag in boolean) is             --計算平方或平方根的標識,這是一個“in”參數
	i int := 2;                     --表示計算平方,這是一個內部變量
begin
	if flag then                    --若爲 true
		num := power(num,i);        --計算平方
	else
		num := sqrt(num);           --計算平方根
	end if;
end;
/

執行結果
在這裏插入圖片描述
在上面的存儲過程中,定義一個IN OUT參數,該參數在存儲過程被調用時會傳入一個數值,然後與另外一個IN參數相結合來判斷所進行的運算方式(平方或平方根),最後將計算後的平方或平方根再保存到這個IN OUT參數中。

調用存儲過程pro_square

set serverout on
declare
	var_number number;                --存儲要進行運算的值和運算後的結果
	var_temp number;                  --存儲要進行運算的值
	boo_flag boolean;                 --平方或平方根的邏輯標記
begin
	var_temp := 3;                     --變量賦值
	var_number := var_temp;
	boo_flag := false;                --false 表示計算平方根;true 表示計算平方
	pro_square(var_number,boo_flag);      --調用存儲過程
	if boo_flag then
		dbms_output.put_line(var_temp ||'的平方是:'||var_number);--輸出計算結果
	else
		dbms_output.put_line(var_temp ||'平方根是:'||var_number);
	end if;
end;
/

執行結果

從上面的例子中可以看出,變量var_number在調用存儲過程之前是3,而存儲過程執行完畢之後,該變量的值變爲其平方根,這因爲該變量作爲存儲過程的IN OUT參數被傳入和返回。

1.3 IN 參數的默認值

1.3.1 介紹
前面講到的IN參數的值都是在調用存儲過程時傳入的,實際上,Oracle支持在聲明IN參數的同時給其初始化默認值,這樣在存儲過程調用時,如果沒有向IN參數傳入值,則存儲過程可以使用默認值進行操作。

1.3.2 示例

create or replace procedure insert_dept(
	num_deptno in number,                                --定義存儲部門編號的 IN 參數
	var_dname in varchar2 default '綜合部',               --定義存儲部門名稱的 IN 參數,並初始化默認值
	var_loc in varchar2 default '北京') is
begin
	insert into dept values(num_deptno,var_dname,var_loc);--插入一條記錄
end;
/

執行結果
在這裏插入圖片描述
在上面的存儲過程中,IN參數var_dname和var_loc都有默認值,所以在調用insert_dept存儲過程時,可以不向這兩個參數傳入值,而是使用其默認值(當然也可以傳入值)。

當給一些帶有默認值的參數傳入值,而對另一些帶默認值的參數不傳值,並且傳值的順序不固定時,建議使用“指定名稱傳遞”的方式傳值,這樣程序就不會出現混亂,示例如下:
在這裏插入圖片描述
在上面的代碼中,存儲過程insert_dept有3個IN參數,這裏只傳入兩個參數(num_deptno和var_loc)的值,而var_dname參數的值使用默認值“綜合部”。

1.4 刪除存儲過程

當一個過程不再被需要時,要將此過程從內存中刪除,以釋放相應的內存空間,可以使用下面的語句來完成

DROP PROCEDURE count_num;

示例

DROP PROCEDURE insert_dept;

在這裏插入圖片描述
當一個存儲過程已經過時,想重新定義時,不必先刪除再創建,而只需在CREATE語句後面加上OR REPLACE關鍵字即可。如下所示:

CREATE OR REPLACE PROCEDURE insert_dept

二、Oracle 函數

函數一般用於計算和返回一個值,可以將經常需要使用的計算或功能寫成一個函數。函數的調用是表達式的一部分,而過程的調用是一條PL/SQL語句。 函數與過程在創建的形式上有些相似,也是編譯後放在內存中供用戶使用,只不過調用函數時要用表達式,而不像過程只需要調用過程名。另外,函數必須要有一個返回值,而過程則沒有。

2.1 創建函數

2.1.1 創建函數語法格式
函數的創建語法與存儲過程比較類似,它也是一種存儲在數據庫中的命名程序塊,函數可以接受零或多個輸入參數,並且函數必須有返回值(這一點存儲過程是沒有的),其定義語法格式如下:

create [or replace] function fun_name[(parameter1[,parameter2]) return data_type is
    [inner_variable]
begin
    plsql_ sentence;
    [exception]
    [dowith _ sentences;]
end [fun_name];
  • fun_name:函數名稱,如果數據庫中已經存在了此名稱,則可以指定“or replace”關鍵字,這樣新的函數將覆蓋掉原來的函數。
  • parameter1:函數的參數,這是個可選項,因爲函數可以沒有參數。
  • data_type:函數的返回值類型,這是個必選項。在返回值類型的前面要使用RETURN關鍵字來標明。
  • inner_variable:函數的內部變量,它有別於函數的參數,這是個可選項。
  • plsql_ sentence:PL/SQL語句,它是函數主要功能的實現部分,也就是函數的主體。
  • dowith _ sentences:異常處理代碼,也是PL/SQL語句,這是一個可選項。 由於函數有返回值,所以在函數主體部分(即begin部分)必須使用return語句返回函數值,並且要求返回值的類型要與函數聲明時的返回值類型(即data_type)相同。

2.1.2 創建函數示例

--創建一個函數,該函數實現計算某個部門的平均工資,傳入部門編號參數
create or replace function get_avg_pay(num_deptno number) return number is   
    --保存平均工資的內部變量
	num_avg_pay number;                                                  
begin
	--某個部門的平均工資
	select avg(sal) into num_avg_pay from emp where deptno=num_deptno;   
	--返回平均工資
	return(round(num_avg_pay,2));                                        
exception
	--異常處理
	when no_data_found then                                              
		dbms_output.put_line('該部門編號不存在');
    return(0);
end;
/

執行結果
在這裏插入圖片描述

2.2 調用函數

2.2.1 介紹
由於函數有返回值,所以在調用函數時,必須使用一個變量來保存函數的返回值,這樣函數和這個變量就組成了一個賦值表達式。

2.2.2 調用函數示例

set serveroutput on
declare
	--定義變量,存儲函數返回值
	avg_pay number; 
begin
	--調用函數,並獲取返回值
	avg_pay:=get_avg_pay(10);
	--輸出返回值,即員工平均工資  
	dbms_output.put_line('平均工資是:'||avg_pay);  
end;
/

執行結果
在這裏插入圖片描述

2.3 調用函數

2.3.1 刪除函數語法
刪除函數的操作比較簡單,使用DROP FUNCTION命令,其後面跟着要刪除的函數名稱,其語法格式如下:

drop function fun_name;

參數fucn_name表示要刪除的函數名稱。

2.3.2 刪除函數示例

drop function get_avg_pay;

執行結果
在這裏插入圖片描述當一個函數已經過時,想重新定義時,也不必先刪除再創建,同樣只需要在CREATE語句後面加上OR REPLACE關鍵字即可,如下所示:

create or replace function fun_name;

參考文獻:

  1. Oracle 11g從入門到精通 第二版,明日科技 著,清華大學出版社有限公司
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章