ORACLE存儲過程和常用函數

注: 本篇筆記大部分示例來自網上資料及其他博客。 
目前很多互聯網項目,都把複雜的業務操作寫到了存儲過程裏,加快執行速度,提高效率。所以學習存儲過程也是必要的。

簡單入門例子

示例1

/*不帶任何參數存儲過程(輸出系統日期)*/
create or replace procedure output_date is
begin
dbms_output.put_line(sysdate);
end output_date;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

示例2

/*帶參數in和out的存儲過程*/
create or replace procedure get_username(userid in  varchar2, username out varchar2) is
begin
  select user_name into username  from sm_user where cuserid = userid;
  exception
  when no_data_found then 
   raise_application_error(-20001,'ID不存在!');
end get_username;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

關於 遊標 if,for 的例子

create or replace procedure peace_if is
cursor var_c is select * from sm_user;
begin
  for temp in var_c loop 
   if temp.user_name = '房瑩瑩' then dbms_output.put_line('用戶名:'|| temp.user_name || '是壞人。');
   elsif temp.user_name = '臧金紅' then dbms_output.put_line('用戶名:'|| temp.user_name || '是良民。');
   else dbms_output.put_line('用戶名:'|| temp.user_name || '不是人。');
   end if;
  end loop;

end peace_if;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

關於遊標 for,case 的例子

create or replace procedure  peace_case1(ptr  out varchar2,pintr in varchar2) is
cursor cur is select user_name from sm_user where cuserid= pintr ;

begin
  for temp in cur loop
    case temp.user_name 
    when '房瑩瑩' then ptr := temp.user_name ;
    when '臧金紅' then ptr := temp.user_name ;
    else ptr := 'qita';
    end case;
  end loop;

end ;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

關於for 循環的例子

create or replace procedure peace_for is
sum1 number := 0;
temp varchar2(500);

begin

for i in 1..9 loop 
   temp :='';
   for j in 1..9 loop 
     sum1 := j * j;
     temp := temp||to_char(i) || ' * ' ||to_char(j) ||' = ' ||to_char(sum1) ||' '; 
   end loop;
   dbms_output.put_line(temp );
end loop;
end peace_for;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

關於遊標和loop循環的例子

create or replace procedure peace_loop is
sum1 number :=0;
temp number :=0;

begin
  loop
    exit when  temp >= 10;
    sum1 := sum1 + temp;
    temp := temp + 1;
  end loop;
  dbms_output.put_line(sum1);
end peace_loop;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
create or replace procedure loop_cur is
user_name varchar2(100);
cursor var_cur is select user_name from sm_user;
begin
  open var_cur;
       loop fetch var_cur into user_name;
       exit when var_cur%notfound;
       dbms_output.put_line(user_name);
       end loop;
  close var_cur;
end loop_cur;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

關於異常處理的例子

示例1create or replace procedure peace_exp(in1 in varchar2) is
c_n varchar2(200);
begin
  select  user_name into c_n from sm_user where user_name= in1 ;
  dbms_output.put_line(c_n); 
  exception
    when no_data_found then dbms_output.put_line('try');
    when TOO_MANY_ROWS then dbms_output.put_line('more');

end peace_exp;

示例2create or replace procedure peace_insert(c_n in varchar2) is
error exception;
begin
  if c_n = 'ok' then insert into sm_user(cuserid,user_name) values(sys_guid(),c_n);
  elsif c_n = 'nk' then  insert into sm_user(cuserid,user_name) values(sys_guid(),c_n);
  raise error;
  else 
  Dbms_Output.put_line('c_n' || c_n); 
  end if;
  commit;
  exception
  when error then rollback;
  Dbms_Output.put_line('ERRO'); 

end;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

關於包的例子 定義包體

create or replace package body peace_pkg 
as 
function test1(in1 in varchar2) 
return number 
as 
temp number; 
begin 
temp := 0; 
return temp; 
end; 
procedure test2 (in2 in varchar2) 
is 
begin 
dbms_output.put_line(in2); 
end; 


