OraclePLSQL程式設計

weixin_33981932發表於2018-03-23

PL/SQL程式設計

pl/sql(procedural language/sql)是Oracle在標準的sql語言上的擴充套件。pl/sql不僅允許嵌入式sql語言,還可以定義變數和常量,允許使用條件語句和迴圈語句,允許使用例外處理各種錯誤。這樣使得他的功能變的更強大。缺點是移植性不好。

編寫一個儲存過程,向表中新增資料。

  1. create table mytest (name varchar2(30),passwd varchar2(30));
  2. create or replace procedure xxc_pro1 is

begin

insert into mytest values ('小紅','m123');

end;

  1. 呼叫過程  exec  過程名(引數1,引數2…)或call 過程名引數1,引數2…)

①    exec xxc_pro1;   或者是

②    call xxc_pro1;

pl/sql可以做什麼?

塊:包括過程、函式、觸發器、包。

編寫規範:

  1. 註釋  --:單行註釋

eg:select * from emp where empno=7788;--取得員工資訊

    /*……*/多行註釋

  1. 表示符號(變數)的命名規範:

①    當定義變數時,建議用v_作為字首:v_ename

②    當定義常量時,建議用c_作為字首:c_rate

③    當定義遊標時,建議用_cursor作為字尾:emp_cursor

④    當定義例外時,建議用e_作為字首:e_error

塊(block)是pl/sql的今本程式單元,編寫pl/sql程式實際上就是在編寫pl/sql塊;pl/sql塊由三部分組成:定義部分,執行部分,例外處理部分。

declare  --可選部分

/*定義部分:定義常量,變數,遊標,例外,複雜資料型別*/

begin   --必選部分

/*執行部分:要執行的pl/sql語句和sql語句*/

exception  --可選部分

/*例外處理部分:處理執行的各種錯誤*/

 

例項1:只包含執行部分的pl/sql塊

SQL> set serveroutput on  --開啟輸出

SQL> begin

  2  dbms_output.put_line('hello');

  3  end;

  4  /

說明:dbms_output是oracle提供的包,該包包含一些過程,put_line就是其中之一。

例項2:包含定義部分和執行部分

SQL> declare

  2  v_ename varchar2(5);

  3  begin

  4  select ename into v_ename from emp where empno = &no;

  5  dbms_output.put_line('僱員名'||v_ename);

  6  end;

  7  /

說明:&:從控制檯輸入變數,會彈出一個對話方塊。

例項3.同時輸出僱員名和工資

SQL> declare

  2  v_ename varchar2(20);

  3  v_sal number(10,2);

  4  begin

  5  select ename,sal into v_ename,v_sal from emp where empno=&no;

  6  dbms_output.put_line('僱員名:'||v_ename||' 工資:'||v_sal);

  7  end;

  8  /

包含定義,執行,和例外處理的pl/sql塊。

例項4.當輸入的員工號不存在時

SQL> declare

  2  v_ename varchar2(20);

  3  v_sal number(10,2);

  4  begin

  5  select ename,sal into v_ename,v_sal from emp where empno =&no;

  6  dbms_output.put_line('僱員名:'||v_ename||' 工資:'||v_sal);

  7  exception   --異常處理部分

  8  when no_data_found then

  9  dbms_output.put_line('請輸入正確的員工號!');

 10  end;

 11  /

以上為塊的基礎,下面來介紹塊的各個組成:過程,函式,觸發器,包。

過程

過程用於執行特定的操作,當執行過程的時候,可以指定輸入引數(in),也可以指定輸出引數(out)。通過在過程中使用輸入引數,可以講資料輸入到執行部分,通過使用輸出引數,可以將執行部分的資料輸出到應用環境,在pl/sql中可以使用create procedure命令來建立過程。

編寫一個儲存過程,可以輸入僱員名和新工資來改變員工工資。

--案例

create or replace procedure xxc_pro3(newname in varchar2,newsal in number) is 

begin

update emp set sal=newsal where ename=newname;

end;

呼叫   exec xxc_pro3(‘SCOTT’,2900);[A1] 

--in表示是輸入引數,可以不寫,預設是in,但out必須寫。

在java程式中呼叫儲存過程來修改工資;

//演示java程式呼叫oracle中的儲存過程

 

package TestOraPro;//根據不同的包,包名不同

import java.sql.*;

 

public class TestOraPro {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       // TODO Auto-generated method stub

