PL/SQL概述
Oracle提供了在數(shù)據(jù)庫(kù)服務(wù)器端編程的語(yǔ)言,即PL/SQL。而SQL只是一種聲明式語(yǔ)言,是非過(guò)程性的,語(yǔ)句之間相互獨(dú)立。在實(shí)際工作中,許多事務(wù)處理應(yīng)用都是過(guò)程性的,前后語(yǔ)句之間存在一定關(guān)聯(lián)。
PL/SQL是過(guò)程化SQL,可以彌補(bǔ)SQL語(yǔ)句的不足??梢跃帉?xiě)過(guò)程、函數(shù)、觸發(fā)器,而這些存放在oracle數(shù)據(jù)庫(kù)中可以在java程序中調(diào)用就節(jié)省了傳輸量和解析時(shí)間,同時(shí)提高了性能。
在Oracle 中使用PL/SQL來(lái)擴(kuò)展SQL的功能,PL/SQL可以通過(guò)IF和LOOP語(yǔ)句控制程序的執(zhí)行流程;可以定義變量以便在語(yǔ)句之間傳遞數(shù)據(jù)信息。PL/SQL是對(duì)標(biāo)準(zhǔn)SQL語(yǔ)言的擴(kuò)展, SQL語(yǔ)句完全可以嵌套在PL/SQL程序代碼中,將SQL的數(shù)據(jù)處理能力和PL/SQL的過(guò)程處理能力結(jié)合在一起。使得SQL能夠更加的靈活,功能更加強(qiáng)大,效率更高
本文主要講述PL/SQL的基本語(yǔ)法、條件判斷語(yǔ)句、循環(huán)語(yǔ)句。
1、PL/SQL變量的數(shù)據(jù)類(lèi)型
number:數(shù)字類(lèi)型,可以代表整數(shù)和浮點(diǎn)數(shù)。
int:整數(shù)型。
pls_integer:整數(shù)型,計(jì)算速度快(直接由cpu執(zhí)行),占用較少的存儲(chǔ)空間。但產(chǎn)生溢出時(shí)將觸發(fā)異常。
binary_integer:帶符號(hào)的整數(shù)型,不會(huì)出現(xiàn)溢出,但計(jì)算速度較慢(由oracle模擬執(zhí)行)。
char:定長(zhǎng)字符,最長(zhǎng)255個(gè)字符。
varchar2:變長(zhǎng)字符,最長(zhǎng)2000個(gè)字符。
long:變長(zhǎng)字符,最長(zhǎng)2gb。
date:日期型。
boolean:布爾型(true或false)。
2、變量的聲明和賦值
1)聲明變量的語(yǔ)法
變量名 數(shù)據(jù)類(lèi)型 := 初值 ;
變量名 數(shù)據(jù)類(lèi)型 default 初值 ;
A.長(zhǎng)度不能超過(guò)30個(gè)字符,不能有空格。
B.由字母、數(shù)字、下劃線、美元符號(hào)$和#號(hào)組成,必須以字母開(kāi)頭。
C.不能使用PL/SQL或SQL的關(guān)鍵字??梢允褂胔elp reserved words 命令獲得關(guān)鍵字列表。
D.變量默認(rèn)值為null。
變量命名規(guī)范

