1. 程式人生 > >Oracle工作常用函式總結

Oracle工作常用函式總結

一、常用函式詳解

【a】nvl(a,b)函式: 如果a的值為空,那麼取b的值

with temp1 as
 (select '張三' as name, '10' as text from dual),
temp2 as
 (select '' as name, '20' as text from dual),
temp3 as
 (select '李四' as name, '' as text from dual)

--nvl(a,b)函式: 如果a的值為空,那麼取b的值
select nvl(name, '無名氏') as name, nvl(text, '未知') as text
  from temp1
union all
select nvl(name, '無名氏') as name, nvl(text, '未知') as text
  from temp2
union all
select nvl(name, '無名氏') as name, nvl(text, '未知') as text from temp3

【b】nvl2(a,b,c)函式: 如果a的值不為空,那麼取b的值,如果a的值為空,那麼取c的值(類似三目運算子)

with temp1 as
 (select '張三' as name, '10' as text from dual),
temp2 as
 (select '' as name, '20' as text from dual),
temp3 as
 (select '李四' as name, '' as text from dual)

--nvl2(a,b,c)函式: 如果a的值不為空,那麼取b的值,如果a的值為空,那麼取c的值(類似三目運算子)
select nvl2(name, name, '無名氏') as name, nvl2(text, text, '未知') as text
  from temp1
union all
select nvl2(name, name, '無名氏') as name, nvl2(text, text, '未知') as text
  from temp2
union all
select nvl2(name, name, '無名氏') as name, nvl2(text, text, '未知') as text
  from temp3

【c】sign(number) :  如果number大於0,sign則返回1;如果number小於0,sign則返回-1;如果number等於0,sign則返回0.

--sign(number)    如果number大於0,sign則返回1;如果number小於0,sign則返回-1;如果number等於0,sign則返回0
select sign(20 - 10), sign(10 - 20), sign(20 - 20), sign(20.0001 - 20.0000)
  from dual;

【d】substr(str,a,b): 字串擷取函式

--str :待擷取字串 --a :擷取開始位置 --b :擷取個數

注意:當a為負數時,只要 |a| ≤ b,取a的個數(如:7、8、9);當 |a| ≥ b時,才取b的個數

--字元擷取函式substr(str,a,b)
--str 待擷取字串
--a 擷取開始位置
--b 擷取個數

--注意:當a為負數時,只要 |a| ≤ b,取a的個數(如:7、8、9);當 |a| ≥ b時,才取b的個數

select substr('zhangsan', 0, 3),  --zha
       substr('zhangsan', 1, 3),  --zha
       substr('zhangsan', 3, 5),  --angsa
       substr('zhangsan', -1, 3), --n
       substr('zhangsan', -3, 2)  --sa
  from dual;

 

【e】listagg() ..within group() : 合併資料

with temp1 as
 (select '10001' as categoryId, '蘋果' as categoryName from dual),
temp2 as
 (select '10001' as categoryId, '雪梨' as categoryName from dual),
temp3 as
 (select '10002' as categoryId, '鉛筆' as categoryName from dual),
temp4 as
 (select '10003' as categoryId, '水果刀' as categoryName from dual),
temp5 as
 (select '10002' as categoryId, '鋼筆' as categoryName from dual),
allResult as
 (select *
    from temp1
  union all
  select *
    from temp2
  union all
  select *
    from temp3
  union all
  select *
    from temp4
  union all
  select *
    from temp5)

select * from allResult;

假如我們需要將categoryId相同的categoryName合併在一起顯示,那麼可以使用listagg within group函式來實現。

with temp1 as
 (select '10001' as categoryId, '蘋果' as categoryName from dual),
temp2 as
 (select '10001' as categoryId, '雪梨' as categoryName from dual),
temp3 as
 (select '10002' as categoryId, '鉛筆' as categoryName from dual),
temp4 as
 (select '10003' as categoryId, '水果刀' as categoryName from dual),
temp5 as
 (select '10002' as categoryId, '鋼筆' as categoryName from dual),
allResult as
 (select *
    from temp1
  union all
  select *
    from temp2
  union all
  select *
    from temp3
  union all
  select *
    from temp4
  union all
  select *
    from temp5)

select t.categoryId,
       listagg(to_char(t.categoryName), ',') within group(order by t.categoryName) as categoryName
  from allResult t
 group by t.categoryId

【f】型別轉換相關函式: to_char()/to_date()/to_number()