       try{

       //載入驅動

       Class.forName("oracle.jdbc.driver.OracleDriver");

       //得到連線   1521為埠號

       Connection ct = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:CUIXIAO2","scott","xxc");

       //建立callablestatement

       CallableStatement cs=ct.prepareCall("{call xxc_pro3(?,?)}");

       //給?賦值

       cs.setString(1, "SMITH");

       cs.setInt(2,2600);

       //執行

       cs.execute();

      

       }catch(Exception e){

            e.printStackTrace();

       } finally{

           //關閉資源

           cs.close();

           ct.close();

}

    }

}

以上為過程基礎,後會詳細講。

 

函式

函式用於返回特定的資料,當建立函式時,在函式頭部必須包含return子句,而在函式體內必須包含return語句來返回資料,可以使用create function來建立函式。

案例1.返回工人年工資。

--函式案例

create or replace function xxc_fun1(newname varchar2)

return number is yearSal number(10,2);

begin

select sal*12+nvl(comm,0)*12 into yearSal from emp where ename=newname;

return yearSal;

end;

在sqlplus中呼叫函式

sql>var income number;

sql>call xxc_fun1(‘SCOTT’) into: income;

sql>print income;

在java中呼叫函式

select xxc_fun1(‘SCOTT’) from dual;

這樣可以通過rs.setInt(1)得到返回結果。

 

包用於在邏輯上組合過程和函式,它由包規範和包體兩部分組成。

1.我們可以用create(or replace) package命令來建包;

    例項:create package xxc_package is

           Procedure update_sal (name varchar2,newsal number);

           Function annual_sal(name varchar2) return number;

           End;

包規只包含過程和函式的說明,但是沒有函式和過程的實現程式碼。[A2] 

包體用於實現包規範中的過程和函式。

2.建立包體可以用create package body命令。

    create package body xxc_package is

    Procedure update_sal(name varchar2,newsal number) is

    begin

    update emp set sal=newsal where ename=name;

    end;

    function annual_sal(name varchar2) return number is

    annual_salary number;

    begin

    select sal*12+nvl(comm,0)*12 into annual_salary from emp    where ename=name;

    return;

    end;

    end;

[A3] 3.如何呼叫包中的過程和函式。

    在過程和函式前加上包名。

    exec xxc_package.update_sal(‘SCOTT’,120);

觸發器

觸發器是指隱含的儲存過程,當定義觸發器是,必須指定觸發事件和觸發的操作,常用的觸發操作有insert、update和delete。觸發器操作實際上是一個pl/sql塊,可以使用create trigger命令來建立觸發器。因為觸發器內容很多,會在後面詳細介紹,觸發器是非常有用的,可以用來維護資料庫的安全和一致性。

 

在編寫pl/sql塊時可以定義的變數和常量;

  1. 標量型別(scalar);
  2. 複合型別(composite);
  3. 參照型別(reference);
  4. lob(large ofject);

 

標量型別(scalar)—常用型別

語法格式(即前邊最常見的格式)

變數名 [constant] datatype [not null] [:=/default expr]

expr:指定初始值的pl/sql表示式,可以是文字,其他變數,函式等。

定義標量案例

①    定義一個變長字串

V_ename varchar2(10);

②    定義一個小數,範圍在-9999.99~9999.99

v_sal number(6,2);

③    定義一個小數並賦初值  :=是pl/sql的賦值符號;

v_sal number(6,2):=12.3;

④    定義一個日期型別數

v_birthday date;

⑤    定義一個布林型別變數,不能為空,預設是false;

v_valid boolen not null default false;

[A4] 下面以輸入員工號,顯示員工姓名,工資,個人所得稅(稅率為0.03)為例,說明變數的使用。

declare

c_tax_rate number(3,2):=0.03;

v_ename varchar2(5);

v_sal number(10,2);

v_tax_sal number(10,2);

begin

select ename,sal into v_ename,v_sal from emp where empno=&no;

v_tax_sal:=v_sal*c_tax_rate;

dbms_output.put_line(‘員工名:’||v_ename||’工資:’||v_sal||’繳稅:’||v_tax_sal);

end;

 

對於上邊的pl/sql塊,有一個問題。

如果員工的名字長於5個字元,就會出現錯誤,為了降低pl/sql的維護工作量,可以使用%type屬性來定義變數,這樣它會按照資料庫列來確定你定義的變數的型別和長度。

變數名  表名.列名%type

對於上例的改動

v_ename emp.ename%type;

v_sal emp.sal%type;

複合型別(composite)-介紹

用於存放多個值的變數,主要包括這幾種:

① pl/sql記錄;

② pl/sql表;

③ 巢狀表;

④ varray;

其中① ② 用的多,③ ④ 用的少。

1.pl/sql的記錄。

類似於高階語言的結構體,當引用pl/sql記錄成員的時候,必須要加記錄變數作為字首(記錄變數.記錄成員)。

如:declare

type emp_record_type is record(name emp.ename%type, salary emp.sal%type,title emp.job%type);[A5] 

xxc_record emp_record_type;

begin

select ename,sal,job into xxc_record from emp where empno=&no;

dbms_output.put_line(‘員工名:’||xxc_record.name||’工資:’||xxc_record.salary);

end;

2.pl/sql

相當於高階語言中的陣列,需要注意的是高階語言中的陣列的下標不能為負,但表的下標沒有限制,可以為負。[A6] 

例如:declare           -- binary_integer表示下標是整數

type xxc_table_type is table of emp.ename%type index by binary_integer;

xxc_table xxc_table_type;

begin        --下標0可以是任何整數,-1,-2,23都可以,但輸出的時候也要是同一個數,不然會出錯。

select ename into xxc_table(0) from emp where empno=7788;

dbms_output.put_line(‘員工名:’||xxc_table(0));

end;

在這個例項中,如果把where子句去掉,就會出錯,因為你只請求了一個資料,而返回了多行資料。解決辦法是使用參照變數。

參照變數

參照變數是指用於存放資料指標的變數,通過使用參照變數可以使得應用程式共享相同的物件,從而降低佔用的空間。在編寫pl/sql程式時,可以使用遊標變數(ref cursor)和物件型別變數(ref obj_type)這兩種參照變數,用得多的是遊標變數。

遊標變數

定義遊標是,不需要指定select語句,但當使用遊標(open)時,需要指定select語句,這樣一個遊標就與一個遊標就與一個select語句結合了。

例項:① 編寫一個pl/sql塊,輸入部門號,顯示所有員工名和工資。

       declare

       type xxc_emp_cursor is ref cursor;

test_cursor xxc_emp_cursor;

       v_ename emp.ename%type;

       v_sal emp.sal%type;

       begin

open test_cursor for select ename,sal from emp where deptno=&no;

loop

fetch test_cursor into v_ename,v_sal;

exit when test_cursor%notfound;

dbms_output.put_line(‘名字:’||v_ename||’工資:’||v_sal);

end loop;

close test_cursor;

[A7] end;

②  在① 的基礎上,如果員工的工資低於2000,加100

declare

       type xxc_emp_cursor is ref cursor;

test_cursor xxc_emp_cursor;

       v_ename emp.ename%type;

       v_sal emp.sal%type;

       begin

open test_cursor for select ename,sal from emp where deptno=&no;

loop

fetch test_cursor into v_ename,v_sal;

exit when test_cursor%notfound;

if v_sal<2000 then

update emp set sal=sal+100 where ename=v_ename;

v_sal=v_sal+100;

end if;

dbms_output.put_line(‘名字:’||v_ename||’工資:’||v_sal);

end loop;

close test_cursor;

end;

[A8] Pl/sql分支控制語句

1.條件分支語句

    if…then   if…then…else   if…then…eslif…then…else…

當if語句結束時要有end if。

    不等於號是<>,不是!=,

    if job=’MANAGER’,是單引號,不是雙引號。

2.迴圈語句 

--loop是pl/sql中最簡單的迴圈語句,這種迴圈以loop開始,以end loop結束,此迴圈至少會被執行一次。

例:編寫一個迴圈過程,可輸入使用者名稱,並迴圈新增10個使用者到user表中,使用者編號從1開始。

Sql>create table user(userid number(10),username varchar2(20));

Sql>create procedure xxc_insert_user1(name varchar2) is

       declare

       v_Num number:=1;  --不用指定大小嗎?

       begin

       loop

       insert into user values(v_num,name);

       exit when v_num=10;[A9] 

       v_num:=v_num+1;  --Oracle中沒有++符號

       end loop;

       end;

--while迴圈

當while條件為真時,執行迴圈體。

以while…loop開頭,以end loop結尾。

例:上題,使用者號從11開始,新增10名使用者。

create procedure xxc_insert_user2(name varchar2) is

declare

v_Num number:=11;  --不用指定大小嗎?

    begin

    while v_num<=20 loop

    insert into user values(v_num,name);

    v_num:=v_num+1;

    end loop;

    end;

--for迴圈

迴圈基本結構如下:

begin

    for i in reverse 1..10 loop

    insert into users(I,’小紅’);

    end loop;

    end;

順序控制語句   --goto,null

Goto語句會增加程式的複雜性,降低可讀性,一般不使用,但有時會很方便。

基本語法     goto lable ,lable是定義好了的標籤。

例:declare

    i int:=1;

    begin

    loop

    dbms_output.put_line(‘i=’||i);

    if i=10 then

    goto end_loop;

    end if;

    end loop;

<<end_loop>>    --此為標籤,注意格式

dbms_output.put_line(‘迴圈結束’);

end;

null語句不執行任何操作,好處是可以提高程式的可讀性。

例:if sal<2000 then

       update emp set sal=sal+100 where ename=name;

       else

       null;

 

編寫分頁過程

從易到難,先寫簡單的過程。

寫無返回值的過程,並被Java程式呼叫,前邊已寫過,不再重寫。現在寫一個有返回值的過程,並用Java程式呼叫。

例:輸入員工號,輸出員工姓名。

Create procedure xxc_pro4 (empid in number,empname out varchar2) is

Begin

Select ename into empname from emp where empno = empid;

End;

Java程式呼叫。

import java.sql.*;

 

public class TestOraPro1 {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       // TODO Auto-generated method stub

       try{

       //載入驅動

       Class.forName("oracle.jdbc.driver.OracleDriver");

       //得到連線   1521為埠號

       Connection ct = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:CUIXIAO2","scott","xxc");

       //建立callablestatement

       CallableStatement cs=ct.prepareCall("{call xxc_pro4(?,?)}");

       //給第一個?賦值

       cs.setInt(1,7788);

       //給第二個?賦值

       cs.registerOutParameter(2,oracle.jdbc.OracleTypes.VARCHAR);

       //執行

       cs.execute();

       //取出返回值,要注意?的順序,第幾個?是返回值就寫幾。

       String name = cs.getString(2);

       System.out.println(“7788的名字是”+name);

      

       }catch(Exception e){

            e.printStackTrace();

       }finally{

           //關閉資源

           cs.close();

           ct.close();

}

    }

}

案例擴充套件:輸入一個員工號,輸出該員工的名字,工資和崗位。

create procedure xxc_pro5(empid in number,empname out varchar2,empsal out number,empjob out varchar2) is

begin

select ename,sal,job into empname,empsal,empjob from emp where empno=empid;

end;

Java呼叫

import java.sql.*;

 

public class TestOraPro1 {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       // TODO Auto-generated method stub

       try{

       //載入驅動

       Class.forName("oracle.jdbc.driver.OracleDriver");

       //得到連線   1521為埠號

       Connection ct = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:CUIXIAO2","scott","xxc");

       //建立callablestatement

       CallableStatement cs=ct.prepareCall("{call xxc_pro4(?,?,?,?)}");

       //給第一個?賦值

       cs.setInt(1,7788);

       //給後3個?賦值

       cs.registerOutParameter(2,oracle.jdbc.OracleTypes.VARCHAR);

       cs.registerOutParameter(3,oracle.jdbc.OracleTypes.DOUBLE);

       cs.registerOutParameter(4,oracle.jdbc.OracleTypes.VARCHAR);

       //執行

       cs.execute();

       //取出返回值,要注意?的順序,第幾個?是返回值就寫幾。

       String name = cs.getString(2);

       String job = cs.getString(4);

       System.out.println(“7788的名字是”+name+” 工作是”+job);

      

       }catch(Exception e){

            e.printStackTrace();

       }finally{

           //關閉資源

           cs.close();

           ct.close();

}

    }

}

帶有返回值的儲存過程(結果集是個列表)。

案例:編寫個儲存過程,輸入部門號,輸出該部門的所有員工的資訊。

分析如下:

由於Oracle的儲存過程沒有返回值,它的所有返回值都是通過out引數來替代的,列表同樣也不例外,但由於是個集合,所以不能用一般引數,必須要用package。所以分為兩部分。

① 建立一個包,在包中定義一個test_package,是個遊標;

create package test_package as type test_cursor is ref cursor;

End test_package;

②    建立儲存過程

create procedure xxc_pro6(xxcno in number,xxc_cursor out test_package.test_cursor) is

begin

open xxc_cursor for select * from emp where deptno=xxcno;

end;

在Java中呼叫此儲存過程

import java.sql.*;

 

public class TestOraPro1 {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       // TODO Auto-generated method stub

       try{

       //載入驅動

       Class.forName("oracle.jdbc.driver.OracleDriver");

       //得到連線   1521為oracle埠號

       Connection ct = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:CUIXIAO2","scott","xxc");

       //建立callablestatement

       CallableStatement cs=ct.prepareCall("{call xxc_pro6(?,?)}");

       //給第一個?賦值

       cs.setInt(1,10);

       //給第二個?賦值

       cs.registerOutParameter(2,oracle.jdbc.OracleTypes.CURSOR);

       //執行

       cs.execute();

       //得到結果集

       ResultSet rs = (ResustSet)cs.getObject(2);

       While(rs.next()){

       System.out.println(rs.getInt(1)+” ”+rs.getString(2)+” ”+rs.getString(3));

       }

       }catch(Exception e){

            e.printStackTrace();

       }finally{

           //關閉資源

           cs.close();

           ct.close();

}

    }

}

開始編寫分頁過程。

例:請編寫一個儲存過程,要求可以輸入表名、每頁顯示記錄數、當前頁,返回總記錄數、總頁數和返回的結果集。

現在先回顧一下分頁的語句,這是個模板。

select * from (select t1.*,rownum rn from (select * from emp)  t1 where rownum<=10) where rn>=6;

① 建立一個包,在包中定義一個test_package2,是個遊標;

create package test_package2 as type test_cursor2 is ref cursor;

End test_package2;

② 建立儲存過程;

create procedure fenye is

(tablename in varchar2,  --表名

rowsize in number,  --每頁記錄數

pagenow in number,  --當前頁

recordnum out number,  --總記錄數

pagenum out number,    --總頁數

set_cursor out test_package2.test_cursor2  --結果集的遊標

) is

v_sql varchar2(1000);

v_begin nuber:=(pagenow-1)*rowsize+1;

v_end nuber:=pagenow*rowsize;

begin

--v_sql是連線字串,有點繞,看仔細

 

 v_sql := 'SELECT * FROM (SELECT T.*,ROWNUM rn FROM (SELECT * FROM ' ||

           TABLENAME || ' ) T WHERE ROWNUM <= ' || V_END ||

           ' ) WHERE rn >= ' || V_BEGIN;

--開啟遊標,把遊標和sql語句結合起來

open set_cursor for v_sql;

--計算recordnum和pagenum

v_sql:= 'SELECT COUNT(*) FROM ' || TABLENAME;

execute immediate v_sql into recordnum;

if mod(recordnum,rowsize)=0 then

    pagenum:=recordnum/rowsize;

else

    pagenum:=recordnum/rowsize+1;

end if;

close set_cursor;

end;

用Java程式呼叫:

import java.sql.*;

 

public class TestOraPro1 {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

       // TODO Auto-generated method stub

       try{

       //載入驅動

       Class.forName("oracle.jdbc.driver.OracleDriver");

       //得到連線   1521為埠號

       Connection ct = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:CUIXIAO2","scott","xxc");

       //建立callablestatement

       CallableStatement cs=ct.prepareCall("{call fenye(?,?,?,?,?,?)}");

       //給?賦值

       cs.setString(1,”emp”);

       cs.setInt(2,5);

       cs.setInt(3,1);

       //註冊總記錄數

       cs.registerOutParameter(4,oracle.jdbc.OracleTypes.INTEGER);

       //註冊總頁數

cs.registerOutParameter(5,oracle.jdbc.OracleTypes.INTEGER);

//註冊結果集

cs.registerOutParameter(6,oracle.jdbc.OracleTypes.CURSOR);

 

       //執行

       cs.execute();

//取出返回值,要注意?的順序,第幾個?是返回值就寫幾。

       int rnum=cs.getInt(4);

       int pnum=cs.getInt(5);

       ResultSet rs=(ResultSet)cs.getObject(6);

      

       System.out.println(”記錄數是:”+rnum+” 總頁數是:”+pnum);

       while(rs.next()){

           System.out.println(”編號:”+rs.getInt(1)+”姓名:”+rs.getString(2));

       }

       }catch(Exception e){

            e.printStackTrace();

       }finally{

           //關閉資源

           cs.close();

           ct.close();

}

    }

}

 

例外處理

例外處理分為預定義例外,其他預定義例外和自定義例外。

案例:當輸入的僱員編號不存在時

declare

v_ename emp.ename%type;

begin

select ename into v_name from emp where empno=&no;

dbms_output.putline(’名字是:’||v_name);

exception

when no_data_found then

dbms_output.putline(’編號不存在!’);

end;

 

no_data_found就是一個預定義例外,在執行select語句時會出異常,但在執行update等語句時不會觸發該例外。

 

預定義例外是由pl/sql所提供的系統例外。當pl/sql違反Oracle的規定時就會隱含觸發一個內部例外。

常用的例外:

  1. case_no_found 當編寫pl/sql塊中編寫case語句時,如果在when子句中沒有包含必須的條件分支,就會觸發case_no_found例外。

例:create or replace procedure xxc_pro7(no number) is

    v_sal emp.sal%type;

    begin

    select sal into v_sal from emp where empno=no;

    case

    when v_sal<1000 then

       update emp set sal=sal+200 where empno=no;

    when 1000<=v_sal<2000 then

       update emp set sal=sal+300 where empno=no;

    end case;

    exception

when case_no_found then

    dbms_output.putline(’case中沒有和’||v_sal||’相匹配的條件’);

end;

  1. 2.       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.putline(emp_cursor.ename);

end loop;

exception

when cursor_already_open then

dbms_output.putline(’遊標已開啟!’);

end;

3.dup_val_on_index例外

    在唯一索引所對應的列上插入重複的值時,會隱含的觸發此例外。

    begin

    insert into dept values(10,’公關部’,’北京’);

    exception

    when dup_val_on_index then

    dbms_output.putline(’在deptno列上不能有重複值!’);

end;

4.invaild_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.putline(emp_cursor.ename);

    close emp_cursor;

    exception

    when invalid_cursor then

    dbms_output.putline(’請檢查遊標是否開啟’);

    end;

5.invalid_number例外

當輸入的資料有誤時,會觸發該例外。比如把100寫成1oo就會觸發。

    begin

    update emp set sal=sal+’1oo’;

    exception

    when invalid_number then

    dbms_output.putline(’輸入的數字不正確!’);

    end;

6.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.putline(’返回了多行!’);

    end;

7.zero_divide例外    2/0,即0做分母的時候觸發。

8.value_error例外

當在執行賦值操作時,如果變數的長度不足以容納實際資料,就會觸發該例外。

    declare

    v_ename varchar2(5);

begin

    select ename into v_ename from emp where empno=&no;

    dbms_output.putline(’名字是:’||v_ename);

    exception

    when value_error then

    dbms_output.putline(’資料超出變數長度!’);

    end;

其他預定義例外。

  1. login_denide  當使用者非法登入時,會觸發該例外。
  2. not_logged_on  如果使用者沒有登入就執行dml操作,就會觸發。
  3. storage_error  如果超過了記憶體空間或記憶體被破壞,就會觸發。
  4. timeout_on_resoure  如果oracle在等待資源是出現了超時,觸發。

自定義例外

預定義例外是和oracle的錯誤相關的,而自定義例外於oracle錯誤沒有任何關係,它是由開發人員為特定的情況所定義的例外。

例:編寫一個pl/sql塊,接收一個僱員號,並給該僱員的工資增加1000元,如果該僱員不存在,請提示。

create or replace procedure test_ex(no number) is

declare

myex exception; --定義一個例外

begin

update emp set sal=sal+1000 where empno=no;

if sql%notfound then  -- sql%notfound表示沒有更新資料

raise myex;   --觸發myex

end if;

exception

when myex then

dbms_output.putline(’未更新成功!’);

end;

檢視

檢視與表的區別

  1. 表需要佔用磁碟空間,檢視不需要;
  2. 檢視不能新增索引;
  3. 使用檢視可以簡化複雜查詢;
  4. 檢視可以提高安全性

建立檢視

create view 檢視名 as select語句 [with read only];

例:建立檢視,把emp表的sal<1000的僱員對映到該檢視;

create view myview as select * from emp where sal<1000;

為簡化操作,用檢視顯示員工編號,姓名和所在部門

create view myview2 as select emp.empno,emp.ename,dept.dname from emp,dept where emp.deptno=dept.deptno;

建立或修改檢視

create or replace view 檢視名 as select語句 [with read only];

刪除檢視

drop view 檢視名;


 [A1]

呼叫過程,必須這麼寫

begin

   xxc_pro3('SCOTT',2900);

end;

 [A2]

類似Java的Interface介面

 [A3]報錯

 [A4]如何定義變數

 [A5]相當於Java的POJO

實體類

 [A6]相當於Java的陣列

 [A7]遊標就是C的指標

這裡面用的迴圈,相當於while迴圈

 [A8]展示了迴圈集合,然後修改集合物件的屬性

 [A9]Java中的break

相關文章