1. 程式人生 > >oracle學習儲存過程

oracle學習儲存過程

1, create or replace procedure  sp_pro is

begin 

insert   into  mytest values('123','wangwu');

end;;

 

檢視錯誤: show error;

執行: /

2,呼叫;

exec  過程名(引數,引數);

call  過程名(引數,引數,....);

 

3,塊(程式設計)-->過程,函式,包,觸發器

命名規範: 變數v_字首v_sal ,  常量c_字首c_rate;  遊標_cursor字尾emp_cursor; 異常e_字首e_error;

declear 定義常量、變數、遊標、例外異常、複雜資料型別,

 begin執行sql語句, exception 異常處理, end;

set serveroutput  on --開啟輸出選項;

declare --定義變數

v_ename varchar2(5);

v_sal  number(7,2);

begin

        select ename,sal  into v_ename, v_sal from emp where empno=&no; --將查詢出來的ename放入到引數v_ename中,&表示從控制檯接受輸入的變數; 引數順序要一致

        dbms_output.put_line('僱員名:'||v_ename); --控制檯輸出

        dbms_output.put_line('hello');

exception --異常處理

when no_data_found then

        dbms_output.put_line('資料輸入錯誤');

end;

4,異常例外: no_data_found 資料不存在

create procedure sp_pro3(spName varchar2,  newSal  number) is  ---引數只指定型別不指定大小

begin

update  emp set sal=newSal   where ename=spName; --根據使用者名稱修改工資

end;

exec sp_pro3('scott', 4678); --呼叫過程

 

java呼叫:

CallableStatement  cs=conn.prepareCall("{call  sp_pro3(?,?)}");

cs.setString(1,"Tom");//給? 賦值

cs.setInt(2,1000);

cs.execute(); //執行

 

java呼叫有返回值的儲存過程:

CallableStatement  cs=conn.prepareCall("{call  sp_pro8(?,?)}");//第一個引數是入引數,第二個是出引數

cs.setString(1,"Tom");//給第一個? 賦值

//給第二個?賦值

cs.registerOutParameter(2,oracle.jdbc.oracleTypes.VARCHAR); //過程的第二個引數為輸出引數,型別要一致

cs.execute(); //執行

//取出返回值,要注意?順序

String  name=cs.getString(2);  //得到過程的返回值

 

 

 

5 建立函式:

crete function sp_fun2(spName varchar2) --引數不定義大小

 return number is  yearSal number(7,2);

begin

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

return yearSal;

end;

函式呼叫:

var  abc  number;

call  sp_fun2('scott') into :abc; 

print abc

java程式中呼叫函式:

select  sp_fun('scott')  from dual;//通過rs.get(1)得到返回的結果。

 

6 包: 用於邏輯上組合過程和函式,它有包規範和包體兩部分組成;

create package  sp_package is

        procedure  update_sal(name varchar2, newsal  number);

        function  annual_income(name  varchar2) return number;

end;

包規範只包含了過程和函式的說明,但是沒有過程和函式的實現程式碼。包體用於實現包規範中的過程和函式。

建立包體: create package  body  sp_package is 

procedure update_sal(name varchar2, newsal  number)

is

begin

update emp set sal=newsal where ename=name;

end;

 

function  annual_income(name varchar2)

return  unmber  is

annual_salary  number;

begin

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

return  annual_salary;

end;

end;

 

呼叫執行: call  sp_package.update_sal('tom',120);

 

7 定義變數:

1),定義一個變長字串 v_ename   varchar2(10);

2), 定義一個小數範圍 -9999.99 ~ 9999.99

 v_sal  number(6.2);

3),定義一個小數並初始值為5.4 ,:=是賦值號

v_sal2  number:=5.4;

4) 定義一個日期型別的資料

v_brithdate  date;

5) 定義一個布林變數,不能為空,初始值為false

v_valid  boolean  not  null  default false;

 

8,複合變數:記錄型別,表型別

declare

type emp_record is record( name emp.ename%type, sal emp.sal%type); --定義一個記錄型別

sp_record  emp_record; --定義一個記錄變數

begin

select ename,sal into sp_record  from emp where empno=7788; --賦值

dbms_output.put_line('員工名: '|| sp_record.name); --獲取

end;

 

------------表型別相當於陣列------------------------

declare 

type sp_table_type  is table of emp.ename%type  index by binary_integer; --下標為整數可以為負數

sp_table  sp_table_type;  --定義一個表型別的變數

begin

select ename intosp_table(0) from emp where  empno=7788;  --賦值,下標為0,只能接受一行的記錄

dbms_output.put_line('員工名: '||sp_table(0)); --獲取

end;

 

9,參照表裡:遊標cursor

declare 

type sp_emp_cursor is ref cursor; --定義一個遊標型別

sp_cursor  sp_emp_cursor; --定義一個遊標變數

v_ename emp.ename%type;

v_sal  emp.sal%type;

begin

open sp_currsor  for  select   ename,sal  from emp where deptno=10; --遊標與一個select結合

loop

fetch  sp_currsor into v_ename,v_sal;--從遊標獲取資料賦值給變數

exit  when sp_curror%notfound; --判斷是否為空

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

end  loop;

end;

帶引數的遊標:

declare

  cursor  c_emp(p_deptno  employees.department_id%type)is 

  select *  from  hr.employees where department_id=p_deptno;

  v_emp c_emp%ROWTYPE;

begin

  open c_emp(10);

loop

fetch   c_emp  into  v_emp;

exit when c_emp%NOTFOUND;

DBMS_OUTPUT.PUT_LINE(v_emp.employ_id||v_emp.last_name);

end  loop;

close  .c_emp;

10, 返回結果集的儲存過程

--1,建立一個包,在該包中,定義型別test_sursor, 是個遊標

create  or  replace  package  testpackage  as

type  test_cursor   is  ref  cursor;

end  tespackage;

--2 建立過程

create  or  replace  procedure  sp_pro9(spNo  in  number, p_cursor  out  tespackage.test_cursor)

is

begin

open  p_cursor  for  select  * from emp  where deptno =spno;

end;

 

java呼叫返回的是結果集:

CallableStatement  cs=conn.prepareCall("{call  sp_pro9(?,?)}");//第一個引數是入引數,第二個是遊標出引數

cs.setString(1,10);//給第一個? 賦值

//給第二個?賦值

cs.registerOutParameter(2,oracle.jdbc.oracleTypes.CURSOR); //過程的第二個引數為遊標輸出引數,型別要一致

cs.execute(); //執行

ResultSet   rs=(ResultSet)cs.getobject(2); //得到結果集

while(rs.next()){

        syso(rs.getInt(1)+' '+rs.getString(2)  ); //迭代取出資料,第一列和第二列

}

 

10,if控制

if v_job='pro'  then

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

elsif  v_job='MAN'  then 

update emp set sal=sal+500  where empno=spNo;

else

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

end if;

 

觸發器:create trigger 

 

11.迴圈:

方式一:

loop

insert into  users  values(v_num, spname);

exit  when  v_num=10;--判斷是否退出迴圈,符合條件退出

end loop;

方式二:

while v_num<=20  loop --符合條件才執行

insert into  users  values(v_num, spname);

v_num:=v_num+1;

end  loop;

方式三:

for  i  in   1..10 loop

insert into  users  values(v_num, spname);

end loop;

 

12, goto語句

declare

i  int :=-1;

begin

    loop

    dbms_output.put_line('輸出i='||i);

    if i=10 then

    goto  end_loop;  --跳轉到特定標號處

    end if;

    i:=i+1;

    end  loop;

<<end_loop>>

dbms_output.put_line('迴圈結束');

end;

 

13, null語句不會執行任何操作,

 

14,分頁演算法

--1,建立一個包,在該包中,定義型別test_sursor, 是個遊標

create  or  replace  package  testpackage  as

type  test_cursor   is  ref  cursor;

end  tespackage;

--2 建立過程

create  or  replace  procedure  fenye (

tableName  in varchar2, --表名

 pagesize  in number,  --每頁顯示記錄數

  pageNow  in number,  --顯示第幾頁

 myrows  out  number, --總記錄數

mypagecount   out  number,總頁數

p_cursor  out  testpackage.test_cursor --返回的結果集

) is

---定義變數

v_sql  varchar2(1000);

v_begin  number:=(pageNow-1)*pagesize+1; --計算顯示頁的第一條記錄

v_end  number:=pageNow*pagesize; --計算顯示頁的第二條記錄

begin

v_sql:='select * from (select t.* , rownum  rn  from(select  * from '|| tableName||') t  where  rownum<='|| v_end||' ) where  rn >='||v_begin;

open p_cursor   for v_sql;

v_sql:='select  count(*) from '||tablesName;

execute  immediate  v_sql  into  myrows;  --表的總記錄數

if  mod(myrows, pagesize)=0  then --計算總頁數

mypageCount   := myrows/Pagesize;

else

myPageCount :=myrows/Pagesize+1;

end if;

close  p_cursor; --關閉遊標

end;

 

15,case語句

create or replace procedure  sp_pro6(spno  number) is

v_sal   emp.sal%type;

begin

select sal  into v_sal  from emp where  empno=spno;

case

when v_sal <1000  then 

update emp set sal=sal+100  where empno=spno;

when  v_sal <2000  then

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

end  case;

exception

when case_not_found  then

dbms_output.put_line('case沒有相匹配的');

end;

 

 

16例外:

case_not_found  case中沒有相對應的條件

cursor_already_open  遊標已經開啟

dup_val_on_index  唯一索引重複插入inser語句

invaild_cursor  從未開啟的遊標中提取資料,關閉沒有開啟的遊標

invalid_number  輸入的資料有誤比如100輸成LOO

no_data_found  當select中沒有返回行

too_many_rows  當select返回超過了一行,返回了多行

zero_divide  當執行3/0會觸發該例外,分母不能為0

value_error  賦值操作變數的長度不足以容納實際資料

 

自定義例外

create  or replace  procedure   ex_test(spNo number)

is

myex  exception;  --定義一個自定義例外

begin

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

if sql%notfound  then  --這是表示沒有更新成功

raise  myex;   --觸發myex

end  if;

exception

when myex then

dbms_output.put_line('沒有更新任何使用者');

end;

 

呼叫:exec  ex_test(56);

 

17,檢視view

create  or  replace  view  檢視名 as  select 語句 [ with  read  only]只可讀不可改

刪除檢視 : drop  view  檢視名

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

 

18,當語句中包含單引號使用q加分割符號

v_event := q'!Father's day!'; 前面加q其中!為分割符號

v_event :=q'[Mother's day]';  前面加q其中[]為分割符號

v_event :='Father''s day';   雙單引號

 

19:儲存過程迴圈

 

儲存過程for迴圈:

create or replace package body update_payend_status is

procedure updatestatus(mkey varchar2,accountid number)is

v_sumUnits float :=0;

v_flag pglumpsum.flag%type;

v_mkey pglumpsum.mkey%type;

begin

open getPenFlag(mkey);

fetch getPenFlag into v_flag;

close getPenFlag;

open getAllPayendMembers;

loop

fetch getAllPayendMembers into v_mkey,v_accountid;

exit when getAllPayendMembers%NOTFOUND;

addCalc(v_mkey,v_accoutid);

end loop;

close getAllPayendMembers;

end;

END;

 

 

20, -----先建立序列,再建立觸發器

create sequence SEQ_FIXED_TRADEDATE

minvalue 1

maxvalue 9999999

start with 3

increment by 1

nocache;

--建立觸發器

create or replace trigger tg_fixed_Tradedate

before insert on fixed_Tradedate for each row --定義before觸發器,監測表fixed_tradedate的插入操作,行級別的觸發器

when (new.ID is null)

begin

select SEQ_FIXED_TRADEDATE.nextval into:new.ID from dual;

end;

---刪除序列

drop sequence SEQ_FIXED_TRADEDATE;

--建立同義詞

create sysnonym client_54,user for fe.user;

--刪除同義詞

drop sysnonym user;

--授權

grant select ,insert,update,execute on payment_batch_proc to client_54;

--增加對錶空間的許可權

alter user client_54 quota unlimited on users;