----------異常錯誤處理---------html
即便是寫得最好的PL/SQL程序也會遇到錯誤或未預料到的事件。一個優秀的程序都應該可以正確處理各類出錯狀況,並儘量從錯誤中恢復。任何ORACLE錯誤(報告爲ORA-xxxxx形式的Oracle錯誤號)、PL/SQL運行錯誤或用戶定義條件(不一寫是錯誤),均可以。固然了,PL/SQL編譯錯誤不能經過PL/SQL異常處理來處理,由於這些錯誤發生在PL/SQL程序執行以前。程序員
ORACLE 提供異常狀況(EXCEPTION)和異常處理(EXCEPTION HANDLER)來實現錯誤處理。算法
異常狀況處理(EXCEPTION)是用來處理正常執行過程當中未預料的事件,程序塊的異常處理預約義的錯誤和自定義錯誤,因爲PL/SQL程序塊一旦產生異常而沒有指出如何處理時,程序就會自動終止整個程序運行. sql
有三種類型的異常錯誤:數據庫
1. 預約義 ( Predefined )錯誤express
ORACLE預約義的異常狀況大約有24個。對這種異常狀況的處理,無需在程序中定義,由ORACLE自動將其引起。編程
2. 非預約義 ( Predefined )錯誤c#
即其餘標準的ORACLE錯誤。對這種異常狀況的處理,須要用戶在程序中定義,而後由ORACLE自動將其引起。安全
3. 用戶定義(User_define) 錯誤服務器
程序執行過程當中,出現編程人員認爲的非正常狀況。對這種異常狀況的處理,須要用戶在程序中定義,而後顯式地在程序中將其引起。
異常處理部分通常放在 PL/SQL 程序體的後半部,結構爲:
EXCEPTION
WHEN first_exception THEN <code to handle first exception >
WHEN second_exception THEN <code to handle second exception >
WHEN OTHERS THEN <code to handle others exception >
END;
異常處理能夠按任意次序排列,但 OTHERS 必須放在最後。
5.1.1 預約義的異常處理
預約義說明的部分 ORACLE 異常錯誤
錯誤號 |
異常錯誤信息名稱 |
說明 |
ORA-0001 |
Dup_val_on_index |
違反了惟一性限制 |
ORA-0051 |
Timeout-on-resource |
在等待資源時發生超時 |
ORA-0061 |
Transaction-backed-out |
因爲發生死鎖事務被撤消 |
ORA-1001 |
Invalid-CURSOR |
試圖使用一個無效的遊標 |
ORA-1012 |
Not-logged-on |
沒有鏈接到ORACLE |
ORA-1017 |
Login-denied |
無效的用戶名/口令 |
ORA-1403 |
No_data_found |
SELECT INTO沒有找到數據 |
ORA-1422 |
Too_many_rows |
SELECT INTO 返回多行 |
ORA-1476 |
Zero-divide |
試圖被零除 |
ORA-1722 |
Invalid-NUMBER |
轉換一個數字失敗 |
ORA-6500 |
Storage-error |
內存不夠引起的內部錯誤 |
ORA-6501 |
Program-error |
內部錯誤 |
ORA-6502 |
Value-error |
轉換或截斷錯誤 |
ORA-6504 |
Rowtype-mismatch |
宿主遊標變量與 PL/SQL變 量有不兼容行類型 |
ORA-6511 |
CURSOR-already-OPEN |
試圖打開一個已處於打開狀 態的遊標 |
ORA-6530 |
Access-INTO-null |
試圖爲null 對象的屬性賦值 |
ORA-6531 |
Collection-is-null |
試圖將Exists 之外的集合( collection)方法應用於一個null pl/sql 表上或varray上 |
ORA-6532 |
Subscript-outside-limit |
對嵌套或varray索引得引用超出聲明範圍之外 |
ORA-6533 |
Subscript-beyond-count |
對嵌套或varray 索引得引用大於集合中元素的個數. |
對這種異常狀況的處理,只需在PL/SQL塊的異常處理部分,直接引用相應的異常狀況名,並對其完成相應的異常錯誤處理便可。
例1:更新指定員工工資,如工資小於1500,則加100;
DECLARE
v_empno employees.employee_id%TYPE := &empno;
v_sal employees.salary%TYPE;
BEGIN
SELECT salary INTO v_sal FROM employees WHERE employee_id = v_empno;
IF v_sal<=1500 THEN
UPDATE employees SET salary = salary + 100 WHERE employee_id=v_empno;
DBMS_OUTPUT.PUT_LINE('編碼爲'||v_empno||'員工工資已更新!');
ELSE
DBMS_OUTPUT.PUT_LINE('編碼爲'||v_empno||'員工工資已經超過規定值!');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('數據庫中沒有編碼爲'||v_empno||'的員工');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('程序運行錯誤!請使用遊標');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;
5.1.2 非預約義的異常處理
對於這類異常狀況的處理,首先必須對非定義的ORACLE錯誤進行定義。步驟以下:
1. 在PL/SQL 塊的定義部分定義異常狀況:
<異常狀況> EXCEPTION;
2. 將其定義好的異常狀況,與標準的ORACLE錯誤聯繫起來,使用EXCEPTION_INIT語句:
PRAGMA EXCEPTION_INIT(<異常狀況>, <錯誤代碼>);
3. 在PL/SQL 塊的異常狀況處理部分對異常狀況作出相應的處理。
例2:刪除指定部門的記錄信息,以確保該部門沒有員工。
INSERT INTO departments VALUES(50, 'FINANCE', 'CHICAGO');
DECLARE
v_deptno departments.department_id%TYPE := &deptno;
deptno_remaining EXCEPTION;
PRAGMA EXCEPTION_INIT(deptno_remaining, -2292);
/* -2292 是違反一致性約束的錯誤代碼 */
BEGIN
DELETE FROM departments WHERE department_id = v_deptno;
EXCEPTION
WHEN deptno_remaining THEN
DBMS_OUTPUT.PUT_LINE('違反數據完整性約束!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;
5.1.3 用戶自定義的異常處理
當與一個異常錯誤相關的錯誤出現時,就會隱含觸發該異常錯誤。用戶定義的異常錯誤是經過顯式使用 RAISE 語句來觸發。當引起一個異常錯誤時,控制就轉向到 EXCEPTION塊異常錯誤部分,執行錯誤處理代碼。
對於這類異常狀況的處理,步驟以下:
1. 在PL/SQL 塊的定義部分定義異常狀況:
<異常狀況> EXCEPTION;
2. RAISE <異常狀況>;
3. 在PL/SQL 塊的異常狀況處理部分對異常狀況作出相應的處理。
例3:更新指定員工工資,增長100;
DECLARE
v_empno employees.employee_id%TYPE :=&empno;
no_result EXCEPTION;
BEGIN
UPDATE employees SET salary = salary+100 WHERE employee_id = v_empno;
IF SQL%NOTFOUND THEN
RAISE no_result;
END IF;
EXCEPTION
WHEN no_result THEN
DBMS_OUTPUT.PUT_LINE('你的數據更新語句失敗了!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;
5.1.4 用戶定義的異常處理
調用DBMS_STANDARD(ORACLE提供的包)包所定義的RAISE_APPLICATION_ERROR過程,能夠從新定義異常錯誤消息,它爲應用程序提供了一種與ORACLE交互的方法。
RAISE_APPLICATION_ERROR 的語法以下:
RAISE_APPLICATION_ERROR(error_number,error_message,[keep_errors] );
這裏的error_number 是從 –20,000 到 –20,999 之間的參數,
error_message 是相應的提示信息(< 2048 字節),
keep_errors 爲可選,若是keep_errors =TRUE ,則新錯誤將被添加到已經引起的錯誤列表中。若是keep_errors=FALSE(缺省),則新錯誤將替換當前的錯誤列表。
例4:定義觸發器,使用RAISE_APPLICATION_ERROR阻止沒有員工姓名的新員式記錄插入:
CREATE OR REPLACE TRIGGER tr_insert_emp
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
IF :new.first_name IS NULL OR :new.last_name is null THEN
RAISE_APPLICATION_ERROR(-20000,'Employee must have a name.');
END IF;
END;
因爲異常錯誤能夠在聲明部分和執行部分以及異常錯誤部分出現,於是在不一樣部分引起的異常錯誤也不同。
5.2.1 在執行部分引起異常錯誤
當一個異常錯誤在執行部分引起時,有下列狀況:
l 若是當前塊對該異常錯誤設置了處理,則執行它併成功完成該塊的執行,而後控制轉給包含塊。
l 若是沒有對當前塊異常錯誤設置定義處理器,則經過在包含塊中引起它來傳播異常錯誤。而後對該包含塊執行步驟1)。
5.2.2 在聲明部分引起異常錯誤
若是在聲明部分引發異常狀況,即在聲明部分出現錯誤,那麼該錯誤就能影響到其它的塊。好比在有以下的PL/SQL程序:
DECLARE
name varchar2(12):='EricHu';
其它語句
BEGIN
其它語句
EXCEPTION
WHEN OTHERS THEN
其它語句
END;
例子中,因爲Abc number(3)=’abc’; 出錯,儘管在EXCEPTION中說明了WHEN OTHERS THEN語句,但WHEN OTHERS THEN也不會被執行。 可是若是在該錯誤語句塊的外部有一個異常錯誤,則該錯誤能被抓住,如:
BEGIN
DECLARE
name varchar2(12):='EricHu';
其它語句
BEGIN
其它語句
EXCEPTION
WHEN OTHERS THEN
其它語句
END;
EXCEPTION
WHEN OTHERS THEN
其它語句
END;
在通常的應用處理中,建議程序人員要用異常處理,由於若是程序中不聲明任何異常處理,則在程序運行出錯時,程序就被終止,而且也不提示任何信息。下面是使用系統提供的異常來編程的例子。
因爲ORACLE 的錯信息最大長度是512字節,爲了獲得完整的錯誤提示信息,咱們可用 SQLERRM和 SUBSTR 函數一塊兒獲得錯誤提示信息,方便進行錯誤,特別是若是WHEN OTHERS異常處理器時更爲方便。
SQLCODE 返回遇到的Oracle錯誤號,
SQLERRM 返回遇到的Oracle錯誤信息.
如: SQLCODE=-100 è SQLERRM=’no_data_found ‘
SQLCODE=0 è SQLERRM=’normal, successfual completion’
例1:將ORACLE錯誤代碼及其信息存入錯誤代碼表
CREATE TABLE errors (errnum NUMBER(4), errmsg VARCHAR2(100));
DECLARE
err_msg VARCHAR2(100);
BEGIN
/* 獲得全部 ORACLE 錯誤信息 */
FOR err_num IN -100 .. 0 LOOP
err_msg := SQLERRM(err_num);
INSERT INTO errors VALUES(err_num, err_msg);
END LOOP;
END;
DROP TABLE errors;
例2:查詢ORACLE錯誤代碼;
BEGIN
INSERT INTO employees(employee_id, first_name,last_name,hire_date,department_id)
VALUES(2222, 'Eric','Hu', SYSDATE, 20);
DBMS_OUTPUT.PUT_LINE('插入數據記錄成功!');
INSERT INTO employees(employee_id, first_name,last_name,hire_date,department_id)
VALUES(2222, '胡','勇', SYSDATE, 20);
DBMS_OUTPUT.PUT_LINE('插入數據記錄成功!');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;
例3: 利用ORACLE錯誤代碼,編寫異常錯誤處理代碼;
DECLARE
empno_remaining EXCEPTION;
PRAGMA EXCEPTION_INIT(empno_remaining, -1);
/* -1 是違反惟一約束條件的錯誤代碼 */
BEGIN
INSERT INTO employees(employee_id, first_name,last_name,hire_date,department_id)
VALUES(3333, 'Eric','Hu', SYSDATE, 20);
DBMS_OUTPUT.PUT_LINE('插入數據記錄成功!');
INSERT INTO employees(employee_id, first_name,last_name,hire_date,department_id)
VALUES(3333, '胡','勇',SYSDATE, 20);
DBMS_OUTPUT.PUT_LINE('插入數據記錄成功!');
EXCEPTION
WHEN empno_remaining THEN
DBMS_OUTPUT.PUT_LINE('違反數據完整性約束!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;
***********************************************
-----------把過程與函數說透-----------
過程與函數(另外還有包與觸發器)是命名的PL/SQL塊(也是用戶的方案對象),被編譯後存儲在數據庫中,以備執行。所以,其它PL/SQL塊能夠按名稱來使用他們。因此,能夠將商業邏輯、企業規則寫成函數或過程保存到數據庫中,以便共享。
過程和函數統稱爲PL/SQL子程序,他們是被命名的PL/SQL塊,均存儲在數據庫中,並經過輸入、輸出參數或輸入/輸出參數與其調用者交換信息。過程和函數的惟一區別是函數總向調用者返回數據,而過程則不返回數據。在本節中,主要介紹:
1. 建立存儲過程和函數。
2. 正確使用系統級的異常處理和用戶定義的異常處理。
3. 創建和管理存儲過程和函數。
1. 建立函數(語法以下:)
CREATE
[
OR
REPLACE
]
FUNCTION
function_name
(arg1 [ {
IN
|
OUT
|
IN
OUT
}] type1 [
DEFAULT
value1],
[arg2 [ {
IN
|
OUT
|
IN
OUT
}] type2 [
DEFAULT
value1]],
......
[argn [ {
IN
|
OUT
|
IN
OUT
}] typen [
DEFAULT
valuen]])
[ AUTHID DEFINER |
CURRENT_USER
]
RETURN
return_type
IS
|
AS
<類型.變量的聲明部分>
BEGIN
執行部分
RETURN
expression
EXCEPTION
異常處理部分
END
function_name;
l IN,OUT,IN OUT是形參的模式。若省略,則爲IN模式。IN模式的形參只能將實參傳遞給形參,進入函數內部,但只能讀不能寫,函數返回時實參的值不變。OUT模式的形參會忽略調用時的實參值(或說該形參的初始值老是NULL),但在函數內部能夠被讀或寫,函數返回時形參的值會賦予給實參。IN OUT具備前兩種模式的特性,即調用時,實參的值老是傳遞給形參,結束時,形參的值傳遞給實參。調用時,對於IN模式的實參能夠是常量或變量,但對於OUT和IN OUT模式的實參必須是變量。
l 通常,只有在確認function_name函數是新函數或是要更新的函數時,才使用OR REPALCE關鍵字,不然容易刪除有用的函數。
例子:獲取某部門的工資總和:
--獲取某部門的工資總和
CREATE
OR
REPLACE
FUNCTION
get_salary(
Dept_no NUMBER,
Emp_count
OUT
NUMBER)
RETURN
NUMBER
IS
V_sum NUMBER;
BEGIN
SELECT
SUM
(SALARY),
count
(*)
INTO
V_sum, emp_count
FROM
EMPLOYEES
WHERE
DEPARTMENT_ID=dept_no;
RETURN
v_sum;
EXCEPTION
WHEN
NO_DATA_FOUND
THEN
DBMS_OUTPUT.PUT_LINE(
'你須要的數據不存在!'
);
WHEN
OTHERS
THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||
'---'
||SQLERRM);
END
get_salary;
2. 函數的調用
函數聲明時所定義的參數稱爲形式參數,應用程序調用時爲函數傳遞的參數稱爲實際參數。應用程序在調用函數時,可使用如下三種方法向函數傳遞參數:
第一種參數傳遞格式:位置表示法。
即在調用時按形參的排列順序,依次寫出實參的名稱,而將形參與實參關聯起來進行傳遞。用這種方法進行調用,形參與實參的名稱是相互獨立,沒有關係,強調次序纔是重要的。
格式爲:
1
|
argument_value1[,argument_value2 …]
|
例子:計算某部門的工資總和:
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
;
第二種參數傳遞格式:名稱表示法。
即在調用時按形參的名稱與實參的名稱,寫出實參對應的形參,而將形參與實參關聯起來進行傳遞。這種方法,形參與實參的名稱是相互獨立的,沒有關係,名稱的對應關係纔是最重要的,次序並不重要。
格式爲:
1
|
argument => parameter [,…]
|
其中:argument 爲形式參數,它必須與函數定義時所聲明的形式參數名稱相同parameter 爲實際參數。
在這種格式中,形勢參數與實際參數成對出現,相互間關係惟一肯定,因此參數的順序能夠任意排列。
例子:計算某部門的工資總和:
DECLARE
V_num NUMBER;
V_sum NUMBER;
BEGIN
V_sum :=get_salary(emp_count => v_num, dept_no => 10);
DBMS_OUTPUT.PUT_LINE(
'部門號爲:10的工資總和:'
||v_sum||
',人數爲:'
||v_num);
END
;
第三種參數傳遞格式:組合傳遞。
即在調用一個函數時,同時使用位置表示法和名稱表示法爲函數傳遞參數。採用這種參數傳遞方法時,使用位置表示法所傳遞的參數必須放在名稱表示法所傳遞的參數前面。也就是說,不管函數具備多少個參數,只要其中有一個參數使用名稱表示法,其後全部的參數都必須使用名稱表示法。
CREATE
OR
REPLACE
FUNCTION
demo_fun(
Name
VARCHAR2,
--注意VARCHAR2不能給精度,如:VARCHAR2(10),其它相似
Age
INTEGER
,
Sex VARCHAR2)
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
;
不管採用哪種參數傳遞方法,實際參數和形式參數之間的數據傳遞只有兩種方法:傳址法和傳值法。所謂傳址法是指在調用函數時,將實際參數的地址指針傳遞給形式參數,使形式參數和實際參數指向內存中的同一區域,從而實現參數數據的傳遞。這種方法又稱做參照法,即形式參數參照實際參數數據。輸入參數均採用傳址法傳遞數據。
傳值法是指將實際參數的數據拷貝到形式參數,而不是傳遞實際參數的地址。默認時,輸出參數和輸入/輸出參數均採用傳值法。在函數調用時,ORACLE將實際參數數據拷貝到輸入/輸出參數,而當函數正常運行退出時,又將輸出形式參數和輸入/輸出形式參數數據拷貝到實際參數變量中。
3. 參數默認值
在CREATE OR REPLACE FUNCTION 語句中聲明函數參數時可使用DEFAULT關鍵字爲輸入參數指定默認值。
CREATE
OR
REPLACE
FUNCTION
demo_fun(
Name
VARCHAR2,
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
varVARCHAR(32);
BEGIN
Var := demo_fun(
'user1'
, 30);
DBMS_OUTPUT.PUT_LINE(var);
Var := demo_fun(
'user2'
, age => 40);
DBMS_OUTPUT.PUT_LINE(var);
Var := demo_fun(
'user3'
, sex =>
'女'
, age => 20);
DBMS_OUTPUT.PUT_LINE(var);
END
;
6.3.1 建立過程
創建存儲過程
在 ORACLE SERVER上創建存儲過程,能夠被多個應用程序調用,能夠向存儲過程傳遞參數,也能夠向存儲過程傳回參數.
建立過程語法:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
CREATE
[
OR
REPLACE
]
PROCEDURE
procedure_name
([arg1 [
IN
|
OUT
|
IN
OUT
]] type1 [
DEFAULT
value1],
[arg2 [
IN
|
OUT
|
IN
OUT
]] type2 [
DEFAULT
value1]],
......
[argn [
IN
|
OUT
|
IN
OUT
]] typen [
DEFAULT
valuen])
[ AUTHID DEFINER |
CURRENT_USER
]
{
IS
|
AS
}
<聲明部分>
BEGIN
<執行部分>
EXCEPTION
<可選的異常錯誤處理程序>
END
procedure_name;
|
說明:相關參數說明參見函數的語法說明。
例子:使用存儲過程向departments表中插入數據。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
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;
/*調用實例一:
DECLARE
ept_20000 EXCEPTION;
PRAGMA EXCEPTION_INIT(ept_20000, -20000);
ept_20001 EXCEPTION;
PRAGMA EXCEPTION_INIT(ept_20001, -20001);
ept_20002 EXCEPTION;
PRAGMA EXCEPTION_INIT(ept_20002, -20002);
BEGIN
insert_dept(300, '部門300', 100, 2400);
insert_dept(310, NULL, 100, 2400);
insert_dept(310, '部門310', 100, 900);
EXCEPTION
WHEN ept_20000 THEN
DBMS_OUTPUT.PUT_LINE('ept_20000部門編碼不能重複');
WHEN ept_20001 THEN
DBMS_OUTPUT.PUT_LINE('ept_20001部門編碼、部門名稱不能爲空');
WHEN ept_20002 THEN
DBMS_OUTPUT.PUT_LINE('ept_20002沒有該地點');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('others出現了其餘異常錯誤');
END;
調用實例二:
DECLARE
ept_20000 EXCEPTION;
PRAGMA EXCEPTION_INIT(ept_20000, -20000);
ept_20001 EXCEPTION;
PRAGMA EXCEPTION_INIT(ept_20001, -20001);
ept_20002 EXCEPTION;
PRAGMA EXCEPTION_INIT(ept_20002, -20002);
BEGIN
insert_dept(v_dept_name => '部門310', v_dept_id => 310,
v_mgr_id => 100, v_loc_id => 2400);
insert_dept(320, '部門320', v_mgr_id => 100, v_loc_id => 900);
EXCEPTION
WHEN ept_20000 THEN
DBMS_OUTPUT.PUT_LINE('ept_20000部門編碼不能重複');
WHEN ept_20001 THEN
DBMS_OUTPUT.PUT_LINE('ept_20001部門編碼、部門名稱不能爲空');
WHEN ept_20002 THEN
DBMS_OUTPUT.PUT_LINE('ept_20002沒有該地點');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('others出現了其餘異常錯誤');
END;
*/
|
6.3.2 調用存儲過程
存儲過程創建完成後,只要經過受權,用戶就能夠在SQLPLUS 、ORACLE開發工具或第三方開發工具中來調用運行。對於參數的傳遞也有三種:按位置傳遞、按名稱傳遞和組合傳遞,傳遞方法與函數的同樣。ORACLE 使用EXECUTE 語句來實現對存儲過程的調用:
EXEC[UTE] procedure_name( parameter1, parameter2…);
例:EXECUTE logexecution;
在PL/SQL 程序中還能夠在塊內創建本地函數和過程,這些函數和過程不存儲在數據庫中,但能夠在建立它們的PL/SQL 程序中被重複調用。本地函數和過程在PL/SQL 塊的聲明部分定義,它們的語法格式與存儲函數和過程相同,但不能使用CREATE OR REPLACE 關鍵字。
例子:創建本地過程,用於計算指定部門的工資總和,並統計其中的職工數量;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
DECLARE
V_num NUMBER;
V_sum NUMBER(8, 2);
PROCEDURE
proc_demo
(
Dept_no NUMBER
DEFAULT
10,
Sal_sum
OUT
NUMBER,
Emp_count
OUT
NUMBER
)
IS
BEGIN
SELECT
SUM
(salary),
COUNT
(*)
INTO
sal_sum, emp_count
FROM
employees
WHERE
department_id=dept_no;
EXCEPTION
WHEN
NO_DATA_FOUND
THEN
DBMS_OUTPUT.PUT_LINE(
'你須要的數據不存在!'
);
WHEN
OTHERS
THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||
'---'
||SQLERRM);
END
proc_demo;
--調用方法:
BEGIN
Proc_demo(30, v_sum, v_num);
DBMS_OUTPUT.PUT_LINE(
'30號部門工資總和:'
||v_sum||
',人數:'
||v_num);
Proc_demo(sal_sum => v_sum, emp_count => v_num);
DBMS_OUTPUT.PUT_LINE(
'10號部門工資總和:'
||v_sum||
',人數:'
||v_num);
END
;
|
6.3.3 AUTHID
過程當中的AUTHID 指令能夠告訴ORACLE ,這個過程使用誰的權限運行.默任狀況下,存儲過程會做爲調用者的過程運行,可是具備設計者的特權.這稱爲設計者權利運行。
例子:創建過程,使用AUTOID CURRENT_USER;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
CONNECT
HR/qaz
CREATE
OR
REPLACE
PROCEDURE
logexecution
AUTHID
CURRENT_USER
IS
BEGIN
INSERT
INTO
logtable (userid, logdate)
VALUES
(
USER
, SYSDATE);
END
;
GRANT
EXECUTE
ON
logexecution
TO
PUBLIC
;
CONNECT
testuser1/userpwd1
INSERT
INTO
HR.LOGTABLE
VALUES
(
USER
, SYSDATE);
EXECUTE
HR.logexecution
|
6.3.4 PRAGMA AUTONOMOUS_TRANSACTION
ORACLE8i 能夠支持事務處理中的事務處理的概念.這種子事務處理能夠完成它本身的工做,獨立於父事務處理進行提交或者回滾.經過使用這種方法,開發者就可以這樣的過程,不管父事務處理是提交仍是回滾,它均可以成功執行。
例1:創建過程,使用自動事務處理進行日誌記錄;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
DROP
TABLE
logtable;
CREATE
TABLE
logtable(
Username varchar2(20),
Dassate_time
date
,
Mege varchar2(60)
);
CREATE
TABLE
temp_table( N number );
CREATE
OR
REPLACE
PROCEDURE
log_message(p_message varchar2)
AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT
INTO
logtable
VALUES
(
user
, sysdate, p_message );
COMMIT
;
END
log_message;
BEGIN
Log_message (‘About
to
insert
into
temp_table‘);
INSERT
INTO
temp_table
VALUES
(1);
Log_message (‘
Rollback
to
insert
into
temp_table‘);
ROLLBACK
;
END
;
SELECT
*
FROM
logtable;
SELECT
*
FROM
temp_table;
|
例2:創建過程,沒有使用自動事務處理進行日誌記錄;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
CREATE
OR
REPLACE
PROCEDURE
log_message(p_message varchar2)
AS
BEGIN
INSERT
INTO
logtable
VALUES
(
user
, sysdate, p_message );
COMMIT
;
END
log_message;
BEGIN
Log_message (
'About to insert into temp_table'
);
INSERT
INTO
temp_table
VALUES
(1);
Log_message (
'Rollback to insert into temp_table'
);
ROLLBACK
;
END
;
SELECT
*
FROM
logtable;
SELECT
*
FROM
temp_table;
|
6.3.5 開發存儲過程步驟
開發存儲過程、函數、包及觸發器的步驟以下:
使用文字編輯處理軟件編輯存儲過程源碼,要用相似WORD 文字處理軟件進行編輯時,要將源碼存爲文本格式。
在SQLPLUS或用調試工具將存儲過程程序進行解釋;
在SQL>下調試,可用START 或GET 等ORACLE命令來啓動解釋。如:
SQL>START c:\stat1.sql
若是使用調式工具,可直接編輯和點擊相應的按鈕便可生成存儲過程。
咱們不能保證所寫的存儲過程達到一次就正確。因此這裏的調式是每一個程序員必須進行的工做之一。在SQLPLUS下來調式主要用的方法是:
l 使用 SHOW ERROR命令來提示源碼的錯誤位置;
l 使用 user_errors 數據字典來查看各存儲過程的錯誤位置。
若是調式正確的存儲過程沒有進行受權,那就只有創建者本人才能夠運行。因此做爲應用系統的一部分的存儲過程也必須進行受權才能達到要求。在SQL*PLUS下能夠用GRANT命令來進行存儲過程的運行受權。
GRANT語法:
1
2
3
4
5
6
7
8
9
10
11
|
GRANT
system_privilege | role
TO
user
| role |
PUBLIC
[
WITH
ADMIN
OPTION
]
GRANT
object_privilege |
ALL
ON
schema
.object
TO
user
| role |
PUBLIC
[
WITH
GRANT
OPTION
]
--例子:
CREATE
OR
REPLACE
PUBLIC
SYNONYM dbms_job
FOR
dbms_job
GRANT
EXECUTE
ON
dbms_job
TO
PUBLIC
WITH
GRANT
OPTION
|
6.3.6 與過程相關數據字典
USER_SOURCE, ALL_SOURCE, DBA_SOURCE, USER_ERRORS,
ALL_PROCEDURES,USER_OBJECTS,ALL_OBJECTS,DBA_OBJECTS
相關的權限:
1
2
|
CREATE
ANY
PROCEDURE
DROP
ANY
PROCEDURE
|
在SQL*PLUS 中,能夠用DESCRIBE 命令查看過程的名字及其參數表。
1
|
DESC
[RIBE] Procedure_name;
|
6.3.7 刪除過程函數
1.刪除過程
可使用DROP PROCEDURE命令對不須要的過程進行刪除,語法以下:
1
|
DROP
PROCEDURE
[
user
.]Procudure_name;
|
2.刪除函數
可使用DROP FUNCTION 命令對不須要的函數進行刪除,語法以下:
1
2
3
4
5
6
7
8
9
10
11
12
|
DROP
FUNCTION
[
user
.]Function_name;
--刪除上面實例建立的存儲過程與函數
DROP
PROCEDURE
logexecution;
DROP
PROCEDURE
delemp;
DROP
PROCEDURE
insertemp;
DROP
PROCEDURE
fireemp;
DROP
PROCEDURE
queryemp;
DROP
PROCEDURE
proc_demo;
DROP
PROCEDURE
log_message;
DROP
FUNCTION
demo_fun;
DROP
FUNCTION
get_salary;
|
6.3.8 過程與函數的比較
使用過程與函數具備以下優勢:
一、共同使用的代碼能夠只須要被編寫和測試一次,而被須要該代碼的任何應用程序(如:.NET、C++、JAVA、VB程序,也能夠是DLL庫)調用。
二、這種集中編寫、集中維護更新、你們共享(或重用)的方法,簡化了應用程序的開發和維護,提升了效率與性能。
三、這種模塊化的方法,使得能夠將一個複雜的問題、大的程序逐步簡化成幾個簡單的、小的程序部分,進行分別編寫、調試。所以使程序的結構清晰、簡單,也容易實現。
四、能夠在各個開發者之間提供處理數據、控制流程、提示信息等方面的一致性。
五、節省內存空間。它們以一種壓縮的形式被存儲在外存中,當被調用時才被放入內存進行處理。而且,若是多個用戶要執行相同的過程或函數時,就只須要在內存中加載一個該過程或函數。
六、提升數據的安全性與完整性。經過把一些對數據的操做放到過程或函數中,就能夠經過是否授予用戶有執行該過程或的權限,來限制某些用戶對數據進行這些操做。
過程與函數的相同功能有:
一、 都使用IN模式的參數傳入數據、OUT模式的參數返回數據。
二、 輸入參數均可以接受默認值,均可以傳值或傳引導。
三、 調用時的實際參數均可以使用位置表示法、名稱表示法或組合方法。
四、 都有聲明部分、執行部分和異常處理部分。
五、 其管理過程都有建立、編譯、受權、刪除、顯示依賴關係等。
使用過程與函數的原則:
一、若是須要返回多個值和不返回值,就使用過程;若是隻須要返回一個值,就使用函數。
二、過程通常用於執行一個指定的動做,函數通常用於計算和返回一個值。
三、能夠SQL語句內部(如表達式)調用函數來完成複雜的計算問題,但不能調用過程。因此這是函數的特點。
*******************************************************************
---------程序包的建立與應用-----------
程序包(PACKAGE,簡稱包)是一組相關過程、函數、變量、常量和遊標等PL/SQL程序設計元素的組合,做爲一個完整的單元存儲在數據庫中,用名稱來標識包。它具備面向對象程序設計語言的特色,是對這些PL/SQL 程序設計元素的封裝。包相似於c#和JAVA語言中的類,其中變量至關於類中的成員變量,過程和函數至關於類方法。把相關的模塊歸類成爲包,可以使開發人員利用面向對象的方法進行存儲過程的開發,從而提升系統性能。
與高級語言中的類相同,包中的程序元素也分爲公用元素和私用元素兩種,這兩種元素的區別是他們容許訪問的程序範圍不一樣,即它們的做用域不一樣。公用元素不只能夠被包中的函數、過程所調用,也能夠被包外的PL/SQL程序訪問,而私有元素只能被包內的函數和過程序所訪問。
固然,對於不包含在程序包中的過程、函數是獨立存在的。通常是先編寫獨立的過程與函數,待其較爲完善或通過充分驗證無誤後,再按邏輯相關性組織爲程序包
程序包的優勢
u 簡化應用程序設計:程序包的說明部分和包體部分能夠分別建立各編譯。主要體現 在如下三個方面:
1) 能夠在設計一個應用程序時,只建立各編譯程序包的說明部分,而後再編寫引用該 程序包的PL/SQL塊。
2) 當完成整個應用程序的總體框架後,再回頭來定義包體部分。只要不改變包的說明部分,就能夠單獨調試、增長或替換包體的內容,這不會影響其餘的應用程序。
3) 更新包的說明後必須從新編譯引用包的應用程序,但更新包體,則不需從新編譯引用包的應用程序,以快速進行進行應用程序的原形開發。
u 模塊化:可將邏輯相關的PL/SQL塊或元素等組織在一塊兒,用名稱來惟一標識程序包。把一個大的功能模塊劃分人適當個數小的功能模塊,分別完成各自的功能。這樣組織的程序包都易於編寫,易於理解更易於管理。
u 信息隱藏:由於包中的元素能夠分爲公有元素和私有元素。公有元素可被程序包內的過程、函數等的訪問,還能夠被包外的PL/SQL訪問。但對於私有元素只能被包內的過程、函數等訪問。對於用戶,只需知道包的說明,不用瞭解包休的具體細節。
u 效率高:程序包在應用程序第一次調用程序包中的某個元素時,ORACLE將把整個程序包加載到內存中,當第二次訪問程序包中的元素時,ORACLE將直接從內在中讀取,而不須要進行磁盤I/O操做而影響速度,同時位於內在中的程序包可被同一會話期間的其它應用程序共享。所以,程序包增長了重用性並改善了多用戶、多應用程序環境的效率。
對程序包的優勢可總結以下:在PL/SQL程序設計中,使用包不只可使程序設計模塊化,對外隱藏包內所使用的信息(經過使用私用變量),而寫能夠提升程序的執行效率。由於,當程序首次調用包內函數或過程時,ORACLE將整個包調入內存,當再次訪問包內元素時,ORACLE直接從內存中讀取,而不須要進行磁盤I/O操做,從而使程序執行效率獲得提升。
一個包由兩個分開的部分組成:
包說明(PACKAGE):包說明部分聲明包內數據類型、變量、常量、遊標、子程序和異常錯誤處理等元素,這些元素爲包的公有元素。
包主體(PACKAGE BODY):包主體則是包定義部分的具體實現,它定義了包定義部分所聲明的遊標和子程序,在包主體中還能夠聲明包的私有元素。
包說明和包主體分開編譯,並做爲兩部分分開的對象存放在數據庫字典中,可查看數據字典user_source, all_source, dba_source,分別瞭解包說明與包主體的詳細信息。
程序包的定義分爲程序包說明定義和程序包主體定義兩部分組成。
程序包說明用於聲明包的公用組件,如變量、常量、自定義數據類型、異常、過程、函數、遊標等。包說明中定義的公有組件不只能夠在包內使用,還能夠由包外其餘過程、函數。但須要說明與注意的是,咱們爲了實現信息的隱藏,建議不要將全部組件都放在包說明處聲明,只應把公共組件放在包聲明部分。包的名稱是惟一的,但對於兩個包中的公有組件的名稱能夠相同,這種用「包名.公有組件名「加以區分。
包體是包的具體實現細節,其實如今包說明中聲明的全部公有過程、函數、遊標等。固然也能夠在包體中聲明僅屬於本身的私有過程、函數、遊標等。建立包體時,有如下幾點須要注意:
u 包體只能在包說明被建立或編譯後才能進行建立或編譯。
u 在包體中實現的過程、函數、遊標的名稱必須與包說明中的過程、函數、遊標一致,包括名稱、參數的名稱以及參數的模式(IN、OUT、IN OUT)。並建設按包說明中的次序定義包體中具體的實現。
u 在包體中聲明的數據類型、變量、常量都是私有的,只能在包體中使用而不能被印刷體外的應用程序訪問與使用。
u 在包體執行部分,可對包說明,包體中聲明的公有或私有變量進行初始化或其它設置。
建立程序包說明語法格式:
CREATE [OR REPLACE] PACKAGE package_name
[AUTHID {CURRENT_USER | DEFINER}]
{IS | AS}
[公有數據類型定義[公有數據類型定義]…]
[公有遊標聲明[公有遊標聲明]…]
[公有變量、常量聲明[公有變量、常量聲明]…]
[公有函數聲明[公有函數聲明]…]
[公有過程聲明[公有過程聲明]…]
END [package_name];
其中:AUTHIDCURRENT_USER和AUTHIDDEFINER選項說明應用程序在調用函數時所使用的權限模式,它們與CREATEFUNCTION語句中invoker_right_clause子句的做用相同。
建立程序包主體語法格式:
CREATE [OR REPLACE] PACKAGE BODY package_name
{IS | AS}
[私有數據類型定義[私有數據類型定義]…]
[私有變量、常量聲明[私有變量、常量聲明]…]
[私有異常錯誤聲明[私有異常錯誤聲明]…]
[私有函數聲明和定義[私有函數聲明和定義]…]
[私有函過程聲明和定義[私有函過程聲明和定義]…]
[公有遊標定義[公有遊標定義]…]
[公有函數定義[公有函數定義]…]
[公有過程定義[公有過程定義]…]
BEGIN
執行部分(初始化部分)
END package_name;
其中:在包主體定義公有程序時,它們必須與包定義中所聲明子程序的格式徹底一致。
與開發存儲過程相似,包的開發須要幾個步驟:
1. 將每一個存儲過程調式正確;
2. 用文本編輯軟件將各個存儲過程和函數集成在一塊兒;
3. 按照包的定義要求將集成的文本的前面加上包定義;
4. 按照包的定義要求將集成的文本的前面加上包主體;
5. 使用SQLPLUS或開發工具進行調式。
對包內共有元素的調用格式爲:包名.元素名稱
PL/SQL 容許對包內子程序和本地子程序進行重載。所謂重載時指兩個或多個子程序有相同的名稱,但擁有不一樣的參數變量、參數順序或參數數據類型。
ORACLE 提供了一個實用工具來加密或者包裝用戶的PL/SQL,它會將用戶的PL/SQL改變爲只有ORACLE可以解釋的代碼版本.
WRAP 實用工具位於$ORACLE_HOME/BIN。
格式爲:
WRAP INAME=<input_file_name> [ONAME=<output_file_name>]
wrap iname=e:\sample.txt
注意:在加密前,請將PL/SQL程序先保存一份,以備後用。
可使用 DROP PACKAGE 命令對不須要的包進行刪除,語法以下:
DROP PACKAGE [BODY] [user.]package_name;
DROP PROCEDURE OpenCurType; --刪除存儲過程
--刪除咱們實例中建立的各個包
DROP PACKAGE demo_pack;
DROP PACKAGE demo_pack1;
DROP PACKAGE emp_mgmt;
DROP PACKAGE emp_package;
包與過程、函數同樣,也是存儲在數據庫中的,能夠隨時查看其源碼。如有須要,在建立包時能夠隨時查看更詳細的編譯錯誤。不須要的包也能夠刪除。
一樣,爲了不調用的失敗,在更新表的結構後,必定要記得從新編譯依賴於它的程序包。在更新了包說明或包體後,也應該從新編譯包說明與包體。語法以下:
ALTER PACKAGE package_name COMPILE [PACKAGE|BODY|SPECIFICATION];
也能夠經過如下數據字典視圖查看包的相關。
DBA_SOURCE, USER_SOURCE, USER_ERRORS,DBA-OBJECTS
******************************************************************
----------把觸發器說透----------
觸發器是許多關係數據庫系統都提供的一項技術。在ORACLE系統裏,觸發器相似過程和函數,都有聲明,執行和異常處理過程的PL/SQL塊。
觸發器在數據庫裏以獨立的對象存儲,它與存儲過程和函數不一樣的是,存儲過程與函數須要用戶顯示調用才執行,而觸發器是由一個事件來啓動運行。即觸發器是當某個事件發生時自動地隱式運行。而且,觸發器不能接收參數。因此運行觸發器就叫觸發或點火(firing)。ORACLE事件指的是對數據庫的表進行的INSERT、UPDATE及DELETE操做或對視圖進行相似的操做。ORACLE將觸發器的功能擴展到了觸發ORACLE,如數據庫的啓動與關閉等。因此觸發器經常使用來完成由數據庫的完整性約束難以完成的複雜業務規則的約束,或用來監視對數據庫的各類操做,實現審計的功能。
8.1.1 DML觸發器
ORACLE能夠在DML語句進行觸發,能夠在DML操做前或操做後進行觸發,而且能夠對每一個行或語句操做上進行觸發。
8.1.2 替代觸發器
因爲在ORACLE裏,不能直接對由兩個以上的表創建的視圖進行操做。因此給出了替代觸發器。它就是ORACLE 8專門爲進行視圖操做的一種處理方法。
8.1.3 系統觸發器
ORACLE 8i 提供了第三種類型的觸發器叫系統觸發器。它能夠在ORACLE數據庫系統的事件中進行觸發,如ORACLE系統的啓動與關閉等。
觸發器組成:
l 觸發事件:引發觸發器被觸發的事件。 例如:DML語句(INSERT, UPDATE, DELETE語句對錶或視圖執行數據處理操做)、DDL語句(如CREATE、ALTER、DROP語句在數據庫中建立、修改、刪除模式對象)、數據庫系統事件(如系統啓動或退出、異常錯誤)、用戶事件(如登陸或退出數據庫)。
l 觸發時間:即該TRIGGER 是在觸發事件發生以前(BEFORE)仍是以後(AFTER)觸發,也就是觸發事件和該TRIGGER 的操做順序。
l 觸發操做:即該TRIGGER 被觸發以後的目的和意圖,正是觸發器自己要作的事情。 例如:PL/SQL 塊。
l 觸發對象:包括表、視圖、模式、數據庫。只有在這些對象上發生了符合觸發條件的觸發事件,纔會執行觸發操做。
l 觸發條件:由WHEN子句指定一個邏輯表達式。只有當該表達式的值爲TRUE時,遇到觸發事件纔會自動執行觸發器,使其執行觸發操做。
l 觸發頻率:說明觸發器內定義的動做被執行的次數。即語句級(STATEMENT)觸發器和行級(ROW)觸發器。
語句級(STATEMENT)觸發器:是指當某觸發事件發生時,該觸發器只執行一次;
行級(ROW)觸發器:是指當某觸發事件發生時,對受到該操做影響的每一行數據,觸發器都單獨執行一次。
編寫觸發器時,須要注意如下幾點:
l 觸發器不接受參數。
l 一個表上最多可有12個觸發器,但同一時間、同一事件、同一類型的觸發器只能有一個。並各觸發器之間不能有矛盾。
l 在一個表上的觸發器越多,對在該表上的DML操做的性能影響就越大。
l 觸發器最大爲32KB。若確實須要,能夠先創建過程,而後在觸發器中用CALL語句進行調用。
l 在觸發器的執行部分只能用DML語句(SELECT、INSERT、UPDATE、DELETE),不能使用DDL語句(CREATE、ALTER、DROP)。
l 觸發器中不能包含事務控制語句(COMMIT,ROLLBACK,SAVEPOINT)。由於觸發器是觸發語句的一部分,觸發語句被提交、回退時,觸發器也被提交、回退了。
l 在觸發器主體中調用的任何過程、函數,都不能使用事務控制語句。
l 在觸發器主體中不能申明任何Long和blob變量。新值new和舊值old也不能向表中的任何long和blob列。
l 不一樣類型的觸發器(如DML觸發器、INSTEAD OF觸發器、系統觸發器)的語法格式和做用有較大區別。
建立觸發器的通常語法是:
1
2
3
4
5
6
7
8
9
|
CREATE
[
OR
REPLACE
]
TRIGGER
trigger_name
{BEFORE |
AFTER
}
{
INSERT
|
DELETE
|
UPDATE
[
OF
column
[,
column
…]]}
[
OR
{
INSERT
|
DELETE
|
UPDATE
[
OF
column
[,
column
…]]}...]
ON
[
schema
.]table_name | [
schema
.]view_name
[REFERENCING {OLD [
AS
] old | NEW [
AS
] new| PARENT
as
parent}]
[
FOR
EACH ROW ]
[
WHEN
condition]
PL/SQL_BLOCK | CALL procedure_name;
|
其中:
BEFORE 和AFTER指出觸發器的觸發時序分別爲前觸發和後觸發方式,前觸發是在執行觸發事件以前觸發當前所建立的觸發器,後觸發是在執行觸發事件以後觸發當前所建立的觸發器。
FOR EACH ROW選項說明觸發器爲行觸發器。行觸發器和語句觸發器的區別表如今:行觸發器要求當一個DML語句操走影響數據庫中的多行數據時,對於其中的每一個數據行,只要它們符合觸發約束條件,均激活一次觸發器;而語句觸發器將整個語句操做做爲觸發事件,當它符合約束條件時,激活一次觸發器。當省略FOR EACH ROW 選項時,BEFORE 和AFTER 觸發器爲語句觸發器,而INSTEAD OF 觸發器則只能爲行觸發器。
REFERENCING 子句說明相關名稱,在行觸發器的PL/SQL塊和WHEN 子句中可使用相關名稱參照當前的新、舊列值,默認的相關名稱分別爲OLD和NEW。觸發器的PL/SQL塊中應用相關名稱時,必須在它們以前加冒號(:),但在WHEN子句中則不能加冒號。
WHEN 子句說明觸發約束條件。Condition 爲一個邏輯表達時,其中必須包含相關名稱,而不能包含查詢語句,也不能調用PL/SQL 函數。WHEN 子句指定的觸發約束條件只能用在BEFORE 和AFTER 行觸發器中,不能用在INSTEAD OF 行觸發器和其它類型的觸發器中。
當一個基表被修改( INSERT, UPDATE, DELETE)時要執行的存儲過程,執行時根據其所依附的基表改動而自動觸發,所以與應用程序無關,用數據庫觸發器能夠保證數據的一致性和完整性。
每張表最多可創建12 種類型的觸發器,它們是:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
BEFORE
INSERT
BEFORE
INSERT
FOR
EACH ROW
AFTER
INSERT
AFTER
INSERT
FOR
EACH ROW
BEFORE
UPDATE
BEFORE
UPDATE
FOR
EACH ROW
AFTER
UPDATE
AFTER
UPDATE
FOR
EACH ROW
BEFORE
DELETE
BEFORE
DELETE
FOR
EACH ROW
AFTER
DELETE
AFTER
DELETE
FOR
EACH ROW
|
8.2.1 觸發器觸發次序
1. 執行 BEFORE語句級觸發器;
2. 對與受語句影響的每一行:
l 執行 BEFORE行級觸發器
l 執行 DML語句
l 執行 AFTER行級觸發器
3. 執行 AFTER語句級觸發器
8.2.2 建立DML觸發器
觸發器名與過程名和包的名字不同,它是單獨的名字空間,於是觸發器名能夠和表或過程有相同的名字,但在一個模式中觸發器名不能相同。
DML觸發器的限制
l CREATE TRIGGER語句文本的字符長度不能超過32KB;
l 觸發器體內的SELECT 語句只能爲SELECT … INTO …結構,或者爲定義遊標所使用的SELECT 語句。
l 觸發器中不能使用數據庫事務控制語句 COMMIT; ROLLBACK, SVAEPOINT 語句;
l 由觸發器所調用的過程或函數也不能使用數據庫事務控制語句;
l 觸發器中不能使用LONG, LONG RAW 類型;
l 觸發器內能夠參照LOB 類型列的列值,但不能經過 :NEW 修改LOB列中的數據;
DML觸發器基本要點
l 觸發時機:指定觸發器的觸發時間。若是指定爲BEFORE,則表示在執行DML操做以前觸發,以便防止某些錯誤操做發生或實現某些業務規則;若是指定爲AFTER,則表示在執行DML操做以後觸發,以便記錄該操做或作某些過後處理。
l 觸發事件:引發觸發器被觸發的事件,即DML操做(INSERT、UPDATE、DELETE)。既能夠是單個觸發事件,也能夠是多個觸發事件的組合(只能使用OR邏輯組合,不能使用AND邏輯組合)。
l 條件謂詞:當在觸發器中包含多個觸發事件(INSERT、UPDATE、DELETE)的組合時,爲了分別針對不一樣的事件進行不一樣的處理,須要使用ORACLE提供的以下條件謂詞。
1)。INSERTING:當觸發事件是INSERT時,取值爲TRUE,不然爲FALSE。
2)。UPDATING [(column_1,column_2,…,column_x)]:當觸發事件是UPDATE 時,若是修改了column_x列,則取值爲TRUE,不然爲FALSE。其中column_x是可選的。
3)。DELETING:當觸發事件是DELETE時,則取值爲TRUE,不然爲FALSE。
解發對象:指定觸發器是建立在哪一個表、視圖上。
l 觸發類型:是語句級仍是行級觸發器。
l 觸發條件:由WHEN子句指定一個邏輯表達式,只容許在行級觸發器上指定觸發條件,指定UPDATING後面的列的列表。
問題:當觸發器被觸發時,要使用被插入、更新或刪除的記錄中的列值,有時要使用操做前、 後列的值.
實現: :NEW 修飾符訪問操做完成後列的值
:OLD 修飾符訪問操做完成前列的值
特性 |
INSERT |
UPDATE |
DELETE |
OLD |
NULL |
實際值 |
實際值 |
NEW |
實際值 |
實際值 |
NULL |
例1: 創建一個觸發器, 當職工表 emp 表被刪除一條記錄時,把被刪除記錄寫到職工表刪除日誌表中去。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
CREATE
TABLE
emp_his
AS
SELECT
*
FROM
EMP
WHERE
1=2;
CREATE
OR
REPLACE
TRIGGER
tr_del_emp
BEFORE
DELETE
--指定觸發時機爲刪除操做前觸發
ON
scott.emp
FOR
EACH ROW
--說明建立的是行級觸發器
BEGIN
--將修改前數據插入到日誌記錄表 del_emp ,以供監督使用。
INSERT
INTO
emp_his(deptno , empno, ename , job ,mgr , sal , comm , hiredate )
VALUES
( :old.deptno, :old.empno, :old.ename , :old.job,:old.mgr, :old.sal, :old.comm, :old.hiredate );
END
;
DELETE
emp
WHERE
empno=7788;
DROP
TABLE
emp_his;
DROP
TRIGGER
del_emp;
|
例2:在觸發器中調用過程。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
CREATE
OR
REPLACE
PROCEDURE
add_job_history
( p_emp_id job_history.employee_id%type
, p_start_date job_history.start_date%type
, p_end_date job_history.end_date%type
, p_job_id job_history.job_id%type
, p_department_id job_history.department_id%type
)
IS
BEGIN
INSERT
INTO
job_history (employee_id, start_date, end_date,
job_id, department_id)
VALUES
(p_emp_id, p_start_date, p_end_date, p_job_id, p_department_id);
END
add_job_history;
--建立觸發器調用存儲過程...
CREATE
OR
REPLACE
TRIGGER
update_job_history
AFTER
UPDATE
OF
job_id, department_id
ON
employees
FOR
EACH ROW
BEGIN
add_job_history(:old.employee_id, :old.hire_date, sysdate,
:old.job_id, :old.department_id);
END
;
|
8.2.3 建立替代(INSTEAD OF)觸發器
建立觸發器的通常語法是:
1
2
3
4
5
6
7
8
9
|
CREATE
[
OR
REPLACE
]
TRIGGER
trigger_name
INSTEAD
OF
{
INSERT
|
DELETE
|
UPDATE
[
OF
column
[,
column
…]]}
[
OR
{
INSERT
|
DELETE
|
UPDATE
[
OF
column
[,
column
…]]}...]
ON
[
schema
.] view_name
--只能定義在視圖上
[REFERENCING {OLD [
AS
] old | NEW [
AS
] new| PARENT
as
parent}]
[
FOR
EACH ROW ]
--由於INSTEAD OF觸發器只能在行級上觸發,因此沒有必要指定
[
WHEN
condition]
PL/SQL_block | CALL procedure_name;
|
其中:
INSTEAD OF 選項使ORACLE激活觸發器,而不執行觸發事件。只能對視圖和對象視圖創建INSTEAD OF觸發器,而不能對錶、模式和數據庫創建INSTEAD OF 觸發器。
FOR EACH ROW選項說明觸發器爲行觸發器。行觸發器和語句觸發器的區別表如今:行觸發器要求當一個DML語句操走影響數據庫中的多行數據時,對於其中的每一個數據行,只要它們符合觸發約束條件,均激活一次觸發器;而語句觸發器將整個語句操做做爲觸發事件,當它符合約束條件時,激活一次觸發器。當省略FOR EACH ROW 選項時,BEFORE 和AFTER 觸發器爲語句觸發器,而INSTEAD OF 觸發器則爲行觸發器。
REFERENCING 子句說明相關名稱,在行觸發器的PL/SQL塊和WHEN 子句中可使用相關名稱參照當前的新、舊列值,默認的相關名稱分別爲OLD和NEW。觸發器的PL/SQL塊中應用相關名稱時,必須在它們以前加冒號(:),但在WHEN子句中則不能加冒號。
WHEN 子句說明觸發約束條件。Condition 爲一個邏輯表達時,其中必須包含相關名稱,而不能包含查詢語句,也不能調用PL/SQL 函數。WHEN 子句指定的觸發約束條件只能用在BEFORE 和AFTER 行觸發器中,不能用在INSTEAD OF 行觸發器和其它類型的觸發器中。
INSTEAD_OF 用於對視圖的DML觸發,因爲視圖有多是由多個表進行聯結(join)而成,於是並不是是全部的聯結都是可更新的。但能夠按照所需的方式執行更新,例以下面狀況:
例1:
1
2
3
|
CREATE
OR
REPLACE
VIEW
emp_view
AS
SELECT
deptno,
count
(*) total_employeer,
sum
(sal) total_salary
FROM
emp
GROUP
BY
deptno;
|
在此視圖中直接刪除是非法:
1
2
|
SQL>
DELETE
FROM
emp_view
WHERE
deptno=10;
DELETE
FROM
emp_view
WHERE
deptno=10
|
ERROR 位於第 1 行:
ORA-01732: 此視圖的數據操縱操做非法
可是咱們能夠建立INSTEAD_OF觸發器來爲 DELETE 操做執行所需的處理,即刪除EMP表中全部基準行:
1
2
3
4
5
6
7
8
9
10
11
|
CREATE
OR
REPLACE
TRIGGER
emp_view_delete
INSTEAD
OF
DELETE
ON
emp_view
FOR
EACH ROW
BEGIN
DELETE
FROM
emp
WHERE
deptno= :old.deptno;
END
emp_view_delete;
DELETE
FROM
emp_view
WHERE
deptno=10;
DROP
TRIGGER
emp_view_delete;
DROP
VIEW
emp_view;
|
例2:建立複雜視圖,針對INSERT操做建立INSTEAD OF觸發器,向複雜視圖插入數據。
l 建立視圖:
1
2
3
4
5
6
7
8
9
|
CREATE
OR
REPLACE
FORCE
VIEW
"HR"
.
"V_REG_COU"
(
"R_ID"
,
"R_NAME"
,
"C_ID"
,
"C_NAME"
)
AS
SELECT
r.region_id,
r.region_name,
c.country_id,
c.country_name
FROM
regions r,
countries c
WHERE
r.region_id = c.region_id;
|
l 建立觸發器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
CREATE
OR
REPLACE
TRIGGER
"HR"
.
"TR_I_O_REG_COU"
INSTEAD
OF
INSERT
ON
v_reg_cou
FOR
EACH ROW
DECLARE
v_count NUMBER;
BEGIN
SELECT
COUNT
(*)
INTO
v_count
FROM
regions
WHERE
region_id = :new.r_id;
IF v_count = 0
THEN
INSERT
INTO
regions
(region_id, region_name
)
VALUES
(:new.r_id, :new.r_name
);
END
IF;
SELECT
COUNT
(*)
INTO
v_count
FROM
countries
WHERE
country_id = :new.c_id;
IF v_count = 0
THEN
INSERT
INTO
countries
(
country_id,
country_name,
region_id
)
VALUES
(
:new.c_id,
:new.c_name,
:new.r_id
);
END
IF;
END
;
|
建立INSTEAD OF觸發器須要注意如下幾點:
l 只能被建立在視圖上,而且該視圖沒有指定WITH CHECK OPTION選項。
l 不能指定BEFORE 或 AFTER選項。
l FOR EACH ROW子但是可選的,即INSTEAD OF觸發器只能在行級上觸發、或只能是行級觸發器,沒有必要指定。
l 沒有必要在針對一個表的視圖上建立INSTEAD OF觸發器,只要建立DML觸發器就能夠了。
8.2.4 建立系統事件觸發器
ORACLE10G提供的系統事件觸發器能夠在DDL或數據庫系統上被觸發。DDL指的是數據定義語言,如CREATE 、ALTER及DROP 等。而數據庫系統事件包括數據庫服務器的啓動或關閉,用戶的登陸與退出、數據庫服務錯誤等。建立系統觸發器的語法以下:
建立觸發器的通常語法是:
1
2
3
4
5
6
|
CREATE
OR
REPLACE
TRIGGER
[sachema.]trigger_name
{BEFORE|
AFTER
}
{ddl_event_list | database_event_list}
ON
{
DATABASE
| [
schema
.]
SCHEMA
}
[
WHEN
condition]
PL/SQL_block | CALL procedure_name;
|
其中: ddl_event_list:一個或多個DDL 事件,事件間用 OR 分開;
database_event_list:一個或多個數據庫事件,事件間用 OR 分開;
系統事件觸發器既能夠創建在一個模式上,又能夠創建在整個數據庫上。當創建在模式(SCHEMA)之上時,只有模式所指定用戶的DDL操做和它們所致使的錯誤才激活觸發器, 默認時爲當前用戶模式。當創建在數據庫(DATABASE)之上時,該數據庫全部用戶的DDL操做和他們所致使的錯誤,以及數據庫的啓動和關閉都可激活觸發器。要在數據庫之上創建觸發器時,要求用戶具備ADMINISTER DATABASE TRIGGER權限。
下面給出系統觸發器的種類和事件出現的時機(前或後):
事件 |
容許的時機 |
說明 |
STARTUP |
AFTER |
啓動數據庫實例以後觸發 |
SHUTDOWN |
BEFORE |
關閉數據庫實例以前觸發(非正常關閉不觸發) |
SERVERERROR |
AFTER |
數據庫服務器發生錯誤以後觸發 |
LOGON |
AFTER |
成功登陸鏈接到數據庫後觸發 |
LOGOFF |
BEFORE |
開始斷開數據庫鏈接以前觸發 |
CREATE |
BEFORE,AFTER |
在執行CREATE語句建立數據庫對象以前、以後觸發 |
DROP |
BEFORE,AFTER |
在執行DROP語句刪除數據庫對象以前、以後觸發 |
ALTER |
BEFORE,AFTER |
在執行ALTER語句更新數據庫對象以前、以後觸發 |
DDL |
BEFORE,AFTER |
在執行大多數DDL語句以前、以後觸發 |
GRANT |
BEFORE,AFTER |
執行GRANT語句授予權限以前、以後觸發 |
REVOKE |
BEFORE,AFTER |
執行REVOKE語句收權限以前、以後觸犯發 |
RENAME |
BEFORE,AFTER |
執行RENAME語句更改數據庫對象名稱以前、以後觸犯發 |
AUDIT / NOAUDIT |
BEFORE,AFTER |
執行AUDIT或NOAUDIT進行審計或中止審計以前、以後觸發 |
8.2.5 系統觸發器事件屬性
事件屬性\事件 |
Startup/Shutdown |
Servererror |
Logon/Logoff |
DDL |
DML |
事件名稱 |
* |
* |
* |
* |
* |
數據庫名稱 |
* |
||||
數據庫實例號 |
* |
||||
錯誤號 |
* |
||||
用戶名 |
* |
* |
|||
模式對象類型 |
* |
* |
|||
模式對象名稱 |
* |
* |
|||
列 |
* |
除DML語句的列屬性外,其他事件屬性值可經過調用ORACLE定義的事件屬性函數來讀取。
函數名稱 |
數據類型 |
說 明 |
Ora_sysevent |
VARCHAR2(20) |
激活觸發器的事件名稱 |
Instance_num |
NUMBER |
數據庫實例名 |
Ora_database_name |
VARCHAR2(50) |
數據庫名稱 |
Server_error(posi) |
NUMBER |
錯誤信息棧中posi指定位置中的錯誤號 |
Is_servererror(err_number) |
BOOLEAN |
檢查err_number指定的錯誤號是否在錯誤信息棧中,若是在則返回TRUE,不然返回FALSE。在觸發器內調用此函數能夠判斷是否發生指定的錯誤。 |
Login_user |
VARCHAR2(30) |
登錄或註銷的用戶名稱 |
Dictionary_obj_type |
VARCHAR2(20) |
DDL語句所操做的數據庫對象類型 |
Dictionary_obj_name |
VARCHAR2(30) |
DDL語句所操做的數據庫對象名稱 |
Dictionary_obj_owner |
VARCHAR2(30) |
DDL語句所操做的數據庫對象全部者名稱 |
Des_encrypted_password |
VARCHAR2(2) |
正在建立或修改的通過DES算法加密的用戶口令 |
例1:建立觸發器,存放有關事件信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
DESC
ora_sysevent
DESC
ora_login_user
--建立用於記錄事件用的表
CREATE
TABLE
ddl_event
(crt_date
timestamp
PRIMARY
KEY
,
event_name VARCHAR2(20),
user_name VARCHAR2(10),
obj_type VARCHAR2(20),
obj_name VARCHAR2(20));
--建立觸犯發器
CREATE
OR
REPLACE
TRIGGER
tr_ddl
AFTER
DDL
ON
SCHEMA
BEGIN
INSERT
INTO
ddl_event
VALUES
(systimestamp,ora_sysevent, ora_login_user,
ora_dict_obj_type, ora_dict_obj_name);
END
tr_ddl;
|
例2:建立登陸、退出觸發器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
CREATE
TABLE
log_event
(user_name VARCHAR2(10),
address VARCHAR2(20),
logon_date
timestamp
,
logoff_date
timestamp
);
--建立登陸觸發器
CREATE
OR
REPLACE
TRIGGER
tr_logon
AFTER
LOGON
ON
DATABASE
BEGIN
INSERT
INTO
log_event (user_name, address, logon_date)
VALUES
(ora_login_user, ora_client_ip_address, systimestamp);
END
tr_logon;
--建立退出觸發器
CREATE
OR
REPLACE
TRIGGER
tr_logoff
BEFORE LOGOFF
ON
DATABASE
BEGIN
INSERT
INTO
log_event (user_name, address, logoff_date)
VALUES
(ora_login_user, ora_client_ip_address, systimestamp);
END
tr_logoff;
|
8.2.6 使用觸發器謂詞
ORACLE 提供三個參數INSERTING, UPDATING, DELETING 用於判斷觸發了哪些操做。
謂詞 |
行爲 |
INSERTING |
若是觸發語句是 INSERT 語句,則爲TRUE,不然爲FALSE |
UPDATING |
若是觸發語句是 UPDATE語句,則爲TRUE,不然爲FALSE |
DELETING |
若是觸發語句是 DELETE 語句,則爲TRUE,不然爲FALSE |
8.2.7 從新編譯觸發器
若是在觸發器內調用其它函數或過程,當這些函數或過程被刪除或修改後,觸發器的狀態將被標識爲無效。當DML語句激活一個無效觸發器時,ORACLE將從新編譯觸發器代碼,若是編譯時發現錯誤,這將致使DML語句執行失敗。
在PL/SQL程序中能夠調用ALTER TRIGGER語句從新編譯已經建立的觸發器,格式爲:
1
|
ALTER
TRIGGER
[
schema
.] trigger_name COMPILE [ DEBUG]
|
其中:DEBUG 選項要器編譯器生成PL/SQL 程序條使其所使用的調試代碼。
l 刪除觸發器:
1
|
DROP
TRIGGER
trigger_name;
|
當刪除其餘用戶模式中的觸發器名稱,須要具備DROP ANY TRIGGER系統權限,當刪除創建在數據庫上的觸發器時,用戶須要具備ADMINISTER DATABASE TRIGGER系統權限。
此外,當刪除表或視圖時,創建在這些對象上的觸發器也隨之刪除。
l 禁用或啓用觸發器
數據庫TRIGGER 的狀態:
有效狀態(ENABLE):當觸發事件發生時,處於有效狀態的數據庫觸發器TRIGGER 將被觸發。
無效狀態(DISABLE):當觸發事件發生時,處於無效狀態的數據庫觸發器TRIGGER 將不會被觸發,此時就跟沒有這個數據庫觸發器(TRIGGER) 同樣。
數據庫TRIGGER的這兩種狀態能夠互相轉換。格式爲:
1
2
3
|
ALTER
TIGGER trigger_name [DISABLE | ENABLE ];
--例:ALTER TRIGGER emp_view_delete DISABLE;
|
ALTER TRIGGER語句一次只能改變一個觸發器的狀態,而ALTER TABLE語句則一次可以改變與指定表相關的全部觸發器的使用狀態。格式爲:
1
2
3
|
ALTER
TABLE
[
schema
.]table_name {ENABLE|DISABLE}
ALL
TRIGGERS;
--例:使表EMP 上的全部TRIGGER 失效:
ALTER
TABLE
emp DISABLE
ALL
TRIGGERS;
|
相關數據字典:USER_TRIGGERS、ALL_TRIGGERS、DBA_TRIGGERS
1
2
3
4
|
SELECT
TRIGGER_NAME, TRIGGER_TYPE, TRIGGERING_EVENT,
TABLE_OWNER, BASE_OBJECT_TYPE, REFERENCING_NAMES,
STATUS, ACTION_TYPE
FROM
user_triggers;
|
例子:建立INSTEAD OF 觸發器。首先建立一個視圖myview, 因爲該視圖是複合查詢所產生的視圖,因此不能執行DML語句。根據用戶對視圖所插入的數據判斷須要將數據插入到哪一個視圖基表中,而後對該基表執行插入操做。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
DECLARE
No
NUMBER;
Name
VARCHAR2(20);
BEGIN
DBMS_UTILITY.EXEC_DDL_STATEMENT(
'
CREATE OR REPLACE VIEW myview AS
SELECT empno, ename, '
'E'
' type FROM emp
UNION
SELECT dept.deptno, dname, '
'D'
' FROM dept
'
);
-- 建立INSTEAD OF 觸發器trigger3;
DBMS_UTILITY.EXEC_DDL_STATEMENT(
'
CREATE OR REPLACE TRIGGER trig3
INSTEAD OF INSERT ON myview
REFERENCING NEW n
FOR EACH ROW
DECLARE
Rows INTEGER;
BEGIN
DBMS_OUTPUT.PUT_LINE('
'正在執行trig3觸發器…'
');
IF :n.type = '
'D'
' THEN
SELECT COUNT(*) INTO rows
FROM dept WHERE deptno = :n.empno;
IF rows = 0 THEN
DBMS_OUTPUT.PUT_LINE('
'向dept表中插入數據…'
');
INSERT INTO dept(deptno, dname, loc)
VALUES (:n.empno, :n.ename, '
'none’’);
ELSE
DBMS_OUTPUT.PUT_LINE('
'編號爲'
'|| :n.empno||
'
'的部門已存在,插入操做失敗!'
');
END IF;
ELSE
SELECT COUNT(*) INTO rows
FROM emp WHERE empno = :n.empno;
IF rows = 0 THEN
DBMS_OUTPUT.PUT_LINE('
’向emp表中插入數據…’’);
INSERT
INTO
emp(empno, ename)
VALUES
(:n.empno, :n.ename);
ELSE
DBMS_OUTPUT.PUT_LINE(
''
編號爲
''
|| :n.empno||
''
的人員已存在,插入操做失敗!
''
);
END
IF;
END
IF;
END
;
');
INSERT INTO myview VALUES (70, '
demo
', '
D
');
INSERT INTO myview VALUES (9999, USER, '
E
');
SELECT deptno, dname INTO no, name FROM dept WHERE deptno=70;
DBMS_OUTPUT.PUT_LINE('
員工編號:
'||TO_CHAR(no)||'
姓名:
'||name);
SELECT empno, ename INTO no, name FROM emp WHERE empno=9999;
DBMS_OUTPUT.PUT_LINE('
部門編號:
'||TO_CHAR(no)||'
姓名:
'||name);
DELETE FROM emp WHERE empno=9999;
DELETE FROM dept WHERE deptno=70;
DBMS_UTILITY.EXEC_DDL_STATEMENT('
DROP
TRIGGER
trig3');
END
;
|
用戶可使用數據庫觸發器實現各類功能:
l 複雜的審計功能;
l 加強數據的完整性管理;
l 幫助實現安全控制;
l 管理複雜的表複製;
l 防止非法的事務發生;
l 自動生成派生的列值;
謝謝各位博友的支持!
未經博主贊成不得隨意轉載。
如需轉載請註明出處:http://www.cnblogs.com/ZRJ-boke/p/6602452.html