1. 程式人生 > >Oracle之PL/SQL編程

Oracle之PL/SQL編程

無提示 字符串轉換 保留字 case語句 大於等於 不變 replace 異常 inner

PL/SQL(Procedural Language/SQL,過程語言/SQL)

  是結合了Oracel過程語言和結構化查詢語言(SQL)的一種擴展語言。

優點:

(1)PL/SQL具有編程語言的特點,它能把一組SQL語句放到一個模塊中,使其更具模塊化種序的特點。

(2)PL/SQL可以采用過程性語言控制程序的結構。

(3)PL/SQL有自動處理的異常處理機制。

(4)PL/SQL程序塊具有更好的可移植性,可移植到另一個Oracle數據庫中。

(5)PL/SQL程序減少了網絡的交互,有助於提高程序性能。

PL/SQL引擎用來編譯和執行PL/SQL塊或子程序,該引擎駐留在Oracle服務器中,僅執行過程語句,面將SQL語句發送給Oracle服務器上的SQL語句執行器。

PL/SQL是一種塊結構的語言,它將一組語句放在一個塊中。匿名塊是一個未在數據庫中命名的PL/SQL塊,在運行時被傳遞到PL/SQL引擎以便執行。在PL/SQL塊中可以執行DML語句、TCL語句、SQL函數等。但PL/SQL塊中不可以執行

DDL語句,該種語句只能由動態SQL來執行。

PL/SQL塊由3部分組成:聲明部分、執行部分、異常處理部分

[declare]

--聲明部分:在此聲明PL/SQL用到的變量、類型及遊標,以及局部的存儲過程和函數

begin

--執行部分:過程及SQL語句,即程序的主要部分,不可省略

[exception]

--異常處理部分:錯誤處理

end;

關系運算符

運算符

意義

=

等於

<>、!=、~=、^=

不等於

<

小於

>

大於

<=

小於等於

>=

大於等於

一般運算符

運算符

意義

+

加號

-

減號

*

乘號

/

除號

:=

賦值符號

=>

關系符號

..

範圍運算符號

||

字符連接符號

邏輯運算符

運算符

意義

is null

是空值

between and

介於兩者之間

in

在一列值中間

and

邏輯與

or

邏輯或

not

取反,如is not null,not in

變量和常量的聲明

變量:variable_name data_type[(size)][:= init_value];

--variable_name表示變量名稱

--data_type表示變量的SQL或PL/SQL數據類型

--size指定變量的範圍。

--init_value指定變量的初始值。

在聲明變量時,可以用彈框的方式,給變量賦值。如:v_ename varchar2(10) :=&請輸入名字;

--這裏的” & ”符號就是關鍵字,後面的“當輸入名字”是提示信息。默認值輸入框中輸入的是數字,如果要輸入字符

串,則需要給要輸入的數據加上雙“’”單引號。

常量:variable_name CONSTANT data_type := value;

例,給常量和變量聲明賦值:

declare

v_ename varchar2(20);

v_no number;

v_rate number(7,2);

c_rate_incr constant number(7,2) := 1.10;

begin

--方法一:通過select into 給變量賦值,查詢結果只返回一條數據並賦值到變量中保存,返回多條或零條數據則報錯。

select ename,sal*c_rate_incr into v_ename, v_rate

  from employee

--方法二:通過賦值操作符“:=”給變量賦值,在賦值時可以使用序列

v_ename := ‘SOCTT’;

v_no := myseq.nextval;

end;

PL/SQL中標識符定義的要求和限制

1)標識符名稱不能超過30個字符。

2)第一個字符必須是字母。

3)不區分大小寫。

4)不能用”-”減號。

5)不能用SQL的保留字。

  命名方法:

標識符

命名規則

例子

程序變量

v_name

v_student_name

程序常量

c_name

c_company_name

遊標變量

cursor_name

cursor_emp

異常標誌

e_name

e_too_many

表類型

name_table_type

emp_record_type

name_table

emp_table

記錄類型

name_record

emp_record

綁定變量

g_name

g_year_sal

PL/SQL中編碼規則:

(1)利用縮進排列展現邏輯結構。保留字後出現的列開始縮進三個空格,如declare下面聲明變量行。

(2)利用大小寫增強可讀性。保留字統一大寫; 應用程序專用名稱或標識符統一小寫。

(3)格式化單獨語句。每行至多寫一條語句; 聲明語句中盡量保持聲明的數據類型近變量名,而不是與數據類型對齊。

(4)格式化SQL語句。右對齊DML語句的子句中的保留字。

註釋

1)使用雙“-”減號加註釋,只在一行有效,如:

  v_sal NUMBER(12,2); --人員的工資變量

2)使用“/* */”來加一行或多行註釋,建議使用如下方式

/*

||在註釋首行只放斜線星號,標誌註釋開始

||,然後註釋塊每一行以雙垂直線開頭,突出後面的註釋內容。可以不寫,但為了可讀性

*/

PL/SQL數據類型

1.標量數據類型,包含單個值,沒有內部組件。包括數字、字符、布爾值和日期時間值。

類型

子類

說明

範圍

CHAR

Character

Nchar

定長字符串

民族語言字符集

0~32767

可選,默認為1

VARCHAR2

Varchar String

NVARCHAR2

可變字符串

民族語言字符集

0~32767

BINARY_INTEGER

帶符號整數,為整數計算優化性能

NUMBER(p,s)

Dec

Double Precision

Integer

Int

Numeric

Real

Small int

小數,NUMBER的子類型

高精度實數

整數,NUMBER的子類型

整數,NUMBER的子類型

與NUMBER等價

與NUMBER等價

整數,比Integer小

LONG

可變長度字符串

0~2147483647

DATE

日期型

公元前4712年1月1日至

公元後4712年12月31日

BOOLEAN

布爾型

TRUE,FALSE,NULL

2.LOB(Large OBject)數據類型,用於存儲大的數據對象的類型,主要支持BFILE、BLOB、CLOB、NCLOB類型。

3.屬性類型,屬性用於引用變量或數據庫列的數據類型,以及表示表中一行的記錄類型。

1)%TYPE

  定義一個變量,其數據類型與已經定義的某個數據變量(尤其是表的一列)的數據類型一致。

2)%ROWTYPE

  返回一個記錄類型,其數據類型和數據庫表的數據結構一致。

例,根據員工編號查詢員工信息:

DECLARE

v_empno employee.empno%TYPE := 7788;

v_rec employee%ROWTYPE;

BEGIN

SELECT * INTO v_rec FROM employee WHERE empno=v_empno;

DBMS_OUTPUT.PUT_LINE(‘姓名:’||v_rec.ename||’工資:’||v_rec.sal);--輸出一行,只在PL/SQL塊中

END;

PL/SQL控制語句

1.條件控制,用於根據條件執行一系列語句。條件控制包括IF語句和CASE語句。

  IF語句語法:

IF <布爾表達式> THEN --if

--PL/SQL和SQL語句

END IF;

  -------------

IF <布爾表達式> THEN --if-else

--PL/SQL和SQL語句

ELSE

--其他語句

END IF;

  -------------

IF <布爾表達式> THEN --if-else if-else

--PL/SQL和SQL語句

ELSIF <其他表達式> THEN -- 這裏是elsif 而不是elseif,註意!!!

--其他語句

ELSIF <其他表達式> THEN

--其他語句

ELSE

--其他語句

END IF;

CASE語句語法:

--格式一

  CASE 條件表達式

WHEN 條件表達式結果1 THEN 語句段1

WHEN 條件表達式結果2 THEN 語句段2

.....

WHEN 條件表達式結果n THEN 語句段n

[ELSE 語句段]

END CASE;

--格式二

CASE

WHEN 條件表達式1 THEN 語句段1

WHEN 條件表達式2 THEN 語句段2

.....

WHEN 條件表達式n THEN 語句段n

[ELSE 語句段]

END CASE;

2.循環控制,用於重復執行的系列語句。包括LOOP和EXIT語句,使用EXIT語句可以立即退出循環; 使用EXIT WHEN

語句可以根據條件結束循環。有3種類型循環,包括LOOP循環、WHILE循環、FOR循環。

LOOP循環語法:

LOOP

要執行的語句;

EXIT WHEN <條件語句> --條件滿足,退出循環語句

END LOOP;

WHILE循環語法:

WHILE <布爾表達式> LOOP

要執行的語句;

END LOOP;

FOR循環語法:

FOR 循環計數器 IN [REVERSE] 下限 .... 上限 LOOP

要執行的語句;

END LOOP;

3.順序控制,用於按順序執行語句。順序控制包括NULL語句和GOTO語句。GOTO語句不推薦使。

NULL語句:是一個可執行語句,相當於一個占位符或不執行任何操作的空語句,可以便某些語句變得有意義,提高程

序的可讀性,保證其他語句結構的完整性和正確性。

例,顯示變量v_counter的值,如果該變量小於10,則增加10並顯示該變量改變後的值。

DECLARE

v_counter NUMBER := 5;

BEGIN

DBMS_OUTPUT.PUT.LINE(‘v_counter的當前值為:’||v_counter);

IF v_counter>=10 THEN

NULL; --為了使語法變得有意義,去掉NULL會報語法錯誤

ELSE

v_counter := v_counter+10;

DBMS_OUTPUT.PUT.LINE(‘v_counter的改變後值為:’||v_counter);

END IF;

END;

異常處理

在程序運行時出現的錯誤叫異常。發生異常後,語句將停止執行,PL/SQL引擎立即將控制權轉到PL/SQL塊的異常處理。

PL/SQL預定義異常

異常

說明

ACCESS_INTO_NULL

在未初始化對象時出現

CASE_NOT_FOUND

CASE語句中的選項與用戶輸入的數據不匹配時出現

COLLECTION_IS_NULL

給尚未初始化的表或數組賦值時出現

CORSOR_ALREADY_OPEN

在用戶試圖重新打開已經打開的遊標時出現。在重新打開遊標前必須先將其關閉

DUP_VAL_ON_INDEX

在用戶試圖將重復的值存儲在使用唯一索引的數據庫列中時出現

INVALID_CURSOR

在執行非法遊標運算(如打開一個尚未打開的遊標)時出現

INVALID_NUMBER

在將字符串轉換為數字時出現

LOGIN_DENIED

在輸入的用戶名或密碼無效時出現

NO_DATA_FOUND

在表中不存在請求的行時出現。此外,當程序引用已經刪除的元素時,也會引發NO_DATA_FOUND異常

STORAGE_ERROR

在內存損環或PL/SQL耗盡內存時出現

TOO_MANY_ROWS

在執行SELECT INTO語句後返回多行時出現

VALUE_ERROR

產生大小限制錯誤時出現。例如,變量中的列值超出變量的大小

ZERO_DIVIDE

以零作為除數時出現

異常處理語法:

BEGIN

sequence_of_statements;

EXCEPTION

WHEN <exception_name1> THEN

sequence_of_statements;

WHEN <exception_name2> THEN

sequence_of_statements;

WHEN OTHERS THEN --這裏的OTHERS處理程序除之前異常類型外的所有異常。PL/SQL塊只能有一個OTHERS

sequence_of_statements;

END;

--可以使用函數SQLCODE和SQLERRM來返回錯誤代碼和錯誤文本信息。

用戶自定義異常:

步聚如下

(1)在PL/SQL塊的定義部分定義異常情況:

<異常情況> EXCEPTION;

(2)拋出異常情況:

RAISE <異常情況>;

(3)在PL/SQL塊的異常情況處理部分對異常情況做出相應的處理。

例,查詢編號為7788的雇員的福利補助comm列。

DECLARE

v_comm employee.comm%TYPE;

e_comm_is_null EXCEPTION; --定義異常類型變量

BEGIN

SELECT comm INTO v_comm FROM employee WHERE empno=7788;

IF v_comm IS NULL THEN

RAISE e_comm_is_null;

END IF;

EXCEPTION

WHEN NO_DATA_FOUND THEN

DBMS_OUTPUT.PUT_LINE(‘雇員不存在!錯誤為:’||SQLCODE||SQLERRM);

WHEN E_COM_IS_NULL THEN

DBMS_OUTPUT.PUT_LINE(‘該雇員無補助!’);

WHEN OTHERS THEN

DBMS_OUTPUT.PUT_LINE(‘出現其他異常’);

END;

RAISE_APPLICATION_ERROR存儲過程可以重新定義異常錯誤消息,為應用程序提供一種與Oracle交互的方法。

  語法:

    RAISE_APPLICATION_ERROR(error_number, error_message);

--error_number表示用戶為指定的編號。該編號必須是-20999~-20000之間的負整數。

--error_message表示用戶為異常指定的消息文本。消息長度可達2048字節,是與error_number相關的。

例:

DECLARE

......

BEGIN

......

IF v_com IS NULL THEN

RAISE_APPLICATION_ERROR(-20001,’該雇員無補助’);

END IF;

END;

顯示遊標

Oracle會在內在中分配一個緩沖區,將執行結果放在這個緩沖區,而遊標是指向該區的一個指針。遊標為應用程序提供了一種對多行數據查詢結果集中的每一行數據分別進行單獨處理的方法,是設計嵌入式SQL語句的應用程序的常用編程式。

分類:

1)靜態遊標,是在編譯時知道明確的SELECT語句的遊標。靜態遊標分為隱式遊標、顯式遊標。

2)動態遊標

顯式遊標的使用步聚:

1)聲明遊標

CURSOR cursor_name [(parameter [,paramter]....)]

[RETURN return_type] IS select_statements;

--cursor_name指遊標的名稱。

--parameter用於為遊標指定輸入參數。在指定數據類型時,不能使用長度約束。

--return_type用於定義遊標提取的行的類型。

--select_statement 指遊標定義的查詢語句。

2)打開遊標

  OPEN cursor_name[ (parameters) ];

3)提取遊標

  FETCH cursor_name INTO variables;

  --variables是變量名

4)關閉遊標

  CLOSE cursor_name;

例:

技術分享圖片
DECLARE
name employee.ename%TYPE;
sal employee.sal%TYPE; --定義兩個變量來存放ename和sal的內容
CURSOR emp_cursor  --聲明遊標
IS SELECT ename,sal FROM employee;
BEGIN
OPEN emp_cursor;
LOOP
FETCH emp_cursor INTO name, sal;
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(‘第’||emp_cursor%ROWCOUNT||’個雇員:’||name||sal);
END LOOP;
CLOSE emp_cursor;
END;
技術分享圖片

顯式遊標屬性

1)%FOUND:只有在DML語句影響一行或多行時,%FOUND屬性才返回TRUE;

2)%NOTFOUND:%NOTFOUND屬性與%FOUND屬性的作用正好相反。如果DML語句沒有影響任何行,則%NOTFOUND屬性返回TRUE;

3)%ROWCOUNT:%ROWCOUNT屬性返回DML語句影響的行數。如果DML語句沒有影響任何行,則%ROWCOUNT屬性將返回0;

4)%ISOPEN:%ISOPEN屬性返回遊標是否已打開。

使用顯式遊標刪除或更新

  使用遊標時,如果處理過程中需要刪除或更新行,在定義遊標時必須使用SELECT....FOR UPDATE語句; 而在執行DELETE和UPDATE時使用WHERE CURRENT OF子句指定遊標的當前行。

  聲明更新遊標語法:

CURSOR cursor_name IS

select_statement FOR UPDATE [OF culumns];

--SELECT... FOR UPDATE[OF columns]為更新查詢,鎖定選擇的行。[OF columns]可以不是SELECT後的列

--(1)當選擇單表更新查詢時,可以受省略OF子句;

--(2)當選擇多個表更新查詢時,被鎖定的行來源於OF 子句後聲明的列所在的表中的行。

更新執行行語法:

UPDATE table_name

SET column_name= column_value

WHERE CURRENT OF cursor_name;

  --多表查詢更新時,更新表為鎖定列所在的表。

  例:   

技術分享圖片
DECLARE
CURSOR emp_cursor IS SELECT ename, sal FROM employee e INNER JOIN dept d ON 
e.deptno= d.deptno
FOR UPDATE OF SAL;
....
UPDATE employee SET sal=sal+100 WHERE CURRENT OF emp_cursor;
技術分享圖片

  使用循環遊標簡化遊標的讀取,循環遊標隱式打開遊標,自動從活動集獲取行,在處理實所有行時自動關閉遊標。

  語法:

FOR record_index IN cursor_name
LOOP
executable_statements
END LOOP;

  --record_index是PL/SQL聲明的記錄變量。此變量的屬性聲明為%ROWTYPE類型作用域在循環之內。

循環遊標的特性:

1)在遊標中提取了所有記錄之後自動終止。

2)提取和處理遊標中的每一條記錄。

3)如果在提取記錄之後%NOTFOUND屬性返回TRUE,則終止循環。

4)如果未返回行,則不進入循環。

例,顯示雇員表中所有雇員的姓名和薪水:

技術分享圖片
DECLARE
CURSOR emp_cursor IS 
SELECT ename, sal FROM  employee;
BEGIN
FOR emp_record IN emp_cursor 
LOOP
DBMS_OUTPUT.PUT_LINE(‘第’||emp_cursor%ROWCOUNT||’個雇員:’||emp_record.ename||
emp_record.sal);
END LOOP;
END;
技術分享圖片

NOT_DATA_FOUND和%NOTFOUND的區別

1)SELECT ··· INTO語句返回0條和多條記錄時觸發NO_DATA_FOUND。

2)當UPDATE或DELETE語句的WHERE 子句未找到時,觸發%NOTFOUND。

3)在提取循環中用%NOTFOUND或%FOUND來確定循環的退出條件,而不用NO_DATA_FOUND。

存儲過程

子程序

子程序是已命名的PL/SQL塊,它們存儲在數據庫中,包括存儲過程和函數。使用存儲過程執行操作,使用函數執行操作並返回值。

1.聲明部分,包括類型、遊標、常量、異常和嵌套子程序的使用。退出子程序後雩不復存在。

2.可執行部分,包括賦值、控制執行過程以及操縱Oracle數據的語句。

3.異常處理部分,包括異常處理程序,負責處理執行存儲過程中出現的異常。

子程序的優點:

1)模塊化:通過子種序,可以將程序分解為可管理的、明確的邏輯模塊。

2)可重用性:子程序在創建並執行後,就可以在任意數目的應用程序中使用。

3)可維護性:子程序可以簡化維護操作,因為如果一個子程序受到影響,則只需要修改該子程序的定義。

4)安全性:用戶可以設置權限,使得訪問數據的唯一方式就是用戶提供的存儲過程。這樣也可以保證正確性。

存儲過程:

  存儲過程是執行某些程序操作的子程序,是執行特定任務的模塊。從根本上來講,存儲過程就是命名後的PL/SQL塊。

  創建存儲過程:

技術分享圖片
CREATE [OR REPLACE] PROCEDURE procedure_name
[(parameter_list)]
[IS|AS]
[local_declarations]
BEGIN
execetable_statements
[EXCEPTION]
[exception_handlers]
END [procedure_name];
技術分享圖片

--procedure_name:存儲過程的名稱。

--parameter_list:參數列表,可選。

--local_declarations:局部聲明,可選。

--executable_statements:可執行語句。

--excetption_handlers:異常處理程序,可選。

--OR REPLACE:可選。如果包含OR REPLACE語句,當系統中有這個存儲過程時,將覆蓋。如果不包含,當系統中有這個存儲過程時,將報異常。

--聲明時,數據類型不能帶大小。如NUMBER(4),只能寫成NUMBER。

--聲明時可以給定默認值,如:job VARCHAR2 DEFAULT ‘CLEAK’ 如果調用時不揭定該參數,自動默認值。

  調用存儲過程(存儲過程通過授權,才可以調用)

1.用命令調用

1)執行:

  EXEC[UTE] procedure_name (parameter_list);

  --EXECUTE:執行命令,可以縮寫為EXEC

2)參數的傳遞方式

按位置傳遞,例:EXEC add_employee(1111,’MARY’,2000,’MANAGER’,10);

按名稱傳遞,即在調用時按名稱對應。名稱的對應關系是最重要的,次序不重要。

例:EXEC add_employee(dno=>10,name=>’MARY’,salary=>2000,job=>’MANAGER’);

混合方法傳遞,

例:EXEC add_employee(1113,dno=>10,name=>’MARY’,salary=>200,job=>’MANAGER);

其中雇員編號為1113,後面如果有一個是按照名稱傳遞,則之後的都要以名稱傳遞。

    2.PL/SQL塊中使用

BEGIN
 add_employee(2111,’MARY’,2000,’MANAGER’,10);
END;

    --在PL/SQL塊中調用存儲過程時不需要寫EXEC,直接寫存儲過程名稱即可,EXEC是命令行中調用存儲過程

    的命令。

    3.存儲過程的參數模式

在存儲過程中參數傳遞的模式有3種:IN、OUT、IN OUT,即輸入 、輸出、輸入/輸出參數。

IN模式只能將實參傳遞給形參,進入函數內部,函數返回時,實參值不變。結論參數傳遞 模式。

OUT模式會忽略調用時的實參值,在函數內部可寫,函數返回時實參的值改變。

IN OUT模式具有前再種模式的特性。即調用時,實參的值總是傳遞給形參;結束時,形參的值傳遞給實參

可以在參數列表中為IN參數賦默認值。但是OUT和INT OUT參數不可以賦默認值。

如:

技術分享圖片
CREATE OR REPLACE PROCEDURE QueryEmp
(
v_empno IN employee.empno%TYPE DEFAULT 1000, --默認編號為1000
v_ename OUT employee.ename%TYPE,
v_sal IN OUT employee.sal%TYPE
)
AS
......
技術分享圖片

    4.存儲過程的訪問權限。

如果非創建該存儲過程的用戶想要訪問該存儲過程,則需要得到存儲過程的EXECUTE權限。

--授權

GRANT EXECUTE ON add_employee TO A_oe;

--撤銷

REVOKE EXECUTE ON add_employee FROM A_oe;

5.刪除存儲過程

DROP PROCEDURE procedure_name;

存儲過程的調試與跟蹤

1.在SQL*Plus下調試

如: SQL>SET SERVEROUTPUT ON;

SQL>--調用add_employee存儲過程

SQL>SHOW ERRORS PROCEDURE add_employee;

2.用PL/SQL Developer工具調試

1)獲得DEBUG CONNECT SESSION權限

GRANT DEBUG CONNECT SESSION TO A_hr;

2)打開一個測試窗口,在裏面編寫存儲過程代碼。

3)按“F9”鍵進入調試狀態。或者測試窗口左上角的黃色齒輪按鈕。

4)在開始調試按鈕右邊第二個按鈕是單步進入按鈕。

存儲過程規範

1.存儲過程不可以直接使用DDL語句。可以通手動態SQL實現,最好不要使用。

2.存儲過程必須有相應的出錯處理功能。

3.存儲過程中變量在引用表字段的時候,需使用%TYPE和%ROWTYPE類型。

4.存儲過程必須包含兩個輸出參數,即on_Flag(number)和 os_Msg(varchar2),分別用於標識過程的執行狀態及過程提示信息。

其中on_Flag有三種取值情況:

0 表示過程執行成功但無提示信息;

大於0 表示過程執行成功但有提示信息;

小於1 表示過程執行失敗且有提示信息;

5.必須在存儲過程中做異常捕獲,並將異常信息通過os_Msg變量輸出。

6.-1999~-1的異常為Oracle定義的異常代碼。

7.“WHEN OTHERS”必須放貫在異常處理代碼的最後作為默認處理器處理沒有顯式處理的異常。

  例:

技術分享圖片
CREATE OR REPLACE PROCEDURE add_employee(
....
on_Flag OUT NUMBER, --執行狀態
os_Msg OUT VARCHAR2
)

IS

BEGIN
INSERT INTO .....
on_Flag:=1;
os_Msg:=’添加成功’;
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
on_Flag=-1;
os_Msg=’該雇員已存在’;
WHEN OTHERS THEN
on_Flag=-2;
os_Msg=’其他錯誤,與管理員聯系。’;      
END;
技術分享圖片

Oracle之PL/SQL編程