end peace_pkg; 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

oracle 常用函數

字符函數

字符函數是oracle中最常用的函數,我們來看看有哪些字符函數: 
lower(char):將字符串轉化爲小寫的格式。 
upper(char):將字符串轉化爲大寫的格式。 
length(char):返回字符串的長度。 
substr(char, m, n):截取字符串的子串,n代表取n個字符的意思,不是代表取到第n個 
replace(char1, search_string, replace_string) 
instr(C1,C2,I,J) –>判斷某字符或字符串是否存在,存在返回出現的位置的索引,否則返回小於1;在一個字符串中搜索指定的字符,返回發現指定的字符的位置; 
C1 被搜索的字符串 
C2 希望搜索的字符串 
I 搜索的開始位置,默認爲1 
J 出現的位置,默認爲1 
問題:將所有員工的名字按小寫的方式顯示 
SQL> select lower(ename) from emp; 
問題:將所有員工的名字按大寫的方式顯示。 
SQL> select upper(ename) from emp; 
問題:顯示正好爲5個字符的員工的姓名。 
SQL> select * from emp where length(ename)=5; 
問題:顯示所有員工姓名的前三個字符。 
SQL> select substr(ename, 1, 3) from emp; 
問題:以首字母大寫,後面小寫的方式顯示所有員工的姓名。 
SQL> select upper(substr(ename,1,1)) || lower(substr(ename,2,length(ename)-1)) from emp; 
問題:以首字母小寫,後面大寫的方式顯示所有員工的姓名。 
SQL> select lower(substr(ename,1,1)) || upper(substr(ename,2,length(ename)-1)) from emp; 
問題:顯示所有員工的姓名,用“我是老虎”替換所有“A” 
SQL> select replace(ename,’A’, ‘我是老虎’) from emp; 
問題:instr(char1,char2,[,n[,m]])用法 
SQL> select instr(‘azhangsanbcd’, ‘zhangsan’) from dual; –返回2 
SQL> select instr(‘oracle traning’, ‘ra’, 1, 1) instring from dual; –返回2 
SQL> select instr(‘oracle traning’, ‘ra’, 1, 2) instring from dual; –返回9 
SQL> select instr(‘oracle traning’, ‘ra’, 1, 3) instring from dual; –返回0,根據條件,由於ra只出現二次,第四個參數3,就是說第3次出現ra的位置,顯然第3次是沒有再出現了,所以結果返回0。注意空格也算一個字符 
SQL> select instr(‘abc’,’d’) from dual; –返回0

數學函數

數學函數的輸入參數和返回值的數據類型都是數字類型的。數學函數包括cos,cosh,exp,ln, log,sin,sinh,sqrt,tan,tanh,acos,asin,atan,round等 
我們講最常用的: 
round(n,[m]) 該函數用於執行四捨五入, 
如果省掉m,則四捨五入到整數。 
如果m是正數,則四捨五入到小數點的m位後。 
如果m是負數,則四捨五入到小數點的m位前。 
eg、SELECT round(23.75123) FROM dual; –返回24 
SELECT round(23.75123, -1) FROM dual; –返回20 
SELECT round(27.75123, -1) FROM dual; –返回30 
SELECT round(23.75123, -3) FROM dual; –返回0 
SELECT round(23.75123, 1) FROM dual; –返回23.8 
SELECT round(23.75123, 2) FROM dual; –返回23.75 
SELECT round(23.75123, 3) FROM dual; –返回23.751 
trunc(n,[m]) 該函數用於截取數字。 
如果省掉m,就截去小數部分, 
如果m是正數就截取到小數點的m位後, 
如果m是負數,則截取到小數點的前m位。 
eg、SELECT trunc(23.75123) FROM dual; –返回23 
SELECT trunc(23.75123, -1) FROM dual; –返回20 
SELECT trunc(27.75123, -1) FROM dual; –返回20 
SELECT trunc(23.75123, -3) FROM dual; –返回0 
SELECT trunc(23.75123, 1) FROM dual; –返回23.7 
SELECT trunc(23.75123, 2) FROM dual; –返回23.75 
SELECT trunc(23.75123, 3) FROM dual; –返回23.751 
mod(m,n)取餘函數 
eg、select mod(10,2) from dual; –返回0 
SELECT MOD(10,3) FROM dual; –返回1 
floor(n) 返回小於或是等於n的最大整數 
ceil(n) 返回大於或是等於n的最小整數 
eg、SELECT ceil(24.56) from dual; –返回25 
SELECT floor(24.56) from dual; –返回24 
abs(n) 返回數字n的絕對值 
對數字的處理,在財務系統或銀行系統中用的最多,不同的處理方法,對財務報表有不同的結果