--to_char() 將查詢結果轉換為字元型別

--to_number() 將字串型別轉換為數字型別 --select to_number('zhangsan') from dual;  --無效數字

--to_date() 將字元型資料轉換為日期型資料

--to_char() 將查詢結果轉換為字元型別

--to_number() 將字串型別轉換為數字型別
--select to_number('zhangsan') from dual;  --無效數字

--to_date() 將字元型資料轉換為日期型資料

select to_char(123456) as str,
       to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS') as now,
       to_number('123456') as num,
       to_date('2018-11-09', 'YYYY-MM-DD') as d
  from dual;

【g】extract(fmt from d):提取日期中的特定部分,如年、月、日等

--fmt 為:year、month、day、hour、minute、second。其中 year、month、day可以為 data 型別匹配,也可以與 timestamp 型別匹配;但是 hour、minute、second 必須與 timestamp 型別匹配。 --hour 匹配的結果中沒有加上時區,在中國執行的結果小 8 小時。

--extract(fmt from d),提取日期中的特定部分。
--fmt 為:year、month、day、hour、minute、second。其中 year、month、day可以為 data 型別匹配,也可以與 timestamp 型別匹配;但是 hour、minute、second 必須與 timestamp 型別匹配。
--hour 匹配的結果中沒有加上時區,在中國執行的結果小 8 小時。

select sysdate as now,
       extract(year from sysdate) as 年,
       extract(month from sysdate) as 月,
       extract(day from sysdate) as 天,
       extract(hour from systimestamp) as 小時_小8小時,
       extract(hour from systimestamp) + 8 as 小時,
       extract(minute from systimestamp) as 分鐘,
       extract(second from systimestamp) as 秒
  from dual;

【h】decode(value,if1,then1,if2,then2,if3,then3,...,else) 

(1). 匹配是否相等(當然也可以使用case when 語句實現同樣效果)

with temp1 as
 (select 'female' as sex from dual),
temp2 as
 (select 'male' as sex from dual),
temp3 as
 (select '' as sex from dual),
res as
 (select sex
    from temp1
  union all
  select sex
    from temp2
  union all
  select sex
    from temp3)

--select sex from res;    


--decode(value,if1,then1,if2,then2,if3,then3,...,else) 

--用法一:匹配是否相等(當然也可以使用case when 語句實現同樣效果)

--可以這樣理解:
--如果 sex='female' 返回  '女'
--如果 sex='male' 返回  '男'
--否則,返回'未知'    

select sex as 性別標識,
       decode(sex, 'female', '女', 'male', '男', '未知') as 性別
  from res;

(2). 結合sign用於比較大小 --select decode(sign(變數1-變數2),-1,變數1,變數2) from dual; --取較小值 --sign()函式根據某個值是0、正數還是負數,分別返回0、1、-1

--用法二:結合sign用於比較大小
--select decode(sign(變數1-變數2),-1,變數1,變數2) from dual; --取較小值
--sign()函式根據某個值是0、正數還是負數,分別返回0、1、-1

--取較小值/較大值
select decode(sign(99 - 88), -1, 99, 88) as min, decode(sign(99 - 88), 1, 99, 88) as max from dual;

(3). 示例:成績>85,顯示優秀;>70顯示良好;>60及格;否則是不及格。

--示例:成績>85,顯示優秀;>70顯示良好;>60及格;否則是不及格。
with temp as
 (select '85' as score
    from dual
  union all
  select '80' as score
    from dual
  union all
  select '75' as score
    from dual
  union all
  select '70' as score
    from dual
  union all
  select '60' as score
    from dual
  union all
  select '55' as score
    from dual)

--select score from temp;

--實現方法一:
select score,
       decode(sign(score - 85),
              1,
              '優秀',
              0,
              '優秀',
              -1,
              decode(sign(score - 70),
                     1,
                     '良好',
                     0,
                     '良好',
                     -1,
                     decode(sign(score - 60), 1, '及格', 0, '及格', '不及格'))) as 成績等級
  from temp;

--實現方法二:
with temp as
 (select '85' as score
    from dual
  union all
  select '80' as score
    from dual
  union all
  select '75' as score
    from dual
  union all
  select '70' as score
    from dual
  union all
  select '60' as score
    from dual
  union all
  select '55' as score
    from dual)
select score, 
       case
         when score >= 85 then
          '優秀'
         when score >= 70 then
          '良好'
         when score >= 60 then
          '及格'
         else
          '不及格'
       end as 成績等級
  from temp;


