Oracle數據庫基本操作(四) —— PLSQL編程


  Procedure Language 實際上是Oracle對SQL語言的能力擴展,讓SQL語言擁有了if條件判斷,for循環等處理。

一、PLSQL基本語法

1 DECLARE 
2     -- 聲明部分
3     變量名 變量類型 := 初始值 
4     變量名 emp.sal % TYPE  -- 引用類型的變量
5           emp % rowtype -- 記錄型變量           
6 BEGIN
7     -- 業務邏輯
8 END ;

1、變量的聲明與使用

 1 -- 已知數據類型的賦值聲明 
 2 DECLARE 
 3     i NUMBER := 100 ;
 4 BEGIN
 5     -- 輸出語句相當於 System.out.print();
 6     dbms_output.put_line('Hello World!' || i) ;
 7 END ;
 8 
 9 -- 未知數據類型的類型聲明
10 -- 輸出7369的工資
11 
12 DECLARE 
13     vsal emp.sal % TYPE ;
14 BEGIN
15     -- 給變量賦值
16     SELECT sal INTO vsal FROM emp WHERE empno = 7369 ; 
17     dbms_output.put_line(vsal) ;
18 END ;
19 
20 -- 記錄型變量聲明與賦值
21 -- 輸出7369的所有信息
22 DECLARE 
23     vrow emp % rowtype ;
24 BEGIN    
25     SELECT * INTO vrow FROM emp WHERE empno = 7369 ;
26     dbms_output.put_line(vrow.empno||'   '|| vrow.ename);
27 END ;

2、if條件判斷語法與使用

 1 -- 根據不同年齡輸出信息
 2 DECLARE
 3     -- 由客戶端輸入     
 4     age number := &aaa;
 5 BEGIN
 6     IF age <= 18 THEN
 7         dbms_output.put_line('未成年人');
 8     ELSIF age > 18 AND age <= 24 THEN
 9         dbms_output.put_line('年輕人');
10     ELSIF age > 24 AND age < 48 THEN
11         dbms_output.put_line('中年人');
12     ELSE 
13         dbms_output.put_line('老年人');
14     END IF;
15 END;

3、三種循環

 1 /*
 2    三種循環
 3    for 變量名 in 起始值..結束值  loop
 4      
 5    end loop; 
 6   ----------------------------------
 7    while 條件 loop
 8      
 9    end loop;
10   -----------------------------------    
11    loop
12      exit when 退出的條件
13      循環體
14    end loop;
15 */
16 
17 -- for 循環
18 -- 輸出1-10
19 DECLARE 
20 
21 BEGIN
22     FOR i IN 1..10 LOOP
23         dbms_output.put_line(i);
24     END LOOP;
25 END;
26 -- 輸出10-1
27 DECLARE 
28 
29 BEGIN
30     FOR i IN REVERSE 1..10 LOOP
31         dbms_output.put_line(i);
32     END LOOP;
33 END;
34 
35 -- while 循環
36 DECLARE 
37     i NUMBER := 1;
38 BEGIN
39     WHILE i <= 10 loop
40         dbms_output.put_line(i);
41         i := i+1;
42     END LOOP;
43 END;
44 
45 -- 簡單循環
46 DECLARE 
47     i NUMBER := 1;
48 BEGIN 
49     LOOP
50         EXIT WHEN i > 10;
51         dbms_output.put_line(i);
52         i := i+1;
53     END LOOP;
54 END;

二、游標

1、游標概述  

1.1 游標: (光標/指針) 是對查詢結果集的封裝, 相當於是jdbc中的ResultSet

1.2 語法:

1 -- 聲明游標
2     CURSOR 游標名 IS 查詢語句;
3     CURSOR 游標名(參數名 參數類型) IS 查詢語句 WHERE 列名 = 參數名;

1.3 開發步驟:

1.打開游標 open 游標名

2.從游標中提取數據:

fetch 游標名 into 變量

     游標名%notfound 沒有數據

   游標名%found 找到數據

3.關閉游標 close 游標名

2、使用示例:

 1 -- 無參 
 2 -- 輸出所有員工的信息
 3 DECLARE
 4    -- 聲明游標
 5   CURSOR vemps IS SELECT * FROM emp;
 6    -- 聲明變量
 7   vrow emp % rowtype;
 8 BEGIN
 9    --1. 打開游標