日期函數

日期函數用於處理date類型的數據。默認情況下日期格式是dd-mon-yy 即“12-7 月-12” 
(1)sysdate 返回系統時間 
eg、SQL> select sysdate from dual; 
(2)oracle add_months函數 
oracle add_months(time,months)函數可以得到某一時間之前或之後n個月的時間 
eg、select add_months(sysdate,-6) from dual; –該查詢的結果是當前時間半年前的時間 
select add_months(sysdate,6) from dual; –該查詢的結果是當前時間半年後的時間 
(3)last_day(d):返回指定日期所在月份的最後一天 
問題:查找已經入職8個月多的員工 
SQL> select * from emp where sysdate>=add_months(hiredate,8); 
問題:顯示滿10年服務年限的員工的姓名和受僱日期。 
SQL> select ename, hiredate from emp where sysdate>=add_months(hiredate,12*10); 
問題:對於每個員工,顯示其加入公司的天數。 
SQL> select floor(sysdate-hiredate) “入職天數”,ename from emp; 
或者 
SQL> select trunc(sysdate-hiredate) “入職天數”,ename from emp; 
問題:找出各月倒數第3天受僱的所有員工。 
SQL> select hiredate,ename from emp where last_day(hiredate)-2=hiredate;

轉換函數

轉換函數用於將數據類型從一種轉爲另外一種。在某些情況下,oracle server允許值的數據類型和實際的不一樣,這時oracle server會隱含的轉化數據類型 
比如: 
create table t1(id int); 
insert into t1 values(‘10’);–這樣oracle會自動的將’10’ –>10 
create table t2 (id varchar2(10)); 
insert into t2 values(1); –這樣oracle就會自動的將1 –>’1’; 
我們要說的是儘管oracle可以進行隱含的數據類型的轉換,但是它並不適應所有的情況,爲了提高程序的可靠性,我們應該使用轉換函數進行轉換。 
to_char()函數 
你可以使用select ename, hiredate, sal from emp where deptno = 10;顯示信息,可是,在某些情況下,這個並不能滿足你的需求。 
問題:日期是否可以顯示 時/分/秒 
SQL> select ename, to_char(hiredate, ‘yyyy-mm-dd hh24:mi:ss’) from emp; 
問題:薪水是否可以顯示指定的貨幣符號 
SQL> 
yy:兩位數字的年份 2004–>04 
yyyy:四位數字的年份 2004年 
mm:兩位數字的月份 8 月–>08 
dd:兩位數字的天 30 號–>30 
hh24: 8點–>20 
hh12:8點–>08 
mi、ss–>顯示分鐘\秒 
9:顯示數字,並忽略前面0 
0:顯示數字,如位數不足,則用0補齊 
.:在指定位置顯示小數點 
,:在指定位置顯示逗號 
$:在數字前加美元 
L:在數字前面加本地貨幣符號 
C:在數字前面加國際貨幣符號 
G:在指定位置顯示組分隔符、 
D:在指定位置顯示小數點符號(.) 
問題:顯示薪水的時候,把本地貨幣單位加在前面 
SQL> select ename, to_char(hiredate, ‘yyyy-mm-dd hh24:mi:ss’), to_char(sal,’L99999.99’) from emp; 
問題:顯示1980年入職的所有員工 
SQL> select * from emp where to_char(hiredate, ‘yyyy’)=1980; 
問題:顯示所有12月份入職的員工 
SQL> select * from emp where to_char(hiredate, ‘mm’)=12;