【i】grouping(): 在分組統計時用到,grouping只能在使用rollup或cube的查詢中使用 .

grouping(xxx) 返回0或者1。如果列值為空,那麼grouping()返回1;如果列值非空,那麼返回0。

with temp as
 (select '10001' as depid, '12000' as salary, 'zhangsan' as n, '01' as jid
    from dual
  union all
  select '10001' as depid, '10000' as salary, 'lisi' as n, '02' as jid
    from dual
  union all
  select '10002' as depid, '1000' as salary, 'wangwu' as n, '01' as jid
    from dual
  union all
  select '10002' as depid, '2000' as salary, 'zhaoliu' as n, '03' as jid
    from dual
  union all
  select '10003' as depid, '15000' as salary, 'tianqi' as n, '01' as jid
    from dual
  union all
  select '10003' as depid, '15000' as salary, 'wangba' as n, '02' as jid
    from dual
  union all
  select '10004' as depid, '15000' as salary, 'jiudan' as n, '01' as jid
    from dual)
--select depid,sum(salary) as total from temp group by rollup(depid)

--grouping(xxx) 返回0或者1。如果列值為空,那麼grouping()返回1;如果列值非空,那麼返回0。grouping只能在使用rollup或cube的查詢中使用    

select grouping(depid), depid, sum(salary) as total
  from temp
 group by rollup(depid);

可見,grouping(xxx)當xxx為空的時候返回1,當xxx不為空的時候返回0.

假如我需要最後一行depid為空顯示‘總計’,可以通過下面的方法實現:

with temp as
 (select '10001' as depid, '12000' as salary, 'zhangsan' as n, '01' as jid
    from dual
  union all
  select '10001' as depid, '10000' as salary, 'lisi' as n, '02' as jid
    from dual
  union all
  select '10002' as depid, '1000' as salary, 'wangwu' as n, '01' as jid
    from dual
  union all
  select '10002' as depid, '2000' as salary, 'zhaoliu' as n, '03' as jid
    from dual
  union all
  select '10003' as depid, '15000' as salary, 'tianqi' as n, '01' as jid
    from dual
  union all
  select '10003' as depid, '15000' as salary, 'wangba' as n, '02' as jid
    from dual
  union all
  select '10004' as depid, '15000' as salary, 'jiudan' as n, '01' as jid
    from dual)

--假如我需要最後一行depid為空顯示‘總計’

--可見列值為空返回1,列值不為空返回0 
select decode(grouping(depid), 1, '總計', depid) as depid,
       sum(salary) as total
  from temp
 group by rollup(depid);

另外一種實現方法:

with temp as
 (select '10001' as depid, '12000' as salary, 'zhangsan' as n, '01' as jid
    from dual
  union all
  select '10001' as depid, '10000' as salary, 'lisi' as n, '02' as jid
    from dual
  union all
  select '10002' as depid, '1000' as salary, 'wangwu' as n, '01' as jid
    from dual
  union all
  select '10002' as depid, '2000' as salary, 'zhaoliu' as n, '03' as jid
    from dual
  union all
  select '10003' as depid, '15000' as salary, 'tianqi' as n, '01' as jid
    from dual
  union all
  select '10003' as depid, '15000' as salary, 'wangba' as n, '02' as jid
    from dual
  union all
  select '10004' as depid, '15000' as salary, 'jiudan' as n, '01' as jid
    from dual)

--假如我需要最後一行depid為空顯示‘總計’

--另一種方法:
select nvl(depid, '總計') as depid, sum(salary) as total
  from temp
 group by rollup(depid);
 
 

【j】group by rollup():在分組統計並且需要小計、總結等功能時可以使用group by rollup()實現。--rollup中列的順序不同,則統計的結果不同。因為它是按列從右遞減分組的。 --如 Group by  ROLLUP(A, B, C),首先會對(A、B、C)進行GROUP BY,然後對(A、B)進行GROUP BY,然後是(A)進行GROUP BY,最後對全表進行GROUP BY操作

我們先看看簡單分組之後的結果:

with temp as
 (select '10001' as depid, '12000' as salary, 'zhangsan' as n, '01' as jid
    from dual
  union all
  select '10001' as depid, '10000' as salary, 'lisi' as n, '02' as jid
    from dual
  union all
  select '10002' as depid, '1000' as salary, 'wangwu' as n, '01' as jid
    from dual
  union all
  select '10002' as depid, '2000' as salary, 'zhaoliu' as n, '03' as jid
    from dual
  union all
  select '10003' as depid, '15000' as salary, 'tianqi' as n, '01' as jid
    from dual
  union all
  select '10003' as depid, '15000' as salary, 'wangba' as n, '02' as jid
    from dual
  union all
  select '10004' as depid, '15000' as salary, 'jiudan' as n, '01' as jid
    from dual)
select depid,sum(salary) as total from temp group by depid

然後,加上一個 group by rolluop(depid),

with temp as
 (select '10001' as depid, '12000' as salary, 'zhangsan' as n, '01' as jid
    from dual
  union all
  select '10001' as depid, '10000' as salary, 'lisi' as n, '02' as jid
    from dual
  union all
  select '10002' as depid, '1000' as salary, 'wangwu' as n, '01' as jid
    from dual
  union all
  select '10002' as depid, '2000' as salary, 'zhaoliu' as n, '03' as jid
    from dual
  union all
  select '10003' as depid, '15000' as salary, 'tianqi' as n, '01' as jid
    from dual
  union all
  select '10003' as depid, '15000' as salary, 'wangba' as n, '02' as jid
    from dual
  union all
  select '10004' as depid, '15000' as salary, 'jiudan' as n, '01' as jid
    from dual)

--rollup指定一個列的時候,按depid分組之後有總計
--rollup中列的順序不同,則統計的結果不同。因為它是按列從右遞減分組的。
--如 Group by  ROLLUP(A, B, C),首先會對(A、B、C)進行GROUP BY,然後對(A、B)進行GROUP BY,然後是(A)進行GROUP BY,最後對全表進行GROUP BY操作
select nvl(depid,'總計'),sum(salary) as total from temp group by rollup(depid)

可見,在rollup加上一列的時候,最後一行出現了總計。

但是,當rollup()中指定多個列的時候,按第一個的分組都會有一個小計,如下:

with temp as
 (select '10001' as depid, '12000' as salary, 'zhangsan' as n, '01' as jid
    from dual
  union all
  select '10001' as depid, '10000' as salary, 'lisi' as n, '02' as jid
    from dual
  union all
  select '10002' as depid, '1000' as salary, 'wangwu' as n, '01' as jid
    from dual
  union all
  select '10002' as depid, '2000' as salary, 'zhaoliu' as n, '03' as jid
    from dual
  union all
  select '10003' as depid, '15000' as salary, 'tianqi' as n, '01' as jid
    from dual
  union all
  select '10003' as depid, '15000' as salary, 'wangba' as n, '02' as jid
    from dual
  union all
  select '10004' as depid, '15000' as salary, 'jiudan' as n, '01' as jid
    from dual)

--rollup指定多個列的時候,按第一個的分組都會有一個小計
select decode(grouping(jid) + grouping(depid), 1, '小計', 2, '總計', jid) jid,
       depid,
       sum(salary) as total
  from temp
 group by rollup(jid, depid)

可見,每一組Jid之後都出現了一個小計結果,最後一行也出現了總計結果,在實際工作中進行Oracle報表統計時相當有用。

但是,rollup()中指定多個列時,順序不同,統計的結果也不同。

with temp as
 (select '10001' as depid, '12000' as salary, 'zhangsan' as n, '01' as jid
    from dual
  union all
  select '10001' as depid, '10000' as salary, 'lisi' as n, '02' as jid
    from dual
  union all
  select '10002' as depid, '1000' as salary, 'wangwu' as n, '01' as jid
    from dual
  union all
  select '10002' as depid, '2000' as salary, 'zhaoliu' as n, '03' as jid
    from dual
  union all
  select '10003' as depid, '15000' as salary, 'tianqi' as n, '01' as jid
    from dual
  union all
  select '10003' as depid, '15000' as salary, 'wangba' as n, '02' as jid
    from dual
  union all
  select '10004' as depid, '15000' as salary, 'jiudan' as n, '01' as jid
    from dual)

select decode(grouping(jid) + grouping(depid), 1, '小計', 2, '總計', depid) depid,
       jid,
       sum(salary) as total
  from temp
 group by rollup(depid,jid)

與上面一個示例比較,這裡是每一組depid對應的後面都出現了小計結果,最後出現總計結果。

二、總結

本文是筆者在實際工作中,對常用到Oracle的一些函式進行總結和一些實踐,僅供大家學習參考,希望能對大家的學習有所幫助!