1. 程式人生 > >oracle中pl/sql程式設計---儲存過程,函式,觸發器,包

oracle中pl/sql程式設計---儲存過程,函式,觸發器,包

1.pl/sql程式設計
pl/sql 指procedure language 過程化/sql.
pl/sql 是oracle在標準的sql語句基礎上擴充套件的一種對oracle資料庫進行程式設計的的語言。
可以定義變數和常量,而且可以使用條件語句和迴圈語句。

2.為什麼要有pl/sql程式設計?
平時是通過java對資料操作,但是有個缺點
(1)不能模組化程式設計,比如完成訂單,可能需要發幾條sql語句
(2)執行速度慢
(3)安全問題(在程式中會有表名)
(4)浪費頻寬
可以通過在資料庫裡面編寫過程,然後用java去呼叫過程
缺點:不能跨平臺

3.建立儲存過程基本語法:
create procedure 儲存過程名
is 
begin
建立語句
end;
例子:
create procedure emp_test is
begin
insert into emp(empno,ename) values (2343,'小白是土鱉');
end;
/

//執行儲存過程:
exec emp_test;

4.儲存過程中的引數是先寫引數名,再寫引數型別
create procedure del_emp(in_empno number )
is
begin
delete from emp where empno=in_empno;
end;
/
//執行儲存過程:
exec del_emp(2345);


5.pl/sql 可以做什麼?
利用pl/sql 可以開發過程,函式,包(包體),觸發器,他們的基本程式設計單元是塊

6.編寫規範:
①註釋
單行註釋 --
多行註釋: /* */
②識別符號號的命名規範:
1)定義變數時,建議使用v_作為字首,如:v_sal
2)定義常量時,建議用c_作為字首,如:c_rate (constant)
3)定義遊標時,建議用_cursor作為字尾,如:emp_cursor
4)定義例外時,建議用e_作為字首,如:e_error (exception)

7.pl/sql塊的介紹:
塊(block)是pl/sql的基本程式單元,編寫pl/sql程式實際上就是編寫pl/sql塊。
要完成相對簡單的應用功能,可能只需要編寫一個塊,但是如果要實現比較複雜的功能,可能要在一個pl/sql塊中巢狀其他的pl/sql塊

8.塊的組成部分:
有三部分組成:定義部分,執行部分,例外處理部分。如下所示:
declare
/*定義部分:-----定義常量,變數,遊標,例外,複雜資料型別*/
begin
/*執行部分-----要執行的pl/sql語句,和sql語句*/
exception
/*例外處理部分:-----處理執行的各種錯誤*/
end;

9:dbms_output 是oracle所提供的包(類似java裡面的開發包,)
該包包含一些過程,put_line 就是dbms_output包的一個過程
單引號
只有執行過程的塊:
set serveroutput on; --設定輸出
begin
dbms_output.put_line('hello,world');
end;
/
有定義變數部分和執行過程的塊:
declare
--定義變數的格式是:變數名稱 變數的型別
v_ename varchar2(16);
begin
select ename into v_ename from emp where empno=&empno;--把查詢的ename值放入v_ename
--輸出v_ename
dbms_output.put_line('僱員名是'||v_ename); --||是oracle裡面的拼接
end;
/
【注意】塊執行完後就沒有了
將上面的語句改為儲存過程:
create procedure emp_pro2(in_empnum number) is
--定義變數的格式是:變數名稱 變數的型別
v_ename varchar2(16);
begin
select ename into v_ename from emp where empno=in_empnum;--把查詢的ename值放入v_ename
--輸出v_ename
dbms_output.put_line('僱員名是'||v_ename); --||是oracle裡面的拼接
end;
/

3.例項3包含定義部分,執行部分,和例外處理部分
為了避免pl/sql程式的執行錯誤,提高pl/sql的健壯性,應該對可能的錯誤進行處理,這個很有必要:
①比如例項2中,如果輸入了不存在的僱員號,應當做例外處理
②有時出現異常,希望用另外的邏輯處理:比如如果不存在,就加入編號為1,名字為“馬大哈”這個人

4.案例:包含定義部分,執行部分,例外處理部分
declare
v_ename varchar2(32);
begin
select ename into v_ename from emp where empno=&empno;
--輸出使用者的名字
dbms_output.put_line('僱員名'||v_ename);
exception
when no_data_found then  --【注意】no_data_found用於select into中

dbms_output.put_line('你輸入的編號有誤');
end;
/
//異常處理的語法
exception
when 異常的名稱 then
//對異常處理的程式碼
//對異常處理的程式碼
when 異常的名稱 then
//對異常處理的程式碼
end;
//【可以使用異常處理進行業務邏輯的處理】

4.儲存過程的輸入變數和輸出變數:
create procedure 過程名
(變數名 in 變數型別……,變數名 out 變數型別……)
is
//這裡可以定義變數
begin
end;

【注意】如果沒有指名變數的in/out,預設為in
in/out 均可以有多個
如:
create procedure pro5
(in_ename in varchar2,in_new_sal in number)--varchar2不用指定長度
is
begin
update emp set sal=in_new_sal where ename=in_ename;
end;
//oracle中檢視錯誤:show error
呼叫儲存過程:exec/call pro5

