Oracle自定義函數
函數的主要特性是它必須返回一個值。創建函數時通過 RETURN 子句指定函數返回值的數據類型。
函數的一些限制:
● 函數只能帶有 IN 參數,不能帶有 IN OUT 或 OUT 參數。
● 形式參數必須只使用數據庫類型,不能使用 PL/SQL 類型。
● 函數的返回類型必須是數據庫類型
Create function 函數名稱 return 返回值類型 as
Begin
····
End 函數名稱;
--創建不帶參數函數,返回t_book中書的數量 create function getBookCount return number as begin declare book_count number; begin select count(*) into book_count from t_book; return book_count; end; end getBookCount; --函數調用 set serveroutput on; begin dbms_output.put_line('表t_book中有'||getBookCount()||'本書'); end;
--創建帶參數函數,查找某個表的記錄數 create function getTableCount(table_name varchar2) return number as begin declare recore_count number; query_sql varchar2(300);--定義sql語句 begin query_sql:='select count(*) from '||table_name; --execute immediate:立即執行該SQL語句 execute immediate query_sql into recore_count; return recore_count; end; end getTableCount; --函數調用 set serveroutput on; begin dbms_output.put_line('表中有'||getTableCount('t_book_log')||'條數據'); end;
CREATE OR REPLACE FUNCTION item_price_rage (price NUMBER)
/* 參數、指定返回類型 */
RETURN varchar2
AS
/* 定義局部變量 */
min_price NUMBER;
max_price NUMBER;
BEGIN
SELECT MAX(ITEMRATE), MIN(ITEMRATE) INTO max_price, min_price
FROM itemfile;
IF price >= min_price AND price <= max_price THEN
RETURN '輸入的單價介於最低價與最高價之間';
ELSE
RETURN '超出范圍';
END IF;
END;
匿名塊執行函數 p NUMBER := 300; MSG varchar2(200); BEGIN MSG := item_price_range(p); DBMS_OUTPUT.PUT_LINE(MSG); END;
SELECT查詢調用(因為函數必須有返回值)
SELECT myfunction FROM dual;
Oracle存儲過程
存儲過程(Stored Procedure),就是一組用於完成特定數據庫功能的SQL語句集,該SQL語句集經過編譯后存儲在數據庫系統中。
在使用時候,用戶通過指定已經定義的存儲過程名字並給出相應的存儲過程參數來調用並執行它,從而完成一個或一系列的數據庫操作
Oracle存儲過程包含三部分:過程聲明,執行過程部分,存儲過程異常
存儲過程創建語法
create [or replace] procedure 存儲過程名(param1 in type,param2 out type) as 變量1 類型(值范圍); 變量2 類型(值范圍); Begin Select count(*) into 變量1 from 表A where列名=param1; If (判斷條件) then Select 列名 into 變量2 from 表A where列名=param1; Dbms_output.Put_line(‘打印信息’); Elsif (判斷條件) then Dbms_output.Put_line(‘打印信息’); Else Raise 異常名(NO_DATA_FOUND); End if; Exception When others then Rollback; End;
declare 顧名思義就是描述的意思就是在這個下邊可以對變量進行聲明。
聲明變量有大概如下兩三種方式
1. v_temp varchar(10)
2.v_temp tablename.property%type(表明屬性名%type就是該表屬性的類型,這樣可以靈活使用)
3.v_stu student%rowtype;(這種類型就是定義一個變量為表數據的行類型用於接受查詢的一行數據,注意是一行數據)
-- Created on 2018/9/9 by LENOVO --聲明變量,聲明一個人的姓名,薪水,地址 declare -- Local variables here --姓名 v_name varchar2(50) :='張三豐'; --薪水 /* v_salary number(6,2);*/ v_salary emp.ename%type; --地址 v_address varchar2(100); v_stu student%rowtype; begin -- Test statements here --dbms_output.put_line('hello world'); v_salary:=1500; --語句賦值操作。
plsql中的復制是:=而不是單個=,單個=是判斷是否相等意思
輸出操作語句 dbms_output.put_line()
-- Created on 2018/9/9 by LENOVO --聲明變量,聲明一個人的姓名 declare -- Local variables here --姓名 v_name varchar2(50) '; begin v_name:=:='張三豐; dbms_output.put_line('姓名---〉'||v_name); end;
循環:loop關鍵詞就是循環的意思,不論大家學習哪門語言都會發現循環的特點就是有入口,有出口(不可能讓其死循環)。
declare vcc number; begin vcc:=1; loop exit when vcc>10; dbms_output.put_line(vcc); vcc:=vcc+1; end loop; end;
基本結構
CREATE OR REPLACE PROCEDURE 存儲過程名字 ( 參數1 IN NUMBER, 參數2 IN NUMBER ) IS 變量1 INTEGER :=0; 變量2 DATE; BEGIN --執行體 END 存儲過程名字;
SELECT INTO STATEMENT
將select查詢的結果存入到變量中,可以同時將多個列存儲多個變量中,必須有一條記錄,否則拋出異常(如果沒有記錄拋出NO_DATA_FOUND)
例子:
BEGIN
SELECT col1,col2 into 變量1,變量2 FROM typestruct where xxx;
EXCEPTION
WHEN NO_DATA_FOUND THEN
xxxx;
END;
IF 判斷
IF V_TEST = 1 THEN BEGIN do something END; END IF;
while 循環
WHILE V_TEST=1 LOOP
BEGIN
XXXX
END;
END LOOP;
變量賦值
V_TEST := 123;
在Oracle中對存儲過程的調用
過程調用方式一
declare realsal emp.sal%type; realname varchar(40); realjob varchar(40); begin //過程調用開始 realsal:=1100; realname:=''; realjob:='CLERK'; runbyparmeters(realsal,realname,realjob);--必須按順序 DBMS_OUTPUT.PUT_LINE(REALNAME||' '||REALJOB); END; //過程調用結束
過程調用方式二
declare realsal emp.sal%type; realname varchar(40); realjob varchar(40); begin //過程調用開始 realsal:=1100; realname:=''; realjob:='CLERK'; --指定值對應變量順序可變 runbyparmeters(sname=>realname,isal=>realsal,sjob=>realjob); DBMS_OUTPUT.PUT_LINE(REALNAME||' '||REALJOB); END; //過程調用結束
過程調用方式三(SQL命令行方式下)
1、SQL>exec proc_emp(‘參數1’,’參數2’);//無返回值過程調用
2、SQL>var vsal number
SQL> exec proc_emp (‘參數1’,:vsal);// 有返回值過程調用
或者:call proc_emp (‘參數1’,:vsal);// 有返回值過程調用
(1)無參存儲過程語法
create or replace procedure NoParPro as //聲明 ; begin // 執行 ; exception//存儲過程異常 ; end;
(2)帶參存儲過程實例
create or replace procedure queryempname(sfindno emp.empno%type) as sName emp.ename%type; sjob emp.job%type; begin .... exception .... end;
(3)帶參數存儲過程含賦值方式
create or replace procedure runbyparmeters (isal in emp.sal%type, sname out varchar, sjob in out varchar) as icount number; begin select count(*) into icount from emp where sal>isal and job=sjob; if icount=1 then .... else .... end if; exception when too_many_rows then DBMS_OUTPUT.PUT_LINE('返回值多於1行'); when others then DBMS_OUTPUT.PUT_LINE('在RUNBYPARMETERS過程中出錯!'); end;
其中參數IN表示輸入參數,是參數的默認模式。
OUT表示返回值參數,類型可以使用任意Oracle中的合法類型。
OUT模式定義的參數只能在過程體內部賦值,表示該參數可以將某個值傳遞回調用他的過程
IN OUT表示該參數可以向該過程中傳遞值,也可以將某個值傳出去。
Create procedure 存儲過程名稱 as
Begin
···
End 存儲過程名稱;
In 只進不出
Out 只出不進
In out 可進可出
--創建存儲過程,在t_book表中插入數據,且判斷插入的數據是否已經存在 create procedure addBook(bName in varchar2,typeid in number) as begin declare maxId number; n number; begin select count(*) into n from t_book where t_book.bookname=bName; if(n>0) then return; end if; select max(id) into maxId from t_book; insert into t_book values(maxId+1,bName,typeid); commit; end; end addBook; --調用存儲過程 execute addBook('vs',1);
--創建存儲過程,在t_book表中插入數據,輸出插入前后數據條數 create procedure addBook(bName in varchar2,typeid in number,n1 out number,n2 out number) as begin declare maxId number; n number; begin --n1存儲執行前數據條數 select count(*) into n1 from t_book; select count(*) into n from t_book where t_book.bookname=bName; if(n>0) then select count(*) into n2 from t_book; return; end if; select max(id) into maxId from t_book; insert into t_book values(maxId+1,bName,typeid); --n2存儲執行后數據條數 select count(*) into n2 from t_book; commit; end; end addBook; --返回存儲執行前后數據條數 declare n1 number; n2 number; begin addBook('c+++',1,n1,n2); dbms_output.put_line('n1='||n1||',n2='||n2); end;
CREATE OR REPLACE PROCEDURE test (value IN varchar2, value2 OUT NUMBER)
/* 參數,不需指定長度或精度 */
IS
/* 局部變量,省略 DECLARE 關鍵字,需有長度 */
identity NUMBER;
BEGIN
SELECT ITEMRATE INTO identity
FROM itemFile
WHERE itemcode = value;
IF identity < 200 THEN
value2 := 200;
ELSE
value2 :=50;
END IF;
END;
匿名塊執行過程
tvalue2 NUMBER;
BEGIN
test('i202', tvalue2);
DBMS_OUTPUT.PUT_LINE('value2的值為:' || TO_CHAR(value2));
END;
單獨執行
EXECUTE myproc('0001');
過程與函數的異同
過程:
作為 PL/SQL 語句執行;
在規范中不包含 RETURN 子句;
不返回任何值(只有輸入/輸出參數,結果集);
可以包含 RETURN 語句,但是與函數不同,它不能用於返回值。
函數:
作為表達式的一部分調用;
必須在規范中包含 RETURN 子句;
必須返回單個值;
必須包含至少一條 RETURN 語句。
程序包
程序包是一種數據庫對象,它是對相關 PL/SQL 類型、子程序、游標、異常、變量和常量的封裝。
程序包規范:聲明類型、變量、常量、異常、游標和子程序。
程序包主體:用於實現在程序包規范中定義的游標、子程序。
程序包的優點:程序包將相關的功能在邏輯上組織在一起,模塊化,信息隱藏和更好的性能。
引入目的:為了有效的管理函數和存儲過程,當項目模塊很多的時候,用程序包管理就很有效了。
語法
create or replace 包名 as
變量名稱1 數據類型1;
變量名稱2 數據類型2;
····
····
function 函數名稱1(參數列表) return 數據類型1;
function 函數名稱2(參數列表) return 數據類型2;
····
····
procedure 存儲過程名稱1(參數列表);
procedure 存儲過程名稱2(參數列表);
····
····
end 包名;
--創建包,放置存儲過程、函數 create package pkg_book as function getBookCount return number; procedure addBook(bName in varchar2,typeid in number,n1 out number,n2 out number); end pkg_book; --創建包體,實現方法 create package body pkg_book as function getBookCount return number as begin declare book_count number; begin select count(*) into book_count from t_book; return book_count; end; end getBookCount; procedure addBook(bName in varchar2,typeid in number,n1 out number,n2 out number) as begin declare maxId number; n number; begin --n1存儲執行前數據條數 select count(*) into n1 from t_book; select count(*) into n from t_book where t_book.bookname=bName; if(n>0) then select count(*) into n2 from t_book; return; end if; select max(id) into maxId from t_book; insert into t_book values(maxId+1,bName,typeid); --n2存儲執行后數據條數 select count(*) into n2 from t_book; commit; end; end addBook; end pkg_book; --調用 begin dbms_output.put_line('表中有'||pkg_book.getBookCount||'條記錄'); end;
游標
游標是一種 PL/SQL 控制結構,可以對SQL語句的處理進行顯式控制,便於對表的數據逐條進行處理。ps.當表中數據量大的時候,不建議使用游標(效率不高,耗費資源),但是它能逐條取數據方法靈活。
游標是記錄的指針,利用游標對活動集的更新或刪除會反饋到表的記錄上。在學習jdbc操作的時候返回的結果集。ResultSet呢其實這里的結果集就可以通過游標來取的
游標的屬性:
--%rowcount 整型 獲得fetch語句返回的數據行數
--%found 布爾型 最近的fetch語句返回一行數據則為真,否則為假
--%notfound 布爾型 與%found屬性的返回值相反
--%isopen 布爾型 游標已經打開則為真,否則為假
--其中%notfound是游標中找不到元素時候返回true,通常用來判斷推退出循環。
游標的使用需要有四個步驟
聲明------》打開-----》取值-----》關閉
--聲明游標:利用關鍵字 cursor + 任意名字[參數列表(可有可無)] +is +你的sql語句
eg:cursor cur is
select name,age from student;
這里就是聲明了一個游標並且給其賦值。
打開游標:open + 游標;
eg:open cur;
這里沒有什么可說的就類似於jdbc 的connection的open方法
取值:取值有一個關鍵字叫做fetch英文翻譯來就是抓取的意思 使用方法如下::
fetch +游標名稱 into 你定義的變量;就是將抓取的游標賦給你之前定義的其他變量。
因為既然使用了游標肯定是有多行數據。所以一般這里的fetch都是放在loop里邊的。
--聲明變量接受游標中的數據。 v_name student.name%type; v_num student.age%type; begin --打開游標 open cur; --遍歷取值 loop --獲取游標中德數據,如果有則賦值變量,否則退出 fetch cur into v_name v_num; exit when cur%notfound dbms_output.put_line('姓名:' || v_name || '年齡:' ||v_num); end loop; --關閉游標 close cur;
關閉游標:當便利完畢關閉游標即可:close +游標名;
上邊有個語法叫做exit when cur%notfound dbms_output.put_line('姓名:' || v_name || '年齡:' ||v_num);
這里的屬性cur%notfound就是如果游標中沒有值返回true,因為每次游標都是向下讀取的。讀到沒有數據就會返回cur%notfound為true。
游標的定義
--顯示cursor的處理 declare ---聲明cursor,創建和命名一個sql工作區 cursor cursor_name is select real_name from account_hcz; v_realname varchar2(20); begin open cursor_name;---打開cursor,執行sql語句產生的結果集 fetch cursor_name into v_realname;--提取cursor,提取結果集中的記錄 dbms_output.put_line(v_realname); close cursor_name;--關閉cursor end;
顯式游標是由用戶顯式聲明的游標。根據在游標中定義的查詢,查詢返回的行集可以包含零或多行,這些行稱為活動集。游標將指向活動集中的當前行
顯式游標操縱過程:聲明、打開、從游標中獲取記錄、關閉。
用for in 使用cursor
FOR 循環游標:采用遍歷方式,自動打開、提取和關閉游標。
DECLARE
/* 定義帶參數游標 */
CURSOR cur_para(id varchar2) IS
SELECT books_name FROM books WHERE books_id = id;
BGEIN
/* 調用帶參數游標,並以 FOR 循環方式處理 */
FOR cur IN cur_para('0001') LOOP
DBMS_OUTPUT.PUT_LINE(cur.books_id || ' ' || cur.books_id);
END LOOP;
END;
存儲過程中游標定義使用
as //定義(游標一個可以遍歷的結果集) CURSOR cur_1 IS SELECT area_code,CMCODE,SUM(rmb_amt)/10000 rmb_amt_sn, SUM(usd_amt)/10000 usd_amt_sn FROM BGD_AREA_CM_M_BASE_T WHERE ym >= vs_ym_sn_beg AND ym <= vs_ym_sn_end GROUP BY area_code,CMCODE; begin //執行(常用For語句遍歷游標) FOR rec IN cur_1 LOOP UPDATE xxxxxxxxxxx_T SET rmb_amt_sn = rec.rmb_amt_sn,usd_amt_sn = rec.usd_amt_sn WHERE area_code = rec.area_code AND CMCODE = rec.CMCODE AND ym = is_ym; END LOOP;
帶參數的顯式游標
參數不需指定長度或者精度
CURSOR C_USER(C_ID NUMBER) IS SELECT NAME FROM USER WHERE TYPEID=C_ID; OPEN C_USER(變量值); FETCH C_USER INTO V_NAME; EXIT WHEN FETCH C_USER%NOTFOUND; CLOSE C_USER;
使用顯示游標刪除或更新記錄
定義時:需使用 SELECT ... FOR UPDATE 語句表示事物的鎖定;
執行時:需使用 WHERE CURRENT OF curXXX 子句指定游標的當前行。
/* 定義部分 */
CURSOR cur IS
SELECT name FROM deptment FOR UPDATE;
....
/* 執行部分 */
UPDATE deptment SET name=name || '_tt' WHERE CURRENT OF cur;
隱式游標
不需聲明,打開和關閉的游標。PL/SQL 為所有的 SQL 數據操縱語句隱式聲明游標,它是不能直接命名和控制。
BEGIN FROM cur IN (SELECT name FROM deptment) LOOP DBMS_OUTPUT.PUT_LINE(cur.books_id || ' ' || cur.books_id); END LOOP; END;
觸發器簡介
觸發器的定義就是說某個條件成立的時候,觸發器里面所定義的語句就會被自動的執行。
因此觸發器不需要人為的去調用,也不能調用。
然后,觸發器的觸發條件其實在你定義的時候就已經設定好了。
這里面需要說明一下,觸發器可以分為語句級觸發器和行級觸發器。
詳細的介紹可以參考網上的資料,簡單的說就是語句級的觸發器可以在某些語句執行前或執行后被觸發。而行級觸發器則是在定義的了觸發的表中的行數據改變時就會被觸發一次。
具體舉例:
1、 在一個表中定義的語句級的觸發器,當這個表被刪除時,程序就會自動執行觸發器里面定義的操作過程。這個就是刪除表的操作就是觸發器執行的條件了。
2、 在一個表中定義了行級的觸發器,那當這個表中一行數據發生變化的時候,比如刪除了一行記錄,那觸發器也會被自動執行了。
觸發器的語法:
create [or replace] tigger 觸發器名 觸發時間 觸發事件 on 表名 [for each row] begin pl/sql語句 end
觸發器名:觸發器對象的名稱。由於觸發器是數據庫自動執行的,因此該名稱只是一個名稱,沒有實質的用途。 觸發時間:指明觸發器何時執行,該值可取: before:表示在數據庫動作之前觸發器執行; after:表示在數據庫動作之后觸發器執行。 觸發事件:指明哪些數據庫動作會觸發此觸發器: insert:數據庫插入會觸發此觸發器; update:數據庫修改會觸發此觸發器; delete:數據庫刪除會觸發此觸發器。 表 名:數據庫觸發器所在的表。 for each row:對表的每一行觸發器執行一次。如果沒有這一選項,則只對整個表執行一次。
功能:
1、 允許/限制對表的修改
2、 自動生成派生列,比如自增字段
3、 強制數據一致性
4、 提供審計和日志記錄
5、 防止無效的事務處理
6、 啟用復雜的業務邏輯
舉例
1)、下面的觸發器在更新表tb_emp之前觸發,目的是不允許在周末修改表:
create or replace trigger auth_secure before insert or update or DELETE on tb_emp begin IF(to_char(sysdate,'DY')='星期日') THEN RAISE_APPLICATION_ERROR(-20600,'不能在周末修改表tb_emp'); END IF; END; /
2)、使用觸發器實現序號自增
創建一個測試表:
create table tab_user( id number(11) primary key, username varchar(50), password varchar(50) );
創建一個序列:
創建一個觸發器:
CREATE OR REPLACE TRIGGER MY_TGR BEFORE INSERT ON TAB_USER FOR EACH ROW--對表的每一行觸發器執行一次 DECLARE NEXT_ID NUMBER; BEGIN SELECT MY_SEQ.NEXTVAL INTO NEXT_ID FROM DUAL; :NEW.ID := NEXT_ID; --:NEW表示新插入的那條記錄 END;
向表插入數據:
insert into tab_user(username,password) values('admin','admin'); insert into tab_user(username,password) values('fgz','fgz'); insert into tab_user(username,password) values('test','test'); COMMIT;
查詢表結果:SELECT * FROM TAB_USER;
3)、當用戶對test表執行DML語句時,將相關信息記錄到日志表
--創建測試表 CREATE TABLE test( t_id NUMBER(4), t_name VARCHAR2(20), t_age NUMBER(2), t_sex CHAR ); --創建記錄測試表 CREATE TABLE test_log( l_user VARCHAR2(15), l_type VARCHAR2(15), l_date VARCHAR2(30) );
創建觸發器:
--創建觸發器 CREATE OR REPLACE TRIGGER TEST_TRIGGER AFTER DELETE OR INSERT OR UPDATE ON TEST DECLARE V_TYPE TEST_LOG.L_TYPE%TYPE; BEGIN IF INSERTING THEN --INSERT觸發 V_TYPE := 'INSERT'; DBMS_OUTPUT.PUT_LINE('記錄已經成功插入,並已記錄到日志'); ELSIF UPDATING THEN --UPDATE觸發 V_TYPE := 'UPDATE'; DBMS_OUTPUT.PUT_LINE('記錄已經成功更新,並已記錄到日志'); ELSIF DELETING THEN --DELETE觸發 V_TYPE := 'DELETE'; DBMS_OUTPUT.PUT_LINE('記錄已經成功刪除,並已記錄到日志'); END IF; INSERT INTO TEST_LOG VALUES (USER, V_TYPE, TO_CHAR(SYSDATE, 'yyyy-mm-dd hh24:mi:ss')); --USER表示當前用戶名 END; / --下面我們來分別執行DML語句 INSERT INTO test VALUES(101,'zhao',22,'M'); UPDATE test SET t_age = 30 WHERE t_id = 101; DELETE test WHERE t_id = 101; --然后查看效果 SELECT * FROM test; SELECT * FROM test_log;
運行結果如下:
3)、創建觸發器,它將映射emp表中每個部門的總人數和總工資
--創建映射表 CREATE TABLE dept_sal AS SELECT deptno, COUNT(empno) total_emp, SUM(sal) total_sal FROM scott.emp GROUP BY deptno; --創建觸發器 CREATE OR REPLACE TRIGGER EMP_INFO AFTER INSERT OR UPDATE OR DELETE ON scott.EMP DECLARE CURSOR CUR_EMP IS SELECT DEPTNO, COUNT(EMPNO) AS TOTAL_EMP, SUM(SAL) AS TOTAL_SAL FROM scott.EMP GROUP BY DEPTNO; BEGIN DELETE DEPT_SAL; --觸發時首先刪除映射表信息 FOR V_EMP IN CUR_EMP LOOP --DBMS_OUTPUT.PUT_LINE(v_emp.deptno || v_emp.total_emp || v_emp.total_sal); --插入數據 INSERT INTO DEPT_SAL VALUES (V_EMP.DEPTNO, V_EMP.TOTAL_EMP, V_EMP.TOTAL_SAL); END LOOP; END; --對emp表進行DML操作 INSERT INTO emp(empno,deptno,sal) VALUES('123','10',10000); SELECT * FROM dept_sal; DELETE EMP WHERE empno=123; SELECT * FROM dept_sal;
顯示結果如下:
4)、創建觸發器,用來記錄表的刪除數據
--創建表 CREATE TABLE employee( id VARCHAR2(4) NOT NULL, name VARCHAR2(15) NOT NULL, age NUMBER(2) NOT NULL, sex CHAR NOT NULL ); --插入數據 INSERT INTO employee VALUES('e101','zhao',23,'M'); INSERT INTO employee VALUES('e102','jian',21,'F'); --創建記錄表(包含數據記錄) CREATE TABLE old_employee AS SELECT * FROM employee; --創建觸發器 CREATE OR REPLACE TRIGGER TIG_OLD_EMP AFTER DELETE ON EMPLOYEE FOR EACH ROW --語句級觸發,即每一行觸發一次 BEGIN INSERT INTO OLD_EMPLOYEE VALUES (:OLD.ID, :OLD.NAME, :OLD.AGE, :OLD.SEX); --:old代表舊值 END; / --下面進行測試 DELETE employee; SELECT * FROM old_employee;
5)、創建觸發器,利用視圖插入數據
--創建表 CREATE TABLE tab1 (tid NUMBER(4) PRIMARY KEY,tname VARCHAR2(20),tage NUMBER(2)); CREATE TABLE tab2 (tid NUMBER(4),ttel VARCHAR2(15),tadr VARCHAR2(30)); --插入數據 INSERT INTO tab1 VALUES(101,'zhao',22); INSERT INTO tab1 VALUES(102,'yang',20); INSERT INTO tab2 VALUES(101,'13761512841','AnHuiSuZhou'); INSERT INTO tab2 VALUES(102,'13563258514','AnHuiSuZhou'); --創建視圖連接兩張表 CREATE OR REPLACE VIEW tab_view AS SELECT tab1.tid,tname,ttel,tadr FROM tab1,tab2 WHERE tab1.tid = tab2.tid; --創建觸發器 CREATE OR REPLACE TRIGGER TAB_TRIGGER INSTEAD OF INSERT ON TAB_VIEW BEGIN INSERT INTO TAB1 (TID, TNAME) VALUES (:NEW.TID, :NEW.TNAME); INSERT INTO TAB2 (TTEL, TADR) VALUES (:NEW.TTEL, :NEW.TADR); END; / --現在就可以利用視圖插入數據 INSERT INTO tab_view VALUES(106,'ljq','13886681288','beijing'); --查詢 SELECT * FROM tab_view; SELECT * FROM tab1; SELECT * FROM tab2;
6)、創建觸發器,比較emp表中更新的工資
--創建觸發器 set serveroutput on; CREATE OR REPLACE TRIGGER SAL_EMP BEFORE UPDATE ON EMP FOR EACH ROW BEGIN IF :OLD.SAL > :NEW.SAL THEN DBMS_OUTPUT.PUT_LINE('工資減少'); ELSIF :OLD.SAL < :NEW.SAL THEN DBMS_OUTPUT.PUT_LINE('工資增加'); ELSE DBMS_OUTPUT.PUT_LINE('工資未作任何變動'); END IF; DBMS_OUTPUT.PUT_LINE('更新前工資 :' || :OLD.SAL); DBMS_OUTPUT.PUT_LINE('更新后工資 :' || :NEW.SAL); END; / --執行UPDATE查看效果 UPDATE emp SET sal = 3000 WHERE empno = '7788';
運行結果如下:
7)、創建觸發器,將操作CREATE、DROP存儲在log_info表
--創建表 CREATE TABLE log_info( manager_user VARCHAR2(15), manager_date VARCHAR2(15), manager_type VARCHAR2(15), obj_name VARCHAR2(15), obj_type VARCHAR2(15) ); --創建觸發器 set serveroutput on; CREATE OR REPLACE TRIGGER TRIG_LOG_INFO AFTER CREATE OR DROP ON SCHEMA BEGIN INSERT INTO LOG_INFO VALUES (USER, SYSDATE, SYS.DICTIONARY_OBJ_NAME, SYS.DICTIONARY_OBJ_OWNER, SYS.DICTIONARY_OBJ_TYPE); END; / --測試語句 CREATE TABLE a(id NUMBER); CREATE TYPE aa AS OBJECT(id NUMBER); DROP TABLE a; DROP TYPE aa; --查看效果 SELECT * FROM log_info; --相關數據字典----------------------------------------------------- SELECT * FROM USER_TRIGGERS; --必須以DBA身份登陸才能使用此數據字典 SELECT * FROM ALL_TRIGGERS;SELECT * FROM DBA_TRIGGERS; --啟用和禁用 ALTER TRIGGER trigger_name DISABLE; ALTER TRIGGER trigger_name ENABLE;