to_date()函數 
函數to_date用於將字符串轉換成date類型的數據。 
問題:能否按照中國人習慣的方式年—月—日添加日期。 
eg、SELECT to_date(‘2012-02-18 09:25:30’,’yyyy-mm-dd hh24:mi:ss’) FROM dual;

sys_context()系統函數

1)terminal:當前會話客戶所對應的終端的標示符,如計算機名 
2)language: 語言 
3)db_name: 當前數據庫名稱 
4)nls_date_format: 當前會話客戶所對應的日期格式 
5)session_user: 當前會話客戶所對應的數據庫用戶名 
6)current_schema: 當前會話客戶所對應的默認方案名 
7)host: 返回數據庫所在主機的名稱 
通過該函數,可以查詢一些重要信息,比如你正在使用哪個數據庫? 
select sys_context(‘USERENV’,’db_name’) from dual; 
注意:USERENV是固定的,不能改的,db_name可以換成其它, 
eg、select sys_context(‘USERENV’,’language’) from dual; 
select sys_context(‘USERENV’,’current_schema’) from dual;

查看oracle版本: SELECT * from v$version

trunc函數

1、TRUNC(for dates) TRUNC函數爲指定元素而截去的日期值。 
  其具體的語法格式如下: TRUNC(date[,fmt]) 
  其中:date一個日期值,fmt日期格式,該日期將由指定的元素格式所截去。忽略它則由最近的日期截去 
下面是該函數的使用情況: 
select trunc(to_date(‘2012-03-23 23:59:59’,’yyyy-mm-dd hh24:mi:ss’)) from dual – return date : 2012-3-23 
  trunc(sysdate,’yyyy’) –返回當年第一天. 
  trunc(sysdate,’mm’) –返回當月第一天. 
trunc(sysdate,’d’) –返回當前星期的第一天.

2、TRUNC(for number) 
  TRUNC函數返回處理後的數值,其工作機制與ROUND函數極爲類似,只是該函數不對指定小數前或後的部分做相應舍入選擇處理,而統統截去。 
  其具體的語法格式如下TRUNC(number[,decimals]) 
  其中:number待做截取處理的數值,decimals指明需保留小數點後面的位數。可選項,忽略它則截去所有的小數部分 
  下面是該函數的使用情況: 
  TRUNC(89.985,2)=89.98 
  TRUNC(89.985)=89 
  TRUNC(89.985,-1)=80 
  注意:第二個參數可以爲負數,表示爲小數點左邊指定位數後面的部分截去,即均以0記。與取整類似,比如參數爲1即取整到十分位,如果是-1,則是取整到十位,以此類推;如果所設置的參數爲負數,且負數的位數大於整數的字節數的話,則返回爲0。如:TRUNC(89.985,-3)=0.

to_char() ,to_date (),TO_NUMBER()

to char是把日期或數字轉換爲字符串;to date是把字符串轉換爲數據庫中得日期類型 
TO_CHAR 
使用TO_CHAR函數處理數字:TO_CHAR(number, ‘格式’);TO_CHAR(salary,’$99,999.99’); 
使用TO_CHAR函數處理日期: TO_CHAR(date,’格式’); 
select to_number(to_char(sysdate,’yyyy’)) from dual –取年 
select to_number(to_char(sysdate,’mm’)) from dual –取月 
select to_number(to_char(sysdate,’dd’)) from dual –取日 
TO_NUMBER 
使用TO_NUMBER函數將字符轉換爲數字:TO_NUMBER(char[, ‘格式’])

