|
pl/sql是oracle對標準資料庫語言的擴充,oracle公司已經將pl/sql整合到oracle 伺服器和其他工具中了,近幾年中更多的開發人員和dba開始使用pl/sql,本文將講述pl/sql基礎文法,結構和組件、以及如何設計並執行一個pl/sql程式。
pl/sql的優點
從版本6開始pl/sql就被可靠的整合到oracle中了,一旦掌握pl/sql的優點以及其專屬的資料管理的便利性,那麼你很難想象oracle缺了pl/sql的情形。pl/sql 不是一個獨立的產品,他是一個整合到oracle伺服器和oracle工具中的技術,可以把pl/sql看作oracle伺服器內的一個引擎,sql語句執行者處理單個的sql語句,pl/sql引擎處理pl/sql程式塊。當pl/sql程式塊在pl/sql引擎處理時,oracle伺服器中的sql語句執行器處理pl/sql程式塊中的sql語句。
pl/sql的優點如下:
. pl/sql是一種高效能的基於交易處理的語言,能運行在任何oracle環境中,支援所有資料處理命令。通過使用pl/sql程式單元處理sql的資料定義和資料控制元素。
. pl/sql支援所有sql資料類型和所有sql函數,同時支援所有oracle物件類型
. pl/sql塊可以被命名和儲存在oracle伺服器中,同時也能被其他的pl/sql程式或sql命令調用,任何客戶/伺服器工具都能訪問pl/sql程式,具有很好的可重用性。
. 可以使用oracle資料工具管理儲存在伺服器中的pl/sql程式的安全性。可以授權或撤銷資料庫其他使用者訪問pl/sql程式的能力。
. pl/sql代碼可以使用任何ascii文字編輯器編寫,所以對任何oracle能夠啟動並執行作業系統都是非常便利的
. 對於sql,oracle必須在同一時間處理每一條sql語句,在網路環境下這就意味作每一個獨立的調用都必須被oracle伺服器處理,這就佔用大量的伺服器時間,同時導致網路擁擠。而pl/sql是以整個語句塊發給伺服器,這就降低了網路擁擠。
pl/sql塊結構
pl/sql是一種塊結構的語言,組成pl/sql程式的單元是邏輯塊,一個pl/sql 程式包含了一個或多個邏輯塊,每個塊都可以劃分為三個部分。與其他語言相同,變數在使用之前必須聲明,pl/sql提供了獨立的專門用於處理異常的部分,下面描述了pl/sql塊的不同部分:
聲明部分(declaration section)
聲明部分包含了變數和常量的資料類型和初始值。這個部分是由關鍵字declare開始,如果不需要聲明變數或常量,那麼可以忽略這一部分;需要說明的是遊標的聲明也在這一部分。
執行部分(executable section)
執行部分是pl/sql塊中的指令部分,由關鍵字begin開始,所有的可執行語句都放在這一部分,其他的pl/sql塊也可以放在這一部分。
異常處理部分(exception section)
這一部分是可選的,在這一部分中處理異常或錯誤,對異常處理的詳細討論我們在後面進行。
pl/sql塊文法
[declare]
---declaration statements
begin
---executable statements
[exception]
---exception statements
end
|
pl/sql塊中的每一條語句都必須以分號結束,sql語句可以使多行的,但分號表示該語句的結束。一行中可以有多條sql語句,他們之間以分號分隔。每一個pl/sql塊由begin或declare開始,以end結束。注釋由--標示。
pl/sql塊的命名和匿名
pl/sql程式塊可以是一個命名的程式塊也可以是一個Anonymizer塊。Anonymizer塊可以用在伺服器端也可以用在用戶端。
命名程式塊可以出現在其他pl/sql程式塊的聲明部分,這方面比較明顯的是子程式,子程式可以在執行部分引用,也可以在異常處理部分引用。
pl/sql程式塊可背獨立編譯並儲存在資料庫中,任何與資料庫相連線應用程式程式都可以訪問這些儲存的pl/sql程式塊。oracle提供了四種類型的可儲存的程式:
. 函數
. 過程
. 包
. 觸發器
函數
函數是命名了的、儲存在資料庫中的pl/sql程式塊。函數接受零個或多個輸入參數,有一個傳回值,傳回值的資料類型在建立函數時定義。定義函數的文法如下:
function name [{parameter[,parameter,...])] return datatypes is
[local declarations]
begin
execute statements
[exception
exception handlers]
end [name] |
過程
預存程序是一個pl/sql程式塊,接受零個或多個參數作為輸入(input)或輸出(output)、或既作輸入又作輸出(inout),與函數不同,預存程序沒有傳回值,預存程序不能由sql語句直接使用,只能通過execut命令或pl/sql程式塊內部調用,定義預存程序的文法如下:
procedure name [(parameter[,parameter,...])] is
[local declarations]
begin
execute statements
[exception
exception handlers ]
end [name] |
包(package)
包其實就是被組合在一起的相關對象的集合,當包中任何函數或預存程序被調用,包就被載入入記憶體中,包中的任何函數或預存程序的子程式訪問速度將大大加快。
包由兩個部分組成:規範和包主體(body),規範描述變數、常量、遊標、和子程式,包體完全定義子程式和遊標。
觸發器(trigger)
觸發器與一個表或資料庫事件聯絡在一起的,當一個觸發事件發生時,定義在表上的觸發器被觸發。
變數和常量
變數存放在記憶體中以獲得值,能被pl/sql區塊引述。你可以把變數想象成一個可儲藏東西的容器,容器內的東西是可以改變的。
聲明變數
變數一般都在pl/sql塊的聲明部分聲明,pl/sql是一種強壯的類型語言,這就是說在引用變數前必須首先聲明,要在執行或異常處理部分使用變數,那麼變數必須首先在聲明部分進行聲明。
聲明變數的文法如下:
| variable_name [constant] databyte [not null][:=|default expression] |
注意:可以在聲明變數的同時給變數強制性的加上not null約束條件,此時變數在初始化時必須賦值。
給變數賦值
給變數賦值有兩種方式:
. 直接給變數賦值
x:=200;
y=y+(x*20);
. 通過sql select into 或fetch into給變數賦值
select sum(salary),sum(salary*0.1)
into total_salary,tatal_commission
from employee
where dept=10;
常量
常量與變數相似,但常量的值在程式內部不能改變,常量的值在定義時賦予,,他的聲明方式與變數相似,但必須包括關鍵字constant。常量和變數都可被定義為sql和使用者定義的資料類型。
| zero_value constant number:=0; |
這個語句定了一個名叫zero_value、資料類型是number、值為0的常量。
標量(scalar)資料類型
標量(scalar)資料類型沒有內部組件,他們大致可分為以下四類:
. number
. character
. date/time
. boolean
表1顯示了數字資料類型;表2顯示了字元資料類型;表3顯示了日期和布林值資料型別。
表1 scalar types:numeric
| datatype |
range |
subtypes |
description |
| binary_integer |
-214748-2147483647 |
natural
natural
npositive
positiven
signtype
|
用於儲存單位元組整數。
要求儲存長度低於number值。
用於限制範圍的子類型(subtype):
natural:用於非負數
positive:只用於正數
naturaln:只用於非負數和非null值
positiven:只用於正數,不能用於null值
signtype:只有值:-1、0或1. |
| number |
1.0e-130-9.99e125 |
dec
decimal
double
precision
float
integeric
int
numeric
real
smallint |
儲存數字值,包括整數和浮點數。可以選擇精度和刻度方式,文法:
number[(
[,])]。
預設的精度是38,scale是0. |
| pls_integer |
-2147483647-2147483647 |
|
與binary_integer基本相同,但採用機器運算時,pls_integer提供更好的效能 。 |
表2 字元資料類型
| datatype |
rang |
subtype |
description |
| char |
最大長度32767位元組 |
character |
儲存定長字串,如果長度沒有確定,預設是1 |
| long |
最大長度2147483647位元組 |
|
儲存可變長度字串 |
| raw |
最大長度32767位元組 |
|
用於儲存位元據和位元組字串,當在兩個資料庫之間進行傳遞時,raw資料不在字元集之間進行轉換。 |
| longraw |
最大長度2147483647 |
|
與long資料類型相似,同樣他也不能在字元集之間進行轉換。 |
| rowid |
18個位元組 |
|
與資料庫rowid偽列類型相同,能夠儲存一個行標示符,可以將行標示符看作資料庫中每一行的唯一索引值。 |
| varchar2 |
最大長度32767位元組 |
stringvarchar |
與varchar資料類型相似,儲存可變長度的字串。聲明方法與varchar相同 |
表3 date和boolean
| datatype |
range |
description |
| boolean |
true/false |
儲存邏輯值true或false,無參數 |
| date |
01/01/4712 bc |
儲存固定長的日期和時間值,日期值中包含時間 |
lob資料類型
lob(大對象,large object) 資料類型用於儲存類似映像,聲音這樣的大型資料對象,lob資料對象可以是位元據也可以是字元資料,其最大長度不超過4g。lob資料類型支援任意訪問方式,long只支援順序訪問方式。lob儲存在一個單獨的位置上,同時一個"lob定位器"(lob locator)儲存在原始的表中,該定位器是一個指向實際資料的指標。在pl/sql中操作lob資料對象使用oracle提供的包dbms_lob.lob資料類型可分為以下四類:
. bfile
. blob
. clob
. nclob
操作符
與其他程式設計語言相同,pl/sql有一系列操作符。操作符分為下面幾類:
. 算術操作符
. 關係操作符
. 比較操作符
. 邏輯操作符
算術操作符如表4所示
| operator |
operation |
| + |
加 |
| - |
減 |
| / |
除 |
| * |
乘 |
| ** |
乘方 |
關係操作符主要用於條件判斷語句或用於where子串中,關係操作符檢查條件和結果是否為true或false,表5是pl/sql中的關係操作符
| operator |
operation |
| < |
小於操作符 |
| <= |
小於或等於操作符 |
| > |
大於操作符 |
| >= |
大於或等於操作符 |
| = |
等於操作符 |
| != |
不等於操作符 |
| <> |
不等於操作符 |
| := |
賦值操作符 |
表6 顯示的是比較操作符
| operator |
operation |
| is null |
如果運算元為null返回true |
| like |
比較字串值 |
| between |
驗證值是否在範圍之內 |
| in |
驗證運算元在設定的一系列值中 |
表7.8顯示的是邏輯操作符
| operator |
operation |
| and |
兩個條件都必須滿足 |
| or |
只要滿足兩個條件中的一個 |
| not |
取反 |
執行部分
執行部分包含了所有的語句和運算式,執行部分以關鍵字begin開始,以關鍵字exception結束,如果exception不存在,那麼將以關鍵字end結束。分號分隔每一條語句,使用賦值操作符:=或select into或fetch into給每個變數賦值,執行部分的錯誤將在異常處理部分解決,在執行部分中可以使用另一個pl/sql程式塊,這種程式塊被稱為嵌套塊
所有的sql資料動作陳述式都可以用於執行部分,pl/sql塊不能再螢幕上顯示select語句的輸出。select語句必須包括一個into子串或者是遊標的一部分,執行部分使用的變數和常量必須首先在聲明部分聲明,執行部分必須至少包括一條可執行語句,null是一條合法的可執行語句,事物控制語句commit和rollback可以在執行部分使用,資料定義語言 (Data Definition Language)(data definition language)不能在執行部分中使用,ddl語句與execute immediate一起使用或者是dbms_sql調用。
執行一個pl/sql塊
sql*plus中匿名的pl/sql塊的執行是在pl/sql塊後輸入/來執行,如下面的例子所示:
declare
v_comm_percent constant number:=10;
begin
update emp
set comm=sal*v_comm_percent
where deptno=10;
end
sql> /
pl/sql procedure successfully completed.
sql> |
命名的程式與Anonymizer的執行不同,執行命名的程式塊必須使用execute關鍵字:
create or replace procedure update_commission
(v_dept in number,v_pervent in number default 10) is
begin
update emp
set comm=sal*v_percent
where deptno=v_dept;
end
sql>/
procedure created
sql>execute update_commission(10,15);
pl/sql procedure successfully completed.
sql> |
如果在另一個命名程式塊或Anonymizer塊中執行這個程式,那麼就不需要execute關進字。
declare
v_dept number;
begin
select a.deptno
into v_dept
from emp a
where job=''president''
update_commission(v_dept);
end
sql>/
pl/sql procedure successfully completed
sql> |
控制結構
控制結構控制pl/sql程式流程的程式碼,pl/sql支援條件控制和迴圈控制結構。
文法和用途
if..then
文法:
if condition then
statements 1;
statements 2;
....
end if
|
if語句判斷條件condition是否為true,如果是,則執行then後面的語句,如果condition為false或null則跳過then到end if之間的語句,執行end if後面的語句。
if..then...else
文法:
if condition then
statements 1;
statements 2;
....
else
statements 1;
statements 2;
....
end if |
如果條件condition為true,則執行then到else之間的語句,否則執行else到end if之間的語句。
if 可以嵌套,可以在if 或if ..else語句中使用if或if..else語句。
if (a>b) and (a>c) then
g:=a;
else
g:=b;
if c>g then
g:=c;
end if
end if |
if..then..elsif
文法:
if condition1 then
statement1;
elsif condition2 then
statement2;
elsif condition3 then
statement3;
else
statement4;
end if;
statement5;
|
如果條件condition1為true則執行statement1,然後執行statement5,否則判斷condition2是否為true,若為true則執行statement2,然後執行statement5,對於condition3也是相同的,如果condition1,condition2,condition3都不成立,那麼將執行statement4,然後執行statement5。
迴圈控制
迴圈控制的基本形式是loop語句,loop和end loop之間的語句將無限次的執行。loop語句的文法如下:
loop
statements;
end loop
loop和end loop之間的語句無限次的執行顯然是不行的,那麼在使用loop語句時必須使用exit語句,強制迴圈結束,例如:
x:=100;
loop
x:=x+10;
if x>1000 then
exit;
end if
end loop;
y:=x; |
此時y的值是1010.
exit when語句將結束迴圈,如果條件為true,則結束迴圈。
x:=100;
loop
x:=x+10;
exit when x>1000;
x:=x+10;
end loop;
y:=x;
|
while..loop
while..loop有一個條件與迴圈相聯絡,如果條件為true,則執行迴圈體內的語句,如果結果為false,則結束迴圈。
x:=100;
while x<=1000 loop
x:=x+10;
end loop;
y=x; |
for...loop
文法:
for counter in [reverse] start_range....end_range loop
statements;
end loop; |
loop和while迴圈的迴圈次數都是不確定的,for迴圈的迴圈次數是固定的,counter是一個隱式聲明的變數,他的初始值是start_range,第二個值是start_range+1,直到end_range,如果start_range等於end _range,那麼迴圈將執行一次。如果使用了reverse關鍵字,那麼範圍將是一個降序。
x:=100;
for v_counter in 1..10 loop
x:=x+10;
end loop
y:=x; |
如果要退出for迴圈可以使用exit語句。
標籤
使用者可以使用標籤使程式獲得更好的可讀性。程式塊或迴圈都可以被標記。標籤的形式是<>。
標記程式塊
<>
[declare]
... ... ...
begin
........
[exception]
.......
end label_name |
標記迴圈
<>
loop
.........
<>
loop
..........
<>
loop
....
exit outer_loop when v_condition=0;
end loop innermost_loop;
..........
end loop inner_loop;
end loop outer_loop; |
goto語句
文法:
goto label;
執行goto語句時,控制會立即轉到由標籤標記的語句。pl/sql中對goto語句有一些限制,對於塊、迴圈、if語句而言,從外層跳轉到內層是非法的。
x :=100;
for v_counter in 1..10 loop
if v_counter =4 then
goto end_of_loop
end if
x:=x+10;
<>
null
end loop
y:=x; |
注意:null是一個合法的可執行語句。
嵌套
程式塊的內部可以有另一個程式塊這種情況稱為嵌套。嵌套要注意的是變數,定義在最外部程式塊中的變數可以在所有子塊中使用,如果在子塊中定義了與外部程式塊變數相同的變數名,在執行子塊時將使用子塊中定義的變數。子塊中定義的變數不能被父區塊引述。同樣goto語句不能由父塊跳轉道子塊中,反之則是合法的。
《outer block》
declare
a_number integer;
b_number integer;
begin
--a_number and b_number are available here
<>
declare
c_number integer
b_number number(20)
begin
c_number:=a_number;
c_number=outer_block.b_number;
end sub_block;
end out_block;
|
小結
我們在這篇文章中介紹了pl/sql的基礎文法以及如何使用pl/sql語言設計和運行pl/sql程式塊,並將pl/sql程式整合到oracle伺服器中,雖然pl/sql程式作為功能塊嵌入oracle資料庫中,但pl/sql與oracle資料庫的緊密結合使得越來越多的oracle資料庫管理員和開發人員開始使用pl/sql。 |