注: 本篇筆記大部分示例來自網上資料及其他博客。
目前很多互聯網項目,都把複雜的業務操作寫到了存儲過程裏,加快執行速度,提高效率。所以學習存儲過程也是必要的。
簡單入門例子
示例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
關於異常處理的例子
示例1:
create 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;
示例2:
create 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