10    open vemps;
11    --2. 提取數據
12    LOOP
13        FETCH vemps INTO vrow;
14         -- 判斷是否有數據
15        EXIT WHEN vemps % notfound;
16         -- 打印數據
17        dbms_output.put_line('姓名:'||vrow.ename||'  工資:'||vrow.sal);
18    END LOOP;
19    
20    -- 關閉游標
21    CLOSE vemps;
22 END;
23 ---------------------------------------------------------------- 
24 -- for 變量游標        
25 DECLARE
26    -- 聲明游標
27    CURSOR vemps IS SELECT * FROM emp;
28    -- 聲明記錄型變量
29    vrow emp % rowtype;
30 BEGIN
31    -- 循環遍歷游標
32    FOR vrow IN vemps
33    LOOP
34         dbms_output.put_line('姓名:'||vrow.ename||' 工資:'||vrow.sal);
35    END LOOP;
36 END;
37 
38 -- ===============================================================
39 -- 有參
40 -- 輸出指定部門的員工信息
41 DECLARE
42    -- 聲明游標
43    CURSOR vemps(vdeptno NUMBER) IS SELECT * FROM emp WHERE deptno = vdeptno;
44    -- 聲明記錄型變量
45    vrow emp % rowtype;
46 BEGIN
47    -- 1. 打開游標
48    OPEN vemps(20);
49    -- 2.循環遍歷游標
50    LOOP
51     FETCH vemps into vrow;
52     EXIT when vemps % notfound;
53       -- 打印數據
54         dbms_output.put_line('姓名:'||vrow.ename||' 工資:'||vrow.sal);
55    END LOOP;
56    -- 3. 關閉游標
57    CLOSE vemps;
58 END;

三、例外

1、例外概述

      例外 (意外): 相當於是java異常

  語法: 

 1 declare 
 2     聲明部分 
 3 begin 
 4     業務邏輯
 5 exception 
 6     處理例外 
 7     when 例外1 then 
 8 
 9     when 例外2 then 
10 
11     when others then 
12 
13 end;

  常見的系統的例外:

    • zero_divide : 除零例外
    • value_error : 類型轉換
    • no_data_found : 沒有找到數據例外
    • too_many_rows : 查詢出多行記錄,但是賦值給了單行變量

2、例外使用示例

 1 DECLARE
 2     i NUMBER;
 3     vrow emp % rowtype;
 4 BEGIN
 5 --     i := 5/0;
 6 --     i := 'aaa';
 7 --     select * into vrow from emp where empno = 1234566;
 8     select * into vrow from emp;
 9 EXCEPTION
10     WHEN too_many_rows THEN
11         dbms_output.put_line('查詢出多行記錄,但是賦值給了單行變量');
12     WHEN no_data_found THEN
13         dbms_output.put_line('發生了沒有找到數據例外');
14     WHEN value_error THEN
15         dbms_output.put_line('發生類型轉換的例外');
16     WHEN zero_divide THEN
17         dbms_output.put_line('發生除零的例外');
18     WHEN others THEN
19         dbms_output.put_line('發生未知的例外');
20 END;

3、自定義例外

  語法:

 1 DECLARE 
 2     -- 聲明例外
 3     例外名稱 EXCEPTION ;
 4 BEGIN
 5     -- 拋出例外
 6     raise 例外名稱 ; 
 7 EXCEPTION 
 8     -- 捕獲例外
 9     WHEN 例外名稱 THEN
10     ....
11 END ;

  使用示例:

 1 -- 查詢指定編號的員工,若沒有找到,則拋出自定義例外
 2 DECLARE 
 3     -- 聲明游標
 4     CURSOR vemps IS SELECT * FROM emp WHERE empno = 1234 ; 
 5     -- 記錄型變量
 6     vrow vemps % rowtype ; 
 7     -- 定義例外
 8     no_emp_found EXCEPTION ; 
 9 BEGIN 
10     --1.打開游標
11     OPEN vemps ;
12     --2.提取記錄 
13     FETCH vemps INTO vrow ;
14     -- 判斷是否有數據 
15     IF vemps % notfound THEN 
16         -- 拋出例外
17         raise no_emp_found ; 
18     END IF ; 
19     -- 關閉游標
20     CLOSE vemps ; 
21 EXCEPTION 
22     WHEN no_emp_found THEN 
23         dbms_output.put_line('沒有找到對應的員工') ; 
24 END ;

 四、存儲過程

1、概述  

  存儲過程: 實際上是將一段已經編譯好的PLSQL代碼片斷,封裝在數據庫中。

  作用:

1. 提高執行效率

2. 提高代碼復用性

  語法:

1 create [or replace] procedure 過程名稱[(參數1 in|out 參數類型,參數2 in|out 參數類型)]
2 is | as
3   -- 聲明    
4 begin
5    -- 業務
6 end;

2、使用示例

  

 1 -- 給指定員工漲薪,並打印漲薪前和漲薪后的工資
 2 -- 員工編號 : 輸入參數
 3 -- 漲多少 : 輸入參數
 4 /*
 5    1. 查詢當前工
 6    2. 打印漲薪前工資
 7    3. 漲工資
 8    4. 打印漲薪后的工資
 9    5. 提交數據
10 */
11 create or replace procedure proc_updatesal(vempno in number,vcount in number)
12 is
13    -- 聲明變量記錄當前工資
14    vsal number;    
15 begin
16    --1. 查詢當前工資
17    select sal into vsal from emp where empno=vempno;
18    --2. 打印漲薪前工資
19    dbms_output.put_line('漲薪前:'||vsal);
20    --3. 漲工資
21    update emp set sal=vsal+vcount where empno=vempno;
22    -- 4. 打印漲薪后的工資
23    dbms_output.put_line('漲薪后:'||(vsal+vcount));
24    --5. 提交數據
25    commit;
26 end;
27 
28 -- 調用存儲過程
29 -- 方式1:
30 call proc_update_sal(7369,100);
31 
32 -- 方式2:
33 declare
34 
35 begin
36    proc_updatesal(7369,100);
37 end;
38 
39 s
40 -- 獲取指定編號員工的年薪
41 /*
42    編號: in  輸入
43    年薪: out 輸出
44 */
45 create or replace procedure proc_getyearsal(vempno in number,vyearsal out number)
46 is
47        
48 begin
49   select sal*12+nvl(comm,0) into vyearsal from emp where empno=vempno;
50 end;
51 
52 -- plsql代碼片斷中調用
53 declare
54    yearsal number;
55 begin
56    proc_getyearsal(7369,yearsal);
57    dbms_output.put_line(yearsal);
58 end;
59 
60 
61 -- 封裝存儲過程,輸出的是游標類型, 所有員工
62 /*
63    sys_refcursor : 系統引用游標
64 */
65 create or replace procedure proc_getemps(vemps out sys_refcursor)
66 is
67 
68 begin
69     -- 打開游標, 誰調用誰關閉
70     open vemps for select * from emp;   
71 end;
72 
73 declare
74   vemps sys_refcursor;
75   vrow emp%rowtype;
76 begin
77   -- 調用存儲過程
78   proc_getemps(vemps);
79   
80   loop
81      fetch vemps into vrow; 
82      exit when vemps%notfound;  
83      dbms_output.put_line(vrow.ename);
84   end loop;
85   -- 關閉游標
86   close vemps;
87 end;

五、存儲函數

1、存儲函數概述

  存儲函數: 實際上是將一段已經編譯好的PLSQL代碼片斷,封裝在數據庫中。

  作用:

1. 提高執行效率

2. 提高代碼復用性

  語法: 

1 create [or replace] function 函數名稱(參數1 in|out 參數類型) return 返回類型 
2 is 
3 
4 begin 
5 
6 end;

  存儲過程和存儲函數:

1. 函數有返回值,過程沒有返回值

2. 函數可以直接在SQL語句中使用,過程不可以

3. 函數能實現的功能,過程能實現

4. 過程能實現的功能,函數也能實現

5. 函數和過程本質上沒有區別 通常情況下,我們自己開發封裝的是存儲過程

2、使用示例

 1 -- 存儲函數:獲取年薪
 2 create or replace function func_getyearsal(vempno number) return number
 3 is
 4   vyearsal number;
 5 begin
 6   select sal*12+nvl(comm,0) into vyearsal from emp where empno=vempno;
 7   return vyearsal;
 8 end;
 9 
