PL/SQL 編程(二)

  1. 前面第一篇衆中講述了Java程序調用存儲過程,這裏再加以補充。java

    存儲過程可能無返回值、有返回值(非列表)、返回結果集等幾種狀況,下面一一舉例:sql

  2. --建表
    drop table book;
    
    create table book(
    bookId number(10) primary key,
    bookName varchar2(50),
    publishHouse varchar2(50),
    bookClass number(3) not null);
    
    /*
    案例 
    實例16-向表book中添加書籍,並用java程序調用:
    */
    
    --存儲過程:in 表示輸入參數, out表示輸出參數, 不寫默認是輸入參數
    create or replace procedure add_book(proBookId in number, proBookName in varchar2, proPublishHouse in varchar2, proBookClass in number) is
    begin
      insert into book values(proBookId, proBookName, proPublishHouse, proBookClass);
    end;
    
    /*
    --Java調用
    public class TestProcedure {
    	public static void main(String[] args) {
    		Connection conn = null;
    		CallableStatement cs = null;
    		
    		try {
    			//加載驅動
    			Class.forName("oracle.jdbc.driver.OracleDriver");
    			//得到鏈接
    			conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl", "dog", "dog");
    			cs = conn.prepareCall("{call add_book(?, ?, ?)}");
    			
    			//設置參數
    			cs.setInt(1, 1);
    			cs.setString(2, "Thinking in Java");
    			cs.setString(3, "America Universe Publish");
          cs.setInt(4, 1);
    	
    			//執行
    			cs.execute();
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			try {
    				cs.close();
    				conn.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }
    */
    
    /*
    案例:有返回值的存儲過程(返回值非列表)
    實例17-輸入書籍編號,返回書籍名、出版社
    */
    create or replace procedure get_book(proBookId in number, proBookName out varchar2, proPublishHouse out varchar2) is
    begin
      select bookName, publishHouse into proBookName, proPublishHouse from book where bookId = proBookId;
    end;
    
    /*
    --Java調用
    public class TestProcedure {
    	public static void main(String[] args) {
    		Connection conn = null;
    		CallableStatement cs = null;
    		
    		try {
    			//加載驅動
    			Class.forName("oracle.jdbc.driver.OracleDriver");
    			//得到鏈接
    			conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl", "dog", "dog");
    				
    			cs = conn.prepareCall("{call get_book(?, ?, ?)");
          //設置輸入參數
    			cs.setInt(1, 1);
    			//設置輸出參數
    			cs.registerOutParameter(2, oracle.jdbc.OracleTypes.VARCHAR);
    			cs.registerOutParameter(3, oracle.jdbc.OracleTypes.VARCHAR);
    			
    			//執行
    			cs.execute();
    			
    			//輸出返回值
    			String bookName = cs.getString(2);
    			String publishHouse = cs.getString(3);
    			System.out.println("書名:" + bookName + "  ---出版社:" + publishHouse);
    		
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			try {
    				cs.close();
    				conn.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }
    */
    
    /*
    案例:有返回值的存儲過程(返回值是列表(結果集))
    因爲返回的是結果集,不能使用通常的out參數,必須使用package。
    實例18-輸入書籍類別,返回書籍信息
    */
    
    --再向book表中插入幾條數據
    --insert into book values(1, 'Thinking in Java', 'America Universe Publish', '001');
    insert into book values(2, 'Harry Potter', 'Titan Books Ltd', '001');
    insert into book values(3, 'The Accident', 'Orion Publishing Co', '001');
    
    --第一步:建立一個包
    --定義一個遊標類型 
    create or replace package pak_ResultSet is
      type pak_cursor_type is ref cursor;
    end;
    
    --第二部:建立存儲過程
    create or replace procedure pro_ResultSet(proBookClass in number, pak_cursor out pak_ResultSet.pak_cursor_type) is
    begin
     --打開遊標
      open pak_cursor for select * from book where bookClass = proBookClass;
    end;
    
    /*Java調用
    
    public class TestProcedure {
    	public static void main(String[] args) {
    		Connection conn = null;
    		CallableStatement cs = null;
    		ResultSet rs = null;
    		
    		try {
    			//加載驅動
    			Class.forName("oracle.jdbc.driver.OracleDriver");
    			//得到鏈接
    			conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl", "dog", "dog");	
    			
    			//有輸入參數 和 輸出參數,輸出參數 是 結果集
    			cs = conn.prepareCall("{call pro_ResultSet(?, ?)}");
    			cs.setInt(1, 1);
    			//結果集參數設置
    			cs.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR);
    			
    			cs.execute();
    			
    			//獲得結果
    			rs = (ResultSet) cs.getObject(2);
    			
    			while (rs.next()) {
    				System.out.println("書編號:" + rs.getInt(1) + "  ---書名:" + rs.getString(2) + "  ---出版社:" + rs.getString(3) + "  ---類別:" + rs.getString(4));
    			}
    		
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			try {
    				cs.close();
    				conn.close();
    				rs.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }
    */
  3. PL/SQL的例外處理:數據庫

    oracle 將例外分爲:預約義例外、非預約義例外和自定義例外 三種。前二者用來處理與oracle錯誤相關的,而且出現的oracle錯誤會隱含觸發相應的例外;而自定義例外與oracle的錯誤沒有任何關聯,它是由開發人員爲特定狀況所定義的例外。安全

    a. 預約義例外:用於處理常見的oracle錯誤;非預約義例外用於處理預約義例外不能處理的例外;自定義例外用於處理     與oraccle錯誤無關的其餘狀況。oracle

        oracle預約義例外大概有20多個,下面介紹一些常見的預約義例外:ide

  4. /*
    預約義例外: no_data_found, 以前在第一篇中出現過,再也不贅述
    */
    
    /*
    預約義例外: case_not_found
    */
    create or replace procedure pro_caseException(EmployNum number) is
      v_sal emp.sal%type;
    begin
      select sal into v_sal from emp where empno = EmployNum;
      case
        when v_sal < 1000 then
          update emp set sal = sal + 200 where empno = EmployNum;
        when v_sal < 2000 then
          update emp set sal = sal + 100 where empno = EmployNum;
          --這裏若是沒有指定default狀況,而又不符合上面兩個case,可能會報錯,能夠在下面指定exception
      end case;
      exception when case_not_found then
        dbms_output.put_line('case not matched');
    end;
    
    /*
    預約義例外: cursor_already_open
    */
    declare
      cursor emp_cursor is select ename, sal from emp;
    begin
      open emp_cursor;
      for emp_record1 in emp_cursor loop
        dbms_output.put_line(emp_record1.ename);
      end loop;
      exception when cursor_already_open then
        dbms_output.put_line('Cursor has been opened!');
    end;
    
    /*
    預約義例外: dup_val_on_index  在惟一索引對應的列上插入重複的值時,會隱含的觸發該例外
    */
    begin
      insert into dept values(10, '技術部', 'shanghai');
      
      exception when dup_val_on_index then
        dbms_output.put_line('Duplicated Deptno!');
    end;
    
    /*
    預約義例外: invalid_cursor  當試圖在不合法的遊標上執行操做時,會觸發該例外(遊標沒有打開或是關閉沒有打開的遊標)
    */
    declare
      cursor emp_cursor is select ename, sal from emp;
      emp_record emp_cursor%rowtype;
    begin
      --open emp_cursor;
      fetch emp_cursor into emp_record;
        dbms_output.put_line(emp_record.ename);
      close emp_cursor;
      
      exception when invalid_cursor then
        dbms_output.put_line('Cursor has been closed!');
    end;
    
    /*
    預約義例外: invalid_number  當輸入的數據有誤時,會觸發該例外
    */
    begin
      update emp set sal=sal + 'abc';
      
      exception when invalid_number then
        dbms_output.put_line('Number error!');
    end;
    
    /*
    預約義例外: too_many_rows  當執行select into 語句時,若是返回超過了一行,則會觸發該例外
    */
    declare
      v_ename emp.ename%type;
    begin
      select ename into v_ename from emp;
      
      exception when too_many_rows then
        dbms_output.put_line('Return too many rows!');
    end;
    
    /*
    預約義例外: zero_divide  當執行2/0 語句時,則會觸發該例外
    */
    declare
      c_num number := 2;
    begin
      c_num := c_num/0;
      
      exception when zero_divide then
        dbms_output.put_line('Zero cannot be divide!');
    end;
    
    /*
    預約義例外: value_error  當在執行賦值操做時,若是變量的長度不足以容納實際數據,則會觸發該例外
    */
    declare
      v_ename varchar2(5);
    begin
      select ename into v_ename from emp where empno = 7654;
      
      exception when value_error then
        dbms_output.put_line('Value is too large for v_ename!');
    end;
    
    /*
    其餘預約義例外:
    login_denide --- 用戶非法登錄時,會觸發該例外
    not_logged_on --- 用戶沒有登錄就執行dml操做,,會觸發該例外
    storage_error --- 超出了內存空間或者內存被損壞,,會觸發該例外
    timeout_on_resource --- 若是oracle在等待資源時出現超時,,會觸發該例外
    */

    b. 自定義例外與oracle的錯誤沒有任何關聯,它是由開發人員爲特定狀況所定義的例外。oop

  5. /*
    自定義例外:
    */
    create or replace procedure test_ModifiedException(EmployeeNo number) is
      --定義一個例外
      myex exception;
    begin
      update emp set sal = sal + 1000 where empno = EmployeeNo;
      --sql%notfound 表示沒有update
      --raise myex; 觸發myex 例外
      if sql%notfound then
        raise myex;
      end if;
      exception when myex then
        dbms_output.put_line('Myex has been occured!');
    end;
  6. 視圖(View):視圖是一個虛擬表,其內容由查詢定義。同真實的表同樣,視圖包含 帶有名稱的列和行數據。可是視圖並不在數據庫中以存儲的數據值集形式存在。行和列數據來自 由自定義視圖的查詢所引用的表,而且在引用視圖時動態生成。視圖和視圖能夠聯合查詢。fetch

    視圖和表的區別:spa

    1. 表須要佔用磁盤空間,而視圖不須要code

    2. 視圖不能添加索引,因此查詢速度會比錶慢一些

    3. 使用試圖能夠簡化複雜查詢

    4. 視圖有利於提升安全性(不一樣用戶查詢不一樣內容的視圖,分隔權限)

    語法:

    建立視圖:create or replace view viewName as select ...  [with read only]

    刪除視圖:drop view viewName

相關文章
相關標籤/搜索