Oracle PL/SQL隨堂筆記總結


1.pl/sql編程

2.存儲過程

3.函數

4.觸發器

5.包

6.pl/sql基礎 -定義並使用變量

7.pl/sql的進階

8.oracle的視圖

1.pl/sql編程

    1.理解oracle的pl/sql的概念
    2.掌握pl/sql編程技術(過程、函數、觸發器)
    pl/sql是標准sql語句的擴展
    簡介
        1.過程、函數、觸發器都是由pl/sql編寫
        2.過程、函數、觸發器是在oracle中
        3.pl/sql是非常強大的過程語言
        4.過程、函數等可以在java程序被調用
    學習必要性:
        1.提高應用程序的性能
        2.模塊化的設計思想
        3.減少網絡傳輸量
        4.提高安全性
    不好的方面:
        移植性差
    pl/sql可以使用變量和邏輯控制語句
    可編寫:分頁存儲過程模塊,訂單處理存儲過程模塊,轉賬存儲過程模塊……

    塊:block 由三部分構成
        定義部分,從declare開始,可選;
        執行部分,從begin開始,必須;
        例外處理部分,從exception開始,可選;

       
實例1-只包括執行部分的pl/sql塊

            set serveroutput on  --打開輸出選項
            begin
                dbms_output.put_line('hello');
            end;
            --說明:dbms_output是oracle所提供的包(類似於java的開發包),該包包含一些過程,put_line就是dbms_output包的一個過程。

        實例2-包含定義部分和執行部分的pl/sql塊

            declare
                v_name varchar2(5);
                v_sal number(7,2);
            begin
                select ename,sal into v_name,v_sal from scott.emp where empno=&jingyu;
                dbms_output.put_line('員工名:'||v_name||'  員工薪水:'||v_sal);
            end;
            --如果返回值不惟一,需要用到參照變量;

        實例3-包含定義部分,執行部分和例外處理部分
            --例外處理部分,為了提高程序的健壯性,應該對可能的錯誤進行處理
            oracle事先定義了一些例外,no_data_found就是找不到數據的例外。
            上例就可以在end前加入如下異常處理部分代碼:

            exception
                when no_data_found then
            dbms_output.put_line('數據不存在,請重新輸入!');

     pl/sql編寫規范
        1.注釋
            單行注釋 --
            多行注釋 /*   */
        2.標識符號的命名規范
            1).定義變量時,用v_ 做前綴
            2).定義常量時,用c_ 做前綴
            3).定義游標時,用_cursor 做后綴
            4).定義例外時,用e_ 做前綴

2.存儲過程

    a.最簡單的存儲過程:

        create or replace procedure sp_pro1 is
        begin
        insert into mytest1 values('shunping','m123');
        end;

    b.調用存儲過程:

        exec sp_pro1;

    c.存儲過程示例:
        1.編寫一個存儲過程,實現功能:可以輸入雇員名,新工資,可以修改雇員的工資。

            create or replace procedure sp_pro2(v_ename varchar2,v_newsal number) is
            begin
                update emp1 set sal=v_newsal where ename=v_ename;
            end;

        2.演示java程序調用oracle的存儲過程
            pl/sql第二講最后幾分鍾。
        3.如何使用過程返回值
            以后解決

3.函數

函數用於返回特定的數據,當建立函數時,在函數頭部必須包含return子句,而在函數體內必須包含return語句返回的數據。
  案例1:輸入雇員的姓名,返回該雇員的年薪。

    create function sp_fun1(spName varchar2)
    return number is
    yearSal number(7,2);
    begin
        select sal*12+nvl(comm,0)*12 into yearSal from emp1 where ename=spName;
        return yearSal;
    end;
    sql>調用函數
    var income number;
    call sp_fun1('SCOTT') into:income;

4.觸發器

觸發器是指隱含執行的存儲過程。當定義一個觸發器時,必須要指定觸發的事件和觸發的操作,常用的觸發事件包括insert,update,delete語句,而觸發操作實際就是一個pl/sql塊。

5.包

包用於在邏輯上組合過程和函數,它由包規范和包體兩部分組成。
  實例1:創建包

    create package sp_package is
        procedure update_sal(ename varchar2,newsal number);
        function annual_sal(name varchar2) return number;
    end;

    --包的規范只包含了過程和函數的說明,沒有過程和函數的實現代碼。
    包體用於實現包規范中的過程和函數
  實例2:建立包體

    create or replace package body sp_package is
    procedure update_sal(name varchar2,newSal number) is
      begin
        update emp1 set sal=newSal where ename=name;
      end;
    function annual_sal(name varchar2)return number is
      yearSal number;
      begin
        select sal*12+nvl(comm,0)*12 into yearSal from emp1 where ename=name;
      return yearSal;
      end;
    end;

  實例3:如何調用包的過程和函數
    調用過程:

    call sp_package.update_sal('SMITH',133);

    調用函數:

    var abc number
    call sp_package.annual('SMITH') into:abc;

6.pl/sql基礎 -定義並使用變量

在編寫pl/sql程序時,可以定義變量和常量;在pl/sql程序中包括有:
①標量類型(scalar)
    標量定義的案例

        v_name  varchar2(20);
        v_sal  number(6,2);
        v_sal  number(6,2):=5.4;
        v_hiredate  date;
        v_valid  boolean  not null default false;

    實例1:輸入員工號,顯示雇員姓名、工資、個人所得稅(稅率為0.03)。

            declare
              c_taxRate number(3,2):=0.03;
              v_ename varchar2(5);
              v_sal number(7,2);
              v_taxSal number(7,2);
            begin
              select ename,sal into v_ename,v_sal from emp1 where empno=&no;
              v_taxSal:=v_sal*c_taxRate;
              dbms_output.put_line('雇員姓名:'||v_ename||' 工資:'||v_sal||' 個人所得稅:'||v_taxSal);
            end;

            ORA-06502: PL/SQL: 數字或值錯誤 :  字符串緩沖區太小
            當ename為MARTIN時,會報上述錯誤,解決方法,定義v_ename時,v_ename emp1.ename%type;
②復合類型(composite)
用於存放多個值的變量。主要包括這幾種
    1)pl/sql記錄    
        類似於高級語言中的結構體(不知道結構體可以先簡單理解成類)
        實例1:

            declare
              --定義一個pl/sql類型,emp_record_type,類型包含3個數據,分別是name,salary,title
              type emp_record_type is record (name emp1.ename%type,salary emp1.sal%type,title emp1.job%type);
              sp_record emp_record_type;
            begin
              select ename,sal,job into sp_record from emp1 where empno=&no;
              dbms_output.put_line('雇員姓名:'||sp_record.name||' 雇員工資'||sp_record.salary);
            end;

    2)pl/sql表    
        相當於高級語言中的數組,但是需要注意的是在高級語言中數組的下標不能為負數,而pl/sql是可以為負數的,並且表元素的下標沒有限制。
        實例1:
            declare

              --定義一個pl/sql表類型,該類型用於存放emp1表中ename字段的這種數據
              type emp_table_type is table of emp1.ename%type index by binary_integer;
              sp_table emp_table_type;
            begin
              select ename into sp_table(-1) from emp1 where empno=&no;
              dbms_output.put_line('名字是:'||sp_table(-1));
            end; 

    3)嵌套表;   

    4)varray;
③參照類型(reference)
參照變量是指用於存放數值指針的變量,通過使用參照變量,可以使得應用程序共享相同對象,從而降低占用的空間。
在編寫pl/sql時,可以使用游標變量(ref_cursor)和對象類型變量(ref_obj_type)兩種參照變量類型。
    1).游標變量(ref_cursor)
    實例1:請使用pl/sql編寫一個塊,可以輸入部門號,顯示該部門所有員工的姓名及其工資。

    --pl/sql參照變量 之游標變量
    declare
      --定義一個游標類型
      type sp_emp_cursor is ref cursor;
      --定義一個游標變量
      test_cursor sp_emp_cursor;
      --定義變量
      v_ename emp1.ename%type;
      v_sal emp1.sal%type;
    begin
      --將游標和select結合
      open test_cursor for select ename,sal from emp1 where deptno=&no;
      --循環取出
      loop
        fetch test_cursor into v_ename,v_sal;
        --判斷何時退出循環 應該是test_cursor為空時退出。
        exit when test_cursor%notfound;
        dbms_output.put_line('名字:'||v_ename||' 工資'||v_sal);
      end loop;
    end;

    實例2:在實例1基礎上,如果哪個員工的工資少於200元,就增加100元。
④lob(large object);

7.pl/sql的進階

控制結構
    (1)使用if語句,
        條件分支語句:if  then;if  then else;if then elsif then else;
        案例1:編寫一個過程,可以輸入一個雇員名,如果該雇員的工資低於2000,就給該雇員工資增加10%。

            --Method1:
            create procedure update_sal(name varchar2) is
            begin
              update emp1 set sal=1.1*sal where sal<2000 and ename=name;
            end;
            --Method2:
            create or replace procedure update_sal2(name varchar2) is
            v_sal emp1.sal%type;
            begin
              select sal into v_sal from emp1 where ename=name;
              if v_sal<2000 then
                update emp1 set sal=1.1*sal where ename=name;
                --exec調用沒有問題;但call調用有問題,在下次查詢才會打印出來
                dbms_output.put_line('此員工工資太低,已經給默認漲10%!');
              end if;
            end;

        案例2:編寫一個過程,輸入一個雇員名,如果他的補助不是0,就增加100.如果是0,就改成200;

            create procedure update_comm(name varchar2) is
            v_comm emp1.comm%type;
            begin
              select comm into v_comm from emp1 where ename=name;
              if v_comm<>0 then
                update emp1 set comm=comm+100 where ename=name;
              else
                update emp1 set comm=200 where ename=name;
              end if;
            end;

        案例3:編寫一個過程,輸入一個雇員編號,如果他是president,工資加1000,如果是manager,工資加500;如果是其他職位,工資加200;

            create or replace procedure update_sal(spNo number) is
            --當上面參數寫empNo時,實驗是不可以的,過程可以成功創建,但是調用有問題。所以最好取不同名字。
            v_job emp1.job%type;
            begin
              select job into v_job from emp1 where empno=spNo;
              if v_job='PRESIDENT' then
                update emp1 set sal=sal+1000 where empno=spNo;
              elsif v_job='MANAGER' then
                update emp1 set sal=sal+500 where empno=spNo;
              else
                update emp1 set sal=sal+200 where empno=spNo;
              end if;
            end;  

    (2)循環語句,
        1.第一種循環結構:
        loop
        ..
        exit when v_num>=10;
        end loop;
        案例:user表中插入10條記錄,編號1-10,姓名"小明"。

            create or replace procedure loop_insert_data(name varchar2) is
            v_num number:=1;
            begin
              loop
                insert into user1 values(v_num,name);
                --判斷退出條件
                exit when v_num>=10;
                v_num:=v_num+1;
              end loop;
            end;

        2.第二種循環結構:
        while v_num<=20 loop
        ..
        end loop;
        案例:user表中插入10條記錄,編號11-20,姓名"小亮"。

            create or replace procedure loop_insert_data2(name varchar2) is
            v_num number:=11;
            begin
              while v_num<=20 loop
                insert into user1 values(v_num,name);
                v_num:=v_num+1;
              end loop;
            end;

        3.第三種循環結構:for循環(不推薦使用,不夠靈活)

            begin
              for i in reverse 1..10 loop
                insert into user1 values (i,'順平');
              end loop;
            end;

    (3)控制語句goto和null;
    goto不推薦使用,降低了程序的可讀性。
    null 不執行任何操作,只是為了提高程序的可讀性。
pl/sql進階:綜合案例之編寫分頁的過程。
1).無返回值的存儲過程,向book表中添加書籍;
create table book(bookid number,bookname varchar2(50),publishhouse varchar2(50));
2).有返回值的存儲過程,可以輸入一個員工的編號,可以返回員工的姓名;
3).有返回值的存儲過程(列表[結果集]),輸入一個部門號,返回該部門所有員工的信息;
    ①創建一個包,定義一個類型test_cursor
    ②創建一個過程
    ③如何在java中調用
4).作業:有了上面的基礎,相信大家可以完成分頁的存儲過程了,要求:可以輸入表名,每頁顯示記錄數,當前頁。返回總記錄數,總頁數,和返回的結果集。
    --1.建立一個包,定義一個游標的類型

    create or replace package sp_package_fy as
    type sp_fy_cursor is ref cursor;
    end sp_package_fy;

    --2.建立一個實現分頁的存儲過程_修正版

    create or replace procedure sp_fenye(spTable in varchar2,spNum in number,spCurrentPage in number,
    spTotalRecord out number,spTotalPage out number,sp_cursor out sp_package_fy.sp_fy_cursor) is
      v_sql varchar2(1000);
      v_begin number:=spNum*(spCurrentPage-1)+1;
      v_end number:=spCurrentPage*spNum;
    begin
      --v_sql賦值
      v_sql:='select * from (select rownum rn,t1.* from (select * from '||spTable||') t1 where rownum<='||v_end||')
      where rn>='||v_begin;
      --顯示指定分頁后詳細的信息
      open sp_cursor for v_sql;
      
      --顯示總記錄數
      v_sql:='select count(*) from '||spTable;
      execute immediate v_sql into spTotalRecord;
      
      --顯示總頁數
      if mod(spTotalRecord,spNum) <> 0 then
        spTotalPage:=spTotalRecord/spNum+1;
      else
        spTotalPage:=spTotalRecord/spNum;
      end if;
      --關閉游標
      --close sp_cursor;
    end;
    --在java程序中調用分頁存儲過程。以后學java時再分析。

例外處理
例外的分類:Oracle將例外分為預定義例外,非預定義例外和自定義例外3類。
(1)預定義例外:定義了oracle常見的錯誤;

data_not_found
case_not_found
cursor_already_open
invalid number
too_many_rows
zero_divide
logon_denied
timeout_on_resourse

(2)非預定義例外:用於處理預定義例外不能處理的例外;

(3)自定義例外:用於處理與oracle錯誤無關的其他情況。
實例:編寫一個存儲過程,輸入一個名字,工資加1000,如果沒有該人,拋出自定義例外。 

8.oracle的視圖

視圖是一個虛擬表,其內容由查詢定義,同真實的表一樣,視圖包含一系列帶有名稱的行和列數據。但是視圖並不在數據庫中以存儲的數據集形式存在,行和列數據來自由定義視圖的查詢所引用的表。

視圖與表的區別

①表需要占用磁盤空間,視圖不需要;

②視圖不能添加索引;

③使用視圖可以簡化復雜查詢;(比如學生選課系統)

④視圖有利於提高安全性;(比如不同用戶查看不同視圖)

創建只讀視圖:create or replace view 視圖名 as select 語句 with read only;

刪除視圖:drop view 視圖名;


免責聲明!

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



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