10 -- 調用
11 declare
12    yearsal number;
13 begin
14    yearsal := func_getyearsal(7369);
15    dbms_output.put_line(yearsal);
16 end;
17 
18 select emp.*,func_getyearsal(emp.empno) from emp;

 六、觸發器

  1、數據庫觸發器是一個與表相關的、存儲的PL/SQL程序。每當一個特定的數據操作語句(insert,update,delete)在指定的表上發出是,Oracle自動地執行觸發器中定義的語句序列。

  2、作用:

    • 監聽表中的數據變化;
    • 對表中的數據進行校驗

  3、語法:

 1 CREATE [OR REPLACE] TRIGGER 觸發器名稱 
 2 {BEFORE | AFTER}
 3 {INSERT | UPDATE | DELETE} 
 4 ON 表名 
 5 [ FOR EACH ROW [WHEN(條件)]]
 6 DECLARE
 7     ....
 8 BEGIN
 9     PLSQL塊
10 END 觸發器名;

  4、觸發器的類型

  • 行級觸發器:一條SQL語句,影響了多少行記錄,觸發器就會執行多少次;
    • 兩個內置對象:
      • :new 新的記錄
      • :old 舊的記錄
  • 語句級觸發器:一條SQL語句,無論影響了多少行記錄,都只觸發一次;

  5、使用示例

  1 -- 若用戶向表中插入數據之后, 打印一句話
  2 create or replace trigger tri_test1
  3 after
  4 insert 
  5 on emp
  6 declare
  7 
  8 begin
  9    dbms_output.put_line('有人插入了....');
 10 end;
 11 
 12 insert into emp(empno,ename) values(9527,'華安');
 13 -- 執行一條更新工資的語句
 14 
 15 -- 周二老板不在,不能辦理員工入職(不能向員工表中插入數據)
 16 -- 觸發器
 17 -- before insert
 18 -- 判斷今天是否是周二
 19 select trim(to_char(sysdate,'day')) from dual;
 20 
 21 create or replace trigger tri_checkday
 22 before
 23 insert
 24 on emp
 25 declare
 26    vday varchar2(20);
 27 begin
 28    -- 查詢當前周幾
 29    select trim(to_char(sysdate,'day')) into vday from dual;
 30    -- 判斷是否為周二,若為周二,則需要中斷插入操作
 31    if vday = 'tuesday' then
 32      --                   -20000 - -20999
 33      raise_application_error(-20001,'周二老板不在,不能插入');
 34    end if;
 35 end;
 36 
 37 insert into emp(empno,ename) values(9527,'華安');
 38 
 39 select * from emp;
 40 
 41 -- 語句級觸發器
 42 create trigger tri_test3
 43 before
 44 update
 45 on emp
 46 declare
 47 
 48 begin
 49   dbms_output.put_line('語句級觸發器'); 
 50 end;
 51 
 52 -- 行級觸發器
 53 create or replace trigger tri_test4
 54 before
 55 update
 56 on emp
 57 for each row
 58 declare
 59 
 60 begin
 61   dbms_output.put_line('行級觸發器,舊的工資:'||:old.sal||'  新的工資:'||:new.sal); 
 62 end;
 63 
 64 update emp set sal=sal+100;
 65 
 66 -- 6個月 ---> 人事 加薪 ---> 加10塊錢 ---> 老板簽字
 67 -- 校驗員工薪資 調整后的工資一定要 大於 薪資調整前的工資
 68 -- 觸發器:  before update on emp
 69 -- 行級觸發器
 70 create or replace trigger tri_checksal
 71 before
 72 update
 73 on emp
 74 for each row
 75 declare
 76 
 77 begin
 78   -- 調整后的工資 <= 薪資調整前的工資 ,則中斷更新操作
 79   -- :new.sal    <= :old.sal
 80   if :new.sal <= :old.sal then
 81      raise_application_error(-20002,'坑爹的,降薪啦!');
 82   end if;
 83 end;
 84 
 85 update emp set sal=sal-100;
 86 
 87 /*
 88      使用觸發器模擬類似auto_increment功能
 89      當用戶插入的時候,若為sid為null,則給sid賦值一個編號
 90 */
 91 create table stu(
 92      sid number primary key,
 93      name varchar2(20)
 94 );
 95 
 96 -- 創建一個序列
 97 create sequence seq_stu;
 98 
 99 -- 觸發器: before insert on stu
100 -- 行級觸發器
101 create or replace trigger tri_auto
102 before
103 insert 
104 on stu
105 for each row
106 declare
107 
108 begin
109    -- 從序列中查詢一個數字出來,賦值給sid
110    select seq_stu.nextval into :new.sid from dual;
111 end;
112 
113 -- 同樣一張表,有時候自己指定id, 有時候需要數據庫自動生成id
114 insert into stu values(null,'zs');
115 insert into stu values(4,'zs');
116 select * from stu; 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM