1. 程式人生 > >資料庫複習10——PL/SQL

資料庫複習10——PL/SQL

資料庫複習

CH10 PL/SQL

10.1 PL/SQL簡介

PL/SQL是Oracle對SQL的過程化的擴充套件,PL/SQL可以實現SQL相關的過程化程式,並且能夠以儲存過程函式的方式讓一段SQL業務邏輯駐留在SQL伺服器中,以便減少客戶機計算任務並減少網路I/O

10.2 PL/SQL程式設計基礎

(1)簡介

PL/SQL程式設計框架為:

DECLARE 
    <Variable List>
BEGIN
    <Extented SQL Execution>
EXCEPTION
    <Exception Handler>
END

若是儲存過程或函式,首部換成Create Procedure/Function ... IS <Variable List>(見後例)

先看一個完整的PL/SQL程式例子:

DECLARE
    name varchar2(20);
BEGIN
    Select sname Into name From Student Where s#='001';     DBMS_OUTPUT.PUT_LINE('學號001的學生姓名是:' || sname)
EXCEPTION
    When NO_DATA_FOUND Then
        DBMS_OUTPUT.PUT_LINE('學號為001的學生不存在');
When others Then DBMS_OUTPUT.PUT_LINE('發生了其它錯誤'); END;

其中:

  • name varchar2(20)宣告一個型別為varchar2長度為20的變數name
  • select S into V是擴充套件的select語句,把表的欄位S賦值給變數V
  • DBMS_OUTPUT.PUT_LINE()是PL/SQL標準輸出語句
  • when <Exception> then <Extented SQL Execution>是PL/SQL異常處理的分支判斷

(2)變數宣告

變數宣告分成普通宣告、表字段型別宣告和記錄型別宣告

普通宣告name varchar2(20);等價於表字段型別宣告name Student.sname%TYPE,後者利用了某表的某欄位的型別來宣告變數的型別

記錄型別相當於結構體,提高程式可讀性,如定義stu記錄型別:

TYPE stu IS RECORD (
    S# varchar2(10),
    name varchar2(20),
    age number
);

val stu;

引用時用點運算:val.name

(3)分支與迴圈

1.if分支

If <Condition> Then
    <Statement>
Elseif <Condition> Then
    <Statement>
Else
    <Statement>
End If;

注意=是相等,:=是賦值

2.while迴圈

While <Condition> Loop
    <Statement>
End LOOP;

3.for迴圈

For <Loop Variable> In [Reverse] <begin>..<end> Loop
    <Statement>
End LOOP;

4.loop迴圈

無條件的Loop,必須在迴圈體內部加入退出語句Exit;Exit When <Condition>才能退出該迴圈

(4)異常處理

標準格式:

Exception
    When <exception_name_1> Or <exception_name_2> Then
        <Statement>
    ...
    When Others Then
        <Statement>

系統定義的exception_name包括:

  • NO_DATA_FOUND:select into語句未找到匹配元組
  • TOO_MANY_ROWS:select into返回多行資料
  • VALUE_ERROR:賦值錯誤(型別不匹配、長度過長)
  • ZERO_DIVIDE:除零
  • TIMEOUT_ON_RESOURCE:等待資源超時

可以通過Raise <exception>生成一個自定義的異常,然後在Exception段捕捉它;也可以raise_application_error生成一個程式錯誤,由外部捕捉

10.3 遊標

PL/SQL每次只能處理單個元組,為了使其和SQL**多元組處理的特性保持一致,引入遊標**

遊標是客戶機上用來存放SQL語句返回中間結果的一塊記憶體,目的是為了協調PL/SQL和SQL間資料處理數目的矛盾

(1)宣告與開啟關閉

PL/SQL中游標只能儲存select語句的中間結果,其宣告如下:

Declare
    Cursor <cursor_name> IS <Select Statement>;

遊標宣告時不會立即執行,需要顯式呼叫open語句(對應關閉遊標的close語句):

Begin
    Open <cursor_name>;

(2)迴圈讀取

遊標中有一下幾個引數用於輔助控制遊標讀取資料:

  • %FOUND:布林,當前Fetch返回一行時為真
  • %NOTFOUND:布林,當前Fetch沒有返回一行時為真
  • %ISOPEN:布林,遊標已開啟為真
  • %ROWCOUNT:數值,返回已從遊標中取出的元組數目

那麼利用Fetch into語句(返回一條元組)有一下兩種方式完成遊標資料訪問:

1.While迴圈版本
Begin
    Open <cursor_name>;
    Fetch <cursor_name> into <record_type_variable>;
    While <cursor_name>%FOUND Loop
        DBMS_OUTPUT.PUT_LINE(...);
        Fetch <cursor_name> into <record_type_variable>;
    End Loop;
    Close <cursor_name>;
    ...

2.For迴圈版本

Begin
    For <Loop_variable> in <cursor_name> Loop
        DBMS_OUTPUT.PUT_LINE(...);
    End Loop;
    ...

其中有:

  • Fetch into語句返回一條元組,cursor自動指向下一個元組
  • For in可以簡潔的遍歷遊標內資料,迴圈開始前自動開啟遊標讀取資料,迴圈結束自動關閉遊標,並且自動為<Loop_variable>宣告記錄型別存放

(3)帶引數的遊標

遊標可以新增引數,如可以在引數中限定where子句的條件:

Cursor cs_s(val Number(3)) IS Select * from stu where age = val;

10.4 儲存過程和函式

一般匿名的PL/SQL程式每次執行時都需要編譯,而命名PL/SQL程式如儲存過程函式觸發器等則是編譯好駐留在資料庫中,可以隨時被SQL或其他PL/SQL程式呼叫

過程和匿名的PL/SQL程式只是宣告格式上些許不同:

Create [or Replace] Procedure <procedure_name> (
    <param_name> In|Out|In Out <type> [:= <initial_value>],
    ...
)
AS|IS
    <Variable Declaration>
Begin
    <PL/SQL statement>
Exception
    <Exception Handler>
End;
)

其中有:

  • In引數不能修改,Out引數只能賦值
  • 引數不能指定長度,但可以用%TYPE
  • 引數傳遞預設按位置順序傳遞,也可以顯式地用<param_name> => <param_value>按名稱亂序傳遞
  • 函式是有返回型別的儲存過程,在AS前加上返回型別宣告Return <return_type>然後再函式體中用return <return_value>返回對應型別的值,在其他的PL/SQL中按函式名傳參呼叫,並用:=賦值給其他變數

10.5 觸發器

觸發器是一類繫結在表上,由特定DML語句(Update、Insert、Delete)觸發自動執行的一段PL/SQL**儲存過程**,一個表能有多個觸發器但一個觸發器只能繫結在一個表上

觸發器的概念在先前的SQL複習中已經詳細講解,這裡列出PL/SQL中觸發器宣告規則:

Create [Or Replace] Trigger <trigger_name>
    // 宣告觸發動作與觸發時間
    Before|After Delect|Insert|Update [Of <attribute_name>]
    // Or 連線多個觸發動作時間宣告
    {Or Before|After Delect|Insert|Update [Of <attribute_name>]}*
On <table_name>
    // 不寫表示語句觸發,寫For Each Row表示行觸發
    [For Each Row]
Declare
...