5.函式:用於返回特定的資料,當建立函式時,在函式頭部必須包含return子句,
而在函式體內必須包含return語句返回的資料,可以使用
create function來建立函式。
語法:
create function 函式名(引數1……)
return 資料型別 is
定義變數;
begin
執行語句;
end;

//如:編寫一個函式接收使用者名稱,並返回使用者的年薪
create function fun1(v_in_ename varchar2)
return number is
--定義變數
v_annual_sal number;
begin
select (sal+nvl(comm,0))*13 into v_annual_sal
from emp where ename=v_in_ename;
return v_annual_sal;
end;
/
//呼叫函式,跟oracle自定義的函式一樣了
select fun1('SMITH') from dual;//直接用虛表

//或者
--直接呼叫函式
var v_annual_sal number;
call fun1('FORD') into:v_annual_sal;
print v_annual_sal;


6.oracle中的包(package):主要用來管理過程,函式,異常,遊標等
建立語法:
create package 包名 is
--宣告函式,過程等,只宣告不實現
function 函式名(變數名 變數型別……) return 返回型別;
procedure 過程名(變數名 變數型別……);
end;
//舉例:
create package mypackage1 is
--宣告一個過程
procedure pro1(v_in_ename varchar2,v_in_newsal number);
--宣告一個函式
function fun1(v_in_ename varchar2) return number;
end;


【包聲明後,需要去實現才能使用,如下】
create package body mypackage1 is  --實現宣告的包體
--實現過程
procedure pro1(v_in_ename varchar2,v_in_newsal number) is
begin 
update emp set sal=v_in_newsal where ename=v_in_ename;
end;
--實現函式
function fun1(v_in_ename varchar2) return number is
v_annual_sal number;
begin
select (sal+nvl(comm,0))*13 into v_annual_sal from emp 
where ename=v_in_ename;
return v_in_ename;
end;
end;


//呼叫包體
exec mypackage1.pro1('SMITH',3000);
【細節:】
①包體中藥實現的方法或者過程,需要在包中宣告
②在呼叫包中的某個方法/過程的時候,在過程和函式前需要帶有包名,
如果需要呼叫其他方案的包,還需要在包前面加上方案名
exec 方案名.包名.過程名(引數值……);
call 方案名.包名.函式名(引數值……);

【注意】在java中呼叫包中的過程或者方法,跟直接呼叫差不多,
只需要加上:方案名.包名

7.觸發器
觸發器是一個隱含執行的過程,它不是有程式或者DBA來顯示呼叫,而是因為某個操作觸發執行的。

8.PL/sql詳解:
編寫pl/sql程式時,可以定義變數和常量,在pl/sql程式中,包括有:
①標量型別(scalar) ②複合型別(composite) ③參照型別(reference) ④lob(large object)
①標量型別(scalar)
語法:
identifier [constant] datatype [not null][:=|defalut expr] //賦初值用:=
identifier:名稱
constant:指定常量,需要指定它的初始值,且值是不可改變的
datatype:資料型別
not null:指定變數值不能為null
:= 給變數或者常量指定初始值
default:用於指定初始值
expr:指定初始值的pl/sql表示式,可以是文字值,其他變數,函式等
舉例:輸入人員編號,顯示出該僱員的姓名,工資,個人所得稅(稅率是0.03)
--建立一個儲存過程
create or replace procedure pro1(v_in_empno number) is
--定義變數
v_tax_rate number(3,2):=0.03;
v_sal number;
v_ename varchar2(32);
v_tax number;
begin
select ename,sal into v_ename,v_sal from emp
where empno=v_in_empno;
--計算個人所得稅
v_tax:=v_sal*v_tax_rate ;
dbms_output.put_line(v_ename||'工資是='||v_sal||'個人所得稅是:'||v_tax);
end;
【注意:】標量使用%type型別

對於上面的pl/sql塊有個問題,如果員工的姓名超過5個字元的話,就會有錯誤,
為了降低pl/sql程式的維護工作量,可以使用%type屬性定義變數,這樣它會按照資料庫列來確定你定義的變數的型別和長度。
用法:識別符號名 表名.列名%type;
如:v_name emp.ename%type;
【注意】上面的意思是定義變數的時候跟表的型別自適應


②複合型別(composite):用於存放多個值得變數,常用的包括:
(1)pl/sql記錄
類似於高階語言中的結構體,需要注意的是,當引用pl/sql記錄成員時,必須要加
記錄變數作為字首(記錄變數.記錄成員),語法如下:
type 自定義的pl/sql記錄名 is record(
變數名 變數型別,
變數名 變數型別
);
//使用自定義的pl/sql記錄
變數名 自定義的pl/sql記錄名
【案例】編寫一個過程,該過程可以接收一個使用者編號,並顯示該使用者的名字,薪水,工作崗位(注意:使用pl/sql記錄實現)
create or replace procedure pro1(v_in_empno in number)
is
--定義一個記錄資料型別
type zy_emp_record is record(
v_ename emp.ename%type;
v_sal emp.sal%type;
v_job emp.job%type;
);
--定義一個變數,該變數的型別是zy_emp_record
v_emp_record zy_emp_record;
begin 
select ename,sal,job into v_emp_record
from emp where empno=v_in_empno;
dbms_output.put_line('名字:'||v_emp_record.v_ename||'工資:'||v_emp_record.v_sal);
end;


(2)pl/sql表【瞭解】
③參照型別(reference)