TO_DATE 
使用TO_DATE函數將字符轉換爲日期:TO_DATE(char[, ‘格式’]) 
select to_date(‘2011-11-5 4:39:57’,’yyyy-mm-dd hh24:mi ss’) as col from dual 
各種格式:

這裏寫圖片描述

INSTR,SUBSTR函數

INSTR方法的格式爲:INSTR(源字符串,目標字符串,起始位置,匹配序號) 
例如:INSTR(‘CORPORATE FLOOR’,’OR’, 3, 2)中,源字符串爲’CORPORATE FLOOR’,目標字符串爲’OR’,起始位置爲3,取第2個匹配項的位置。 
默認查找順序爲從左到右。當起始位置爲負數的時候,從右邊開始查找。 
所以SELECT INSTR(‘CORPORATE FLOOR’, ‘OR’, -1, 1) “Instring” FROM DUAL的顯示結果是:14

substr函數的用法 
取得字符串中指定起始位置和長度的字符串substr( string, start_position, [ length ] ) 
如: 
substr(‘This is a test’, 6, 2) return ‘is’ 
substr(‘This is a test’, 6) return ‘is a test’ 
substr(‘TechOnTheNet’, -3, 3) return ‘Net’ 
substr(‘TechOnTheNet’, -6, 3) return ‘The’ 
select substr(‘Thisisatest’, -4, 2) value from dual 
舉個例子更容易區分這兩個函數: 
select substr(‘張三:一班:男’,instr(‘張三:一班:男’,’:’,1,1)+1,2) as 班級, instr(‘張三:一班:男’,’:’,1,1)+1 開始位置 from dual 
結果是:班級 開始位置 
一班 4

translate與replace

1.translate 
語法:TRANSLATE(char, from, to) 
用法:返回將出現在from中的每個字符替換爲to中的相應字符以後的字符串。 
若from比to字符串長,那麼在from中比to中多出的字符將會被刪除。 
三個參數中有一個是空,返回值也將是空值。 
舉例:SQL> select translate(‘abcdefga’,’abc’,’wo’)返回值from dual; 
返回值——- wodefgw 
分析:該語句要將’abcdefga’中的’abc’轉換爲’wo’, 
由於’abc’中’a’對應’wo’中的’w’,故將’abcdefga’中的’a’全部轉換成’w’; 
而’abc’中’b’對應’wo’中的’o’,故將’abcdefga’中的’b’全部轉換成’o’; 
而’abc’中的’c’在’wo’中沒有與之對應的字符,故將’abcdefga’中的’c’全部刪除; 
簡單說來,就是將from中的字符轉換爲to中與之位置對應的字符,若to中找不到與之對應的字符,返回值中的該字符將會被刪除。 
在實際的業務中,可以用來刪除一些異常數據,比如表a中的一個字段t_no表示電話號碼,而電話號碼本身應該是一個由數字組成的字符串, 
爲了刪除那些含有非數字的異常數據,就用到了translate函數: 
SQL> delete from a, where length(translate(trim(a.t_no), ‘0123456789’ || a.t_no, ‘0123456789’)) <> length(trim(a.t_no)); 
2.replace 
語法:REPLACE(char, search_string,replacement_string) 
用法:將char中的字符串search_string全部轉換爲字符串replacement_string,沒有匹配的字符串就都不變。 
舉例: 
SQL> select REPLACE(‘fgsgswsgs’, ‘fk’ ,’j’) from dual;返回值from dual; 
結果是fgsgswsgs 
SQL> select REPLACE(‘fgsgswsgs’, ‘sg’ ,’eeerrrttt’)返回值from dual; 
結果是fgeeerrrtttsweeerrrttts 
分析:第一個例子中由於’fgsgswsgs’中沒有與’fk’匹配的字符串,故返回值仍然是’fgsgswsgs’; 
第二個例子中將’fgsgswsgs’中的字符串’sg’全部轉換爲’eeerrrttt’。 
總結:綜上所述,replace與translate都是替代函數,只不過replace針對的是字符串,而translate針對的是單個字符。