2)使用%TYPE聲明變量類(lèi)型
%TYPE用來(lái)定義與數(shù)據(jù)表中指定字段數(shù)據(jù)類(lèi)型相同的變量。如果表中字段的數(shù)據(jù)類(lèi)型或長(zhǎng)度發(fā)生變化,%TYPE變量會(huì)自動(dòng)隨之變化。這樣用戶不必查看表中各個(gè)字段的數(shù)據(jù)類(lèi)型,就可以確保所定義的變量能夠正確存儲(chǔ)字段數(shù)據(jù)。
格式為:變量名 方案名.表名.字段名%type
如:var_username scott.emp.empname%type; --員工名稱
3)使用%ROWTYPE聲明變量類(lèi)型
%ROWTYPE類(lèi)型可以根據(jù)數(shù)據(jù)表的行結(jié)構(gòu)定義數(shù)據(jù)類(lèi)型,用于存儲(chǔ)從數(shù)據(jù)表中檢索到的一行完整的數(shù)據(jù)。如果數(shù)據(jù)庫(kù)表的結(jié)構(gòu)發(fā)生變化,記錄變量中的結(jié)構(gòu)也將隨之改變。
格式為:變量名 方案名.表名%rowtype
例如:輸入職工編號(hào),輸出其詳細(xì)信息
declare
var_emp scott.emp%rowtype ; --數(shù)據(jù)行變量
var_empno scott.emp.empno%type;
begin
var_empno:=&var_empno;
select * into var_emp from scott.emp where empno=var_empno ;
dbms_output.put (var_emp.ename) ;
dbms_output.put_line(' '||var_emp.job) ;
dbms_output.put_line(' '||var_emp.sal) ;
end;
4)自定義變量類(lèi)型
自定義記錄數(shù)據(jù)類(lèi)型可以表示由多個(gè)字段值組成的一行數(shù)據(jù)。使用時(shí)首先要定義記錄類(lèi)型的結(jié)構(gòu),然后聲明該類(lèi)型的變量存儲(chǔ)數(shù)據(jù)。
type 類(lèi)型名稱 is record (
變量名稱 數(shù)據(jù)類(lèi)型 := 默認(rèn)值 ,
……
變量名稱 數(shù)據(jù)類(lèi)型 := 默認(rèn)值
) ;
例如:自定義員工姓名與工資類(lèi)型,輸入職工編號(hào),輸出其姓名與工資
declare
type employee_type is record ( --聲明自定義記錄類(lèi)型
ename scott.emp.ename%type,
sal scott.emp.sal%type
);
var_emp employee_type ; --聲明自定義記錄類(lèi)型變量
var_empno scott.emp.empno%type;
begin
var_empno:=&var_empno;
select ename, sal into var_emp from scott.emp where empno=var_empno ;
dbms_output.put (var_emp.ename) ;
dbms_output.put_line(' '||var_emp.sal) ;
end;
例如:允許同一記錄類(lèi)型的兩個(gè)變量整體賦值。
declare
type employee_type is record (
ename scott.emp.ename%type,
sal scott.emp.sal%type
);
var_emp1 employee_type ;
var_emp2 employee_type ;
var_empno scott.emp.empno%type;
begin
var_empno:=&var_empno;
select ename, sal into var_emp1 from scott.emp where empno=var_empno ;
var_emp2:=var_emp1;
dbms_output.put (var_emp2.ename) ;
dbms_output.put_line(' '||var_emp2.sal) ;
end;
3、PL/SQL的語(yǔ)法結(jié)構(gòu)
declare
//這部分用于聲明變量
begin
//這部分用于處理業(yè)務(wù)邏輯
exception
//這部分用于處理例外也就是異常情況
end;
例如:
declare
uname varchar2(10);
hello varchar2(10) := 'helloworld'; --為變量賦值
vsal emp.sal%type; --聲明一個(gè)引用類(lèi)型的變量
pall emp%rowtype; --聲明一個(gè)記錄類(lèi)型的變量
digit number:=#---提示用戶輸入,然后根據(jù)用戶輸入執(zhí)行相應(yīng)的操作
...
begin
dbms_output.put_line(hello);
exception
when exception_name then
//操作
end;
例如:根據(jù)用戶輸入的員工編號(hào)獲得其工資和獎(jiǎng)金
declare
var_empno number; --員工編號(hào)
var_sal number; --工資
var_comm number; --獎(jiǎng)金
begin
--接收用戶輸入的員工編號(hào)
var_empno:=&var_empno;
--獲得工資
select sal,nvl(comm,0) into var_sal,var_comm from scott.emp where empno=var_empno;
dbms_output.put_line('員工編號(hào)是'||var_empno||'的工資是'||var_sal||'獎(jiǎng)金是'||var_comm);
end;
4、PL/SQL的條件判斷語(yǔ)句
if語(yǔ)句
if 條件 then
語(yǔ)句;
end if;
if...else語(yǔ)句
if 條件 then
語(yǔ)句;
else
語(yǔ)句;
end if;
if...elseif...else語(yǔ)句
if 條件 then
語(yǔ)句;
elsif 條件then
語(yǔ)句;
else
語(yǔ)句;
end if;
例如:根據(jù)輸入的數(shù)字判斷大小
declare
v_url VARCHAR(50):='www.baidu.com';
v_num1 NUMBER:= 100;
v_num2 NUMBER:=200;
v_num3 NUMBER;
begin
dbms_output.put_line('請(qǐng)輸入第三個(gè)數(shù)字:');
v_num3 :=&num3;
if v_num1 < v_num3 then
dbms_output.put_line('第一個(gè)字符比第三個(gè)字符小');
end if;
if v_url like '%baidu%' then
dbms_output.put_line('網(wǎng)址之中包含baidu單詞');
end if;
end;
5、case語(yǔ)句
case語(yǔ)句語(yǔ)法為:
case 變量
when <表達(dá)式1> then 語(yǔ)句塊1;
when <表達(dá)式2> then 語(yǔ)句塊2;
……
when <表達(dá)式n> then 語(yǔ)句塊n;
[ else 語(yǔ)句塊 n+1 ]
end ;
例如:使用case語(yǔ)句判斷數(shù)值
declare
v_choose NUMBER:=1;
BEGIN
case v_choose
when 0 then
dbms_output.put_line('選擇的是0');
when 1 then
dbms_output.put_line('選擇的是1');
else
dbms_output.put_line('沒(méi)有選項(xiàng)滿足');
end case;
END;
6、PL/SQL的循環(huán)語(yǔ)句
在PL/SQL中有三種循環(huán)結(jié)構(gòu)
1).loop循環(huán)
loop循環(huán)語(yǔ)法為:
loop
語(yǔ)句塊;
exit when 循環(huán)結(jié)束條件;
循環(huán)語(yǔ)句修改;
end loop;
例如:輸出1-99的數(shù)。
declare
step number := 1;
begin
loop
exit when step > 100;--當(dāng)step>100退出循環(huán)
dbms_output.put_line(step || ' ');
step := step + 1;
end loop;
end;
2).while...loop循環(huán)
while...loop循環(huán)語(yǔ)法為:
while 循環(huán)結(jié)束條件 loop
語(yǔ)句塊;
循環(huán)語(yǔ)句修改;
end loop;
例如:循環(huán)輸出1-100的數(shù)。
declare
step number := 1;
begin
while step <= 100 loop
dbms_output.put_line(step);
step := step + 1;
end loop;
end;
3).for語(yǔ)句循環(huán)
for語(yǔ)句循環(huán)語(yǔ)法為:
for 循環(huán)變量 in n..N loop
語(yǔ)句塊;
end loop;
例如:輸出1-100之間的數(shù)
declare
begin
for i in 1.. 100 loop
dbms_output.put_line(i);
end loop;
end;
7、異常處理
PL/SQL程序運(yùn)行時(shí)出現(xiàn)的錯(cuò)誤稱為異常??梢苑譃閮深?lèi):
預(yù)定義異常: 當(dāng) PL/SQL 程序違反 Oracle 規(guī)則或超越系統(tǒng)限制時(shí)隱式引發(fā)
用戶自定義異常:用戶可以聲明自定義異常,自定義的異常通過(guò) raise 語(yǔ)句手動(dòng)引發(fā)
系統(tǒng)預(yù)定義異常
begin
過(guò)程及sql語(yǔ)句;
exception
when 異常名稱then
過(guò)程及sql語(yǔ)句;
when others then
過(guò)程及sql語(yǔ)句;
end;

