一:前言
目前由於mysql的開源,與幾年前的如ioe的一股浪潮,以及oracle的可拓展瓶頸問題,導致大的公司基本放棄使用oracle。取而代之的是一些基於mysql而改良後的雲數據庫環境,例如阿里雲的drds產品。但是對於業務量不是與日激增的服務,還是完全在使用oracle數據庫,畢竟單機oracle服務性能還是沒得說,已經它特有的一些統計函數等。今天主要講解下關於oracle的PL/SQL即Procedural Language/SQL 語言。
二:關於PL/SQL這一過程化編程語言主要分爲如下幾類便準編程結構:
- 塊結構
- 變量和類型
- 條件邏輯
- 循環
- 遊標,保證查詢返回的結果
- 過程
- 函數
- 包,可以用來將過程與函數組合到一個單元裏面
三:語法結構
1.基本結構示例
DECLARE --聲明部分
聲明語句
BEGIN --執行部分
執行語句
EXCEPTION --異常處理部分
執行語句
END;
2.變量聲明
1.定義普通變量
變量名 類型 [:= 初始值]
Eg: test_v number := 0;
2.引用數據庫表中某一個字段類型
變量名 數據庫表名.字段名 %type [:= 初始值]
eg: realName pl_user.real_name%type; --表示realName的類型和pl_user.real_name的類型相同
3.引用數據庫表中所有字段類型及字段名
變量名 數據庫表名 %rowtype;
Eg: testRow pl_user%rowtype; --表示 testRow包含了pl_user表中所有字段的名及類型,可以理解爲數組
3.常量聲明
變量名 CONSTANT 類型:=初始值;
示例: pi constant number(5,3):=3.14;
4.全局變量聲明
VARIABLE 變量名 類型;
示例: VARIABLE num number;
5.變量賦值
:= 賦給的值
6.使用全局變量
:<變量名>
示例:
:num:=100;
i=:num;
7.條件控制語句
IF <條件1> THEN
語句
[ELSIF <條件2> THEN
語句
ELSIF <條件n> THEN
語句]
[ELSE
語句]
END IF;
8.循環控制語句
1、 loop方式循環:
LOOP
語句;
EXIT WHEN <條件>
END LOOP;
2、 WHILE LOOP方式循環:
WHILE <條件>
LOOP
語句;
END LOOP;
3、 for循環方式:
FOR <循環變量> IN 下限…上限
LOOP
語句;
END LOOP;
9.NULL語句
null;
表示沒有操作;
10.註釋語法
單行註釋: –
多行註釋:/* …
…*/
11.異常處理
EXCEPTION
WHEN <異常類型> THEN
語句;
WHEN OTHERS THEN
語句;
END;
四:遊標
定義:
CURSOR <遊標名> IS <SELECT 語句> [FOR UPDATE | FOR UPDATE OF 字段];
[FOR UPDATE | FOR UPDATE OF 字段] --給遊標加鎖,既是在程序中有"UPDATE",“INSERT”,“DELETE"語句對數據庫操作時。
遊標自動給指定的表或者字段加鎖,防止同時有別的程序對指定的表或字段進行"UPDATE”,“INSERT”,“DELETE"操作.
在使用"DELETE”,“UPDATE"後還可以在程序中使用CURRENT OF <遊標名> 子句引用當前行
操作:OPEN <遊標名> --打開遊標
FETCH <遊標名> INTO 變量1,變量2,變量3,…變量n,;
或者
FETCH <遊標名> INTO 行對象; --取出遊標當前位置的值
CLOSE <遊標名> --關閉遊標
屬性: %NOTFOUND --如果FETCH語句失敗,則該屬性爲"TRUE”,否則爲"FALSE";
%FOUND --如果FETCH語句成果,則該屬性爲"TRUE",否則爲"FALSE";
%ROWCOUNT --返回遊標當前行的行數;
%ISOPEN --如果遊標是開的則返回"TRUE",否則爲"FALSE";
例子:
1:loop循環示例
declare
cursor c_1 is select * from pl_user; --定義遊標
r c_1%rowtype; --定義一個行對象,用於獲得遊標的值
begin
if c_1%isopen then
CLOSE c_1;
end if; --判斷遊標是否打開.如果開了將其關閉,然後在打開
open c_1;
dbms_output.put_line('行號 字段一 字段二 字段三');
loop
fetch c_1 into r;--取值
exit when c_1%notfound; --如果遊標沒有取到值,退出循環.
dbms_output.put_line(c_1%rowcount ||' '|| r.id ||' '|| r.login_name ||' '|| r.real_name ||' '|| r.email);--輸出結果
end loop;
end;
2:FOR循環示例
DECLARE
cursor c_1 is select id,real_name from pl_user; --定義遊標
BEGIN
dbms_output.put_line('行號 id 真實姓名');
FOR r IN c_1 --for循環中的循環變量i爲c_1%rowtype類型;
LOOP
dbms_output.put_line(c_1%rowcount ||' '|| r.id ||' '|| r.real_name);
END LOOP;
END;
注:for循環使用遊標是在循環開始前自動打開遊標,並且自動取值到循環結束後,自動關閉遊標.
3:遊標加鎖示例:
DECLARE
cursor c_1 is select id,real_name from pl_user for update of real_name; --定義遊標對pl_user表的real_name字段加鎖.
BEGIN
dbms_output.put_line('行號 id 真實姓名');
FOR i IN c_1 --for循環中的循環變量i爲c_1%rowtype類型;
LOOP
UPDATE pl_user set real_name=concat(real_name,100) WHERE CURRENT OF c_1; --表示對當前行的real_name進行跟新.
END LOOP;
FOR i IN c_1
LOOP
dbms_output.put_line(c_1%rowcount||' '||i.id||' '||i.real_name); --輸出結果
END LOOP;
END;
4:代參數的遊標示例
DECLARE
cursor c_1(name pl_user.real_name%type) is select id,real_name from pl_user where rownum <5 and real_name=name; --定義遊標
BEGIN
dbms_output.put_line('行號 id 真實姓名');
FOR i IN c_1('&name') --for循環中的循環變量i爲c_1%rowtype類型;
LOOP
dbms_output.put_line(c_1%rowcount||' '||i.id||' '||i.real_name); --輸出結果,需要 set serverout on 才能顯示.
END LOOP;
END;
注:需要傳入name變量的值供遊標的執行
5:隱式遊標示例
隱式遊標遊標是系統自動生成的。每執行一個DML語句就會產生一個隱試遊標,起名字爲SQL;
隱式遊標不能進行"OPEN" ,“CLOSE”,"FETCH"這些操作;
屬性:
%NOTFOUND --如果DML語句沒有影響到任何一行時,則該屬性爲"TRUE",否則爲"FALSE";
%FOUND --如果DML語句影響到一行或一行以上時,則該屬性爲"TRUE",否則爲"FALSE";
%ROWCOUNT --返回遊標當最後一行的行數;
BEGIN
DELETE FROM pl_user WHERE real_name='&a';
IF SQL%NOTFOUND THEN
dbms_output.put_line('real_name不存在');
END IF;
IF SQL%ROWCOUNT>0 THEN
dbms_output.put_line('刪除成功');
END IF;
END;
注:調用時需要給a傳參纔可,如果參數爲number類型的話 則遊標創建語句後半部分需要改爲real_name=&a;