Decode()函數

DECODE函數,它將輸入數值與函數中的參數列表相比較,根據輸入值返回一個對應值。函數的參數列表是由若干數值及其對應結果值組成的若干序偶形式。當然,如果未能與任何一個實參序偶匹配成功,則函數也有默認的返回值。 
區別於SQL的其它函數,DECODE函數還能識別和操作空值。 
語法:DECODE(control_value,value1,result1[,value2,result2…][,default_result]); 
試圖處理的數值。DECODE函數將該數值與後面的一系列的偶序相比較,以決定返回值。 
value1 是一組成序偶的數值。如果輸入數值與之匹配成功,則相應的結果將被返回。對應一個空的返回值,可以使用關鍵字NULL於之對應。 
result1 是一組成序偶的結果值。 
default_result 未能與任何一個值匹配時,函數返回的默認值。 
例如: 
Select decode( x , 1 , ‘x is 1 ’, 2 , ‘x is 2 ’, ‘others’) from dual 
當x等於1時,則返回‘x is 1’。 
當x等於2時,則返回‘x is 2’。 
否則,返回others’。 
需要,比較2個值的時候,可以配合SIGN()函數一起使用。 
SELECT DECODE( SIGN(5 -6), 1 ‘Is Positive’, -1, ‘Is Nagative’, ‘Is Zero’)from dual; 
同樣,也可以用CASE實現: 
SELECT CASE SIGN(5 - 6) 
WHEN 1 THEN ‘Is Positive’ 
WHEN -1 THEN ‘Is Nagative’ 
ELSE ‘Is Zero’ END 
FROM DUAL 
此外,還可以在Order by中使用Decode。 
例如:表subject,有subject_name列。要求按照:語、數、外的順序進行排序。這時,就可以非常輕鬆的使用Decode完成要求了。 
select * from subject order by decode(subject_name, ‘語文’,1, ‘數學’,2, ‘外語’,3)

SQL SERVER : 
SELECT a, 
CASE WHEN a=1THEN ‘one’ 
WHEN a=2THEN ‘two’ 
ELSE ‘other’ 
END AS COL 
FROM test;

a | COL 
—+——- 
1 | one 
2 | two 
3 | other 
1 SELECT TOP 3 id, CASE WHEN id=1 THEN ‘one’ WHEN id=2 THEN ‘two’ELSE ‘other’ END as idName FROM users; 
2 SELECT TOP 3 id, CASE ID WHEN 1 THEN ‘one’ WHEN 2 THEN ‘two’ELSE ‘other’ END as idName FROM users; 
1,2 結果一樣 
(此處實用oracle與SQL Server一樣)

NVL函數

nvl( ) 函數(類似於SQLSERVER的isnull) 
語法: 1. NVL(eExpression1, eExpression2) 
參數: 1. eExpression1, eExpression2 
如果eExpression1的計算結果爲null值,則NVL( )返回eExpression2。 
如果eExpression1的計算結果不是null值,則返回eExpression1。 
eExpression1和eExpression2可以是任意一種數據類型。 
如果eExpression1與eExpression2的結果皆爲null值,則NVL( )返回.NULL.。 
1. select nvl(a.name,’空得’) as name from student a join school b on a.ID=b.ID 
注意:兩個參數得類型要匹配

wm_concat函數

wmsys.wm_concat(column)將多條記錄組成一個用逗號隔開的字符串。 
select wmsys.wm_concat(id) aa from tbl 
類似於SQL server的語句:SELECT @temp=@temp + ‘,’ + id from tbl order by id

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章