例如:當(dāng)在程序中使用0作為除數(shù)進(jìn)行運(yùn)算時(shí),將觸發(fā)該異常。
DECLARE
v_test1 NUMBER := 100;
v_test2 NUMBER := 0;
v_test3 NUMBER := 0;
BEGIN
v_test3 := v_test1 / v_test2;
dbms_output.put_line(v_test3);
EXCEPTION
WHEN zero_divide THEN
dbms_output.put_line('0不能作為除數(shù).');
END;
/
例如:當(dāng)程序中的對(duì)象還沒(méi)有先進(jìn)行對(duì)象初始化的操作,就直接為對(duì)象的屬性賦值,將觸發(fā)該異常。
DECLARE
v_test test_type;
BEGIN
v_test.v_name := 'test';
EXCEPTION
WHEN access_into_null THEN
dbms_output.put_line('首先初始化對(duì)象v_test');
END;
/
例外函數(shù)1: SQLCODE,SQLERRM 在PL/SQL塊中出現(xiàn)Oracle錯(cuò)誤時(shí),通過(guò)使用例外函數(shù)可以取得錯(cuò)誤號(hào)以及相關(guān)的錯(cuò)誤消息。
SQLCODE 返回Oracle錯(cuò)誤號(hào)。
SQLERRM 返回錯(cuò)誤號(hào)對(duì)應(yīng)的錯(cuò)誤消息。
begin
insert into scott.emp(empno , ename , job , sal , deptno)
values('7999','ATG','CLERK',1500,'ABC');
exception
when dup_val_on_index then
dbms_output.put_line('捕獲dup_val_on_index異常');
dbms_output.put_line('該主鍵值已經(jīng)存在');
when others then -- others子句必須放在各種異常處理的最后
dbms_output.put_line( '錯(cuò)誤號(hào):' || sqlcode );
dbms_output.put_line( '錯(cuò)誤描述:' ||sqlerrm );
end;
備注:others可以捕獲所有異常,如果使了其它具體異常則others子句必須放在這些異常處理的最后。
例外函數(shù)2:RAISE_APPLICATION_ERROR在存儲(chǔ)過(guò)程,函數(shù)和包中使用RAISE_APPLICATION_ERROR可以自定義錯(cuò)誤號(hào)和消息。
raise_application_error:用于自定義錯(cuò)誤消息(用于程序段中)
語(yǔ)法:
raise_application_error(error_number,message[,{TRUE | FALSE}]);
error_number : 錯(cuò)誤號(hào),范圍是: -20000 ~ -20999之間的負(fù)整數(shù);
message : 錯(cuò)誤消息,長(zhǎng)度不能超過(guò)2048字節(jié);
第三個(gè)可靠選參數(shù),如果TRUE,該錯(cuò)誤會(huì)被放在先前錯(cuò)誤堆棧中;如果FALSE(默認(rèn)),則替換先前所有錯(cuò)誤.
例如:
CREATE OR REPLACE PROCEDURE raise_comm
(
eno NUMBER,
commission NUMBER
) IS
v_comm emp.comm%TYPE;
BEGIN
SELECT comm INTO v_comm FROM emp WHERE emp = eno;
IF v_comm IS NULL THEN
raise_application_error(-20001, '該員工無(wú)補(bǔ)助.');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('該雇員不存在.');
END;
/
用戶自定義異常
自定義異常使用預(yù)定義異常和非預(yù)定義異常,程序可以捕獲Oracle錯(cuò)誤,并且在出現(xiàn)Oracle錯(cuò)誤時(shí)自動(dòng)觸發(fā)對(duì)應(yīng)的異常。但是在實(shí)際應(yīng)用中,可能還會(huì) 遇到其它錯(cuò)誤,這時(shí)可以為特定的情況自定義異常,不過(guò)需要顯示觸發(fā)該異常:通過(guò)定義異常,然后關(guān)聯(lián)異常和錯(cuò)誤,顯示觸發(fā)異常,最后在EXCEPTION 中處理該異常。
自定義異常的處理步驟:
定義異常處理:異常名 exception ;
觸發(fā)異常處理:raise 異常名
例如:
--自定義異常
declare
e_wage EXCEPTION;
v_wage teachers.wage%type;
begin
v_wage:=&wage;
insert into teachers values (10111,'王彤','教授','01-9月-1990',1000,v_wage,101);
if v_wage <0 then
raise e_wage;
end if;
exception
when e_wage then
dbms_output.put_line('教師工資不能為負(fù)');
rollback;
when others then
dbms_output.put_line('未知異常');
end;
/