1、過程
過程是執行一系列PL/SQL操做的組合程序塊,能夠向存儲過程傳遞參數,也能夠從存儲過程傳回參數,創建後
存儲在數據庫服務器上,可供屢次調用;能夠將商業邏輯、企業規則寫成函數或過程保存到數據庫中,以便共享。
1.建立過程
create or replace procedure pro_name (var_var in/out datatype)
is/as
變量聲明區
begin
業務程序區
exception
異常區
end;
2.過程的參數
a.in 能夠是常量,變量,varchar2類型在參數中不用指定大小
b.out 只能是變量
3.查詢過程的定義
select dbms_metadata.get_ddl('PROCEDURE','PROCE_01') FROM DUAL;
select text from user_source where name = 'PROCE_01';
4.過程依賴的表刪掉後,過程會變成invalid的,當表恢復後,過程不是系統自動維護,因此須要從新編譯:
alter procedure PROCE_01 compile;
5.過程的調用
exec procedure_name(parameters..);
6.過程使用
a.刪除指定員工記錄;
CREATE OR REPLACE PROCEDURE DelEmp
(v_empno IN employees.employee_id%TYPE)
AS
No_result EXCEPTION;
BEGIN
DELETE FROM employees WHERE employee_id = v_empno;
IF SQL%NOTFOUND THEN
RAISE no_result;
END IF;
DBMS_OUTPUT.PUT_LINE('編碼爲'||v_empno||'的員工已被刪除!');
EXCEPTION
WHEN no_result THEN
DBMS_OUTPUT.PUT_LINE('舒適提示:你須要的數據不存在!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END DelEmp;
--調用
DECLARE
v1 employees.first_name%TYPE;
v2 employees.salary%TYPE;
BEGIN
QueryEmp(100, v1, v2);
DBMS_OUTPUT.PUT_LINE('姓名:'||v1);
DBMS_OUTPUT.PUT_LINE('工資:'||v2);
END;
b.使用存儲過程向departments表中插入數據。
CREATE OR REPLACE PROCEDURE insert_dept
(v_dept_id IN departments.department_id%TYPE,
v_dept_name IN departments.department_name%TYPE,
v_mgr_id IN departments.manager_id%TYPE,
v_loc_id IN departments.location_id%TYPE)
IS
ept_null_error EXCEPTION;
PRAGMA EXCEPTION_INIT(ept_null_error, -1400);
ept_no_loc_id EXCEPTION;
PRAGMA EXCEPTION_INIT(ept_no_loc_id, -2291);
BEGIN
INSERT INTO departments
(department_id, department_name, manager_id, location_id)
VALUES
(v_dept_id, v_dept_name, v_mgr_id, v_loc_id);
DBMS_OUTPUT.PUT_LINE('插入部門'||v_dept_id||'成功');
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
RAISE_APPLICATION_ERROR(-20000, '部門編碼不能重複');
WHEN ept_null_error THEN
RAISE_APPLICATION_ERROR(-20001, '部門編碼、部門名稱不能爲空');
WHEN ept_no_loc_id THEN
RAISE_APPLICATION_ERROR(-20002, '沒有該地點');
END insert_dept;
7.刪除過程,不帶參數只用名稱
DROP PROCEDURE [user.]Procudure_name;sql
2、函數
是被命名的PL/SQL塊,用於返回特定的數據,必需要有return字句,在函數的任何地方均可以經過return表達
式語句從函數返回,這裏的表達式的值與函數定義中指定的返回數據類型一致
1.函數定義
create or replace function funct_name (var_l in/out datatype)
return datatype
is/as
begin
function_body;
end;
2.函數的調用及參數傳遞
a.傳址法是指在調用函數時,將實際參數的地址指針傳遞給形式參數,使形式參數和實際參數指向內存中的同一
區域,從而實現參數數據的傳遞。這種方法又稱做參照法,即形式參數參照實際參數數據。輸入參數均採用傳址
法傳遞數據。
b.傳值法是指將實際參數的數據拷貝到形式參數,而不是傳遞實際參數的地址。默認時,輸出參數和輸入/輸出
參數均採用傳值法。在函數調用時,ORACLE將實際參數數據拷貝到輸入/輸出參數,而當函數正常運行退出時,
又將輸出形式參數和輸入/輸出形式參數數據拷貝到實際參數變量中。
c.調用函數
DECLARE
V_num NUMBER;
V_sum NUMBER;
BEGIN
V_sum :=get_salary(10, v_num);
DBMS_OUTPUT.PUT_LINE('部門號爲:10的工資總和:'||v_sum||',人數爲:'||v_num);
END;
3.函數的使用
a.eg
CREATE OR REPLACE FUNCTION demo_fun(
Name VARCHAR2,--注意VARCHAR2不能給精度,如:VARCHAR2(10),其它相似
Age INTEGER,
Sex VARCHAR2 DEFAULT '男')
RETURN VARCHAR2
AS
V_var VARCHAR2(32);
BEGIN
V_var := name||':'||TO_CHAR(age)||'歲.'||sex;
RETURN v_var;
END;
DECLARE
Var VARCHAR(32);
BEGIN
Var := demo_fun('user1', 30, sex => '男');
DBMS_OUTPUT.PUT_LINE(var);
Var := demo_fun('user2', age => 40, sex => '男');
DBMS_OUTPUT.PUT_LINE(var);
Var := demo_fun('user3', sex => '女', age => 20);
DBMS_OUTPUT.PUT_LINE(var);
END;
4.刪除函數
drop function_name;
3、函數和過程的聯繫
1.受權
GRANT EXECUTE ON procedure_name[function_name] TO user_naem [PUBLIC] [WITH GRANT OPTION]
2.函數與過程的區同
a.過程和函數的惟一區別是函數總向調用者返回數據,而過程則不返回數據;
b.過程和函數統稱爲PL/SQL子程序,他們是被命名的PL/SQL塊,均存儲在數據庫中,並經過輸入、輸出參
數或輸入/輸出參數與其調用者交換信息;
c.若是須要返回多個值和不返回值,就使用過程;若是隻須要返回一個值,就使用函數;
d.過程通常用於執行一個指定的動做,函數通常用於計算和返回一個值;
e.能夠SQL語句內部(如表達式)調用函數來完成複雜的計算問題,但不能調用過程。因此這是函數的特點。
2.使用過程與函數具備以下優勢:
a.共同使用的代碼能夠只須要被編寫和測試一次,而被須要該代碼的任何應用程序(如:.NET、C++、JAVA
、VB程序,也能夠是DLL庫)調用。
b.這種集中編寫、集中維護更新、你們共享(或重用)的方法,簡化了應用程序的開發和維護,提升了效率與性能。
c.這種模塊化的方法,使得能夠將一個複雜的問題、大的程序逐步簡化成幾個簡單的、小的程序部分,進行分別編
寫、調試。所以使程序的結構清晰、簡單,也容易實現。
d.能夠在各個開發者之間提供處理數據、控制流程、提示信息等方面的一致性。
e.節省內存空間。它們以一種壓縮的形式被存儲在外存中,當被調用時才被放入內存進行處理。而且,若是多個用
戶要執行相同的過程或函數時,就只須要在內存中加載一個該過程或函數。
f.提升數據的安全性與完整性。經過把一些對數據的操做放到過程或函數中,就能夠經過是否授予用戶有執行該過
程或的權限,來限制某些用戶對數據進行這些操做。數據庫
4、包
一種程序邏輯單元,包能夠將任何出如今塊聲明的語句 ( 過程 , 函數 , 遊標 , 遊標 , 類型 , 變量 ) 放於包
中 , 至關於一個容器。將聲明語句放入包中的好處是 : 用戶能夠從其餘 PL/SQL 塊中對其進行引用 , 所以包爲
PL/SQL 提供了全程變量。包能夠重載過程和函數,在包內能夠用同一個名字聲明多個程序,在運行時根據參
數的數目和數據類型調用正確的程序。安全
1.包和包體的定義
a.包定義
create or replace package p_stu
as
--定義結構體
type re_stu is record(
rname student.name%type,
rage student.age%type
);
--定義遊標
type c_stu is ref cursor;
--定義函數
function numAdd(num1 number,num2 number)return number;
--定義過程
procedure GetStuList(cid in varchar2,c_st out c_stu);
end;
b.包體實現
--實現包體,名稱一致。
create or replace package body p_stu
as
--遊標和結構體,包規範中已聲明,包體中不用再聲明,直接使用。
--實現方法
function numAdd(num1 number,num2 number)return number
as
num number;
begin
num:=num1+num2;
return num;
end;
--實現過程
procedure GetStuList(cid varchar2,c_st out c_stu)
as
r_stu re_stu; --直接使用包規範中的結構
begin
open c_st for select name,age from student where classid=cid;
-- 若是已經在過程當中遍歷了遊標,在使用這個過程的塊中,將沒有值。
-- loop
-- fetch c_st into r_stu;
-- exit when c_st%notfound;
-- dbms_output.put_line('姓名='||r_stu.rname);
-- end loop;
end;
end;
c.使用包
declare
c_stu p_stu.c_stu; --定義包中游標變量
r_stu p_stu.re_stu; --定義包中結構體變量
num number;
begin
--使用及遍歷包中過程返回的結果集
p_stu.GetStuList('C001',c_stu);
loop
fetch c_stu into r_stu;
exit when c_stu%notfound;
dbms_output.put_line('姓名='||r_stu.rname);
end loop;
--使用包中的方法
select p_stu.numAdd(5,6) into num from dual;
dbms_output.put_line('Num='||num);
end;
d.包的私有過程和函數:沒有在包定義過程聲明,只在包體中定義,只能在包體中相互引用,在包外引用會報
錯‘00302必須聲明…..’也不能用desc命令展現結構包中聲明,可是在包體中沒有具體定義,編譯也會報錯‘00323’服務器
5、PL/SQL動態sql使用
1.靜態SQLSQL與動態SQL
前期聯編(early binding),即SQL語句在程序編譯期間就已經肯定,大多數的編譯狀況屬於這種類型,靜態SQL採用;
後期聯編(late binding),即SQL語句只有在運行階段才能創建,動態SQL採用;
2.EXECUTE IMMEDIATE它解析並立刻執行動態的SQL語句或非運行時建立的PL/SQL塊.動態建立和執行SQL語句性能。語法
Excute immediate 動態SQL語句 using 綁定參數列表 returning into 輸出參數列表
3.使用事例
a.在PL/SQL運行DDL語句
begin
execute immediate 'set role all';
end;
b.給動態語句傳值(USING 子句)
declare
l_depnam varchar2(20) := 'testing';
l_loc varchar2(10) := 'Dubai';
begin
execute immediate 'insert into dept values (:1, :2, :3)'
using 50, l_depnam, l_loc;
commit;
end;
c.傳遞並檢索值.INTO子句用在USING子句前
declare
l_dept pls_integer := 20;
l_nam varchar2(20);
l_loc varchar2(20);
begin
execute immediate 'select dname, loc from dept where deptno = :1'
into l_nam, l_loc
using l_dept ;
end;
d.forall批聯編譯
declare
type num_list is varray(20) of number;
v_id num_list :=num_list(100,101);
begin
...
forall i in v_id.first .. v_id.last loop
...
execute immediate 'update emp set =salary*1.2
where id=:1 '
using v_id(i);
end loop;
end; 模塊化