在介紹了Oracle中的基本數據類型及相應的處理函數後,本章將介紹Oracle中較爲複雜的數據處理。
接下來,本文將介紹:
1、利用聚合函數來統計數據;
2、常用技巧;
3、oracle中的基本運算;
4、oracle特殊判式;
5、oracle中的分析與窗口函數
1. 利用聚合函數統計數據
前面幾篇博客介紹的,都有一個共同的特點:均針對單一數據。
而聚合函數則是針對多個數據獲得統計結果。使用聚合函數的場景大多爲表中的數據,接下來的所有示例均基於表employees,其數據結構及內容如下所示。
SQL>select * from employees
表employees中存儲了員工的基本信息,有員工ID、員工姓名、員工職位、員工年齡、員工家庭住址。
1.1 求最大值----max()函數
max()函數可以用於獲得一組數據中的最大值,這裏的“一組數據”通常爲表中某列的所有值,max()函數可以應用的數據類型包括數值型和字符型。
(1)max()函數應用於數值型
max()函數應用於數值型時,是按照數值的大小順序來獲得最大值。
例子:爲了獲得員工的最大年齡可以利用如下所示的SQL語句
SQL>select max(employee_age) max_age from employees;
------
37
from employees提供了表employees中的所有記錄作爲數據源;max(employee_age)中的employee_age爲數據列,該列的所有數據組成了max()函數的參數,max()函數則統計該組數據中的最大值。
max()函數的返回值是一個統計值,與數據表中的元數據並沒有一一對應的關係。例如:表employees中可能存儲了多個37歲的員工信息,而max()函數的返回值只是一個統計值。
(2)max()函數應用於字符型
max()函數不僅可以應用於數值型,還可以應用於字符型。當應用於字符型時,oracle會依照字母表由前到後的順序進行排序。
例子:在表employees中,列employee_name爲字符型,可以利用max()函數來獲得去最大值。
SQL>select max(employee_name ) max_name from employees;
--------
鍾小平
(3)max()函數應用於日期型
日期型的實質也是數值型,因此,max()函數應用於日期型與數值型具有完全相同的效果-----獲得最晚日期。
1.2 求最小值-----min()函數
與max()函數相反,min()函數可以獲得最小值。min()函數同樣可應用於數值型、字符型和日期型。
1.3 求平均值-----avg()函數
avg()函數用於獲得一組數據的平均值,該函數只能應用於數值型。
avg()函數的返回值是一個number型。
1.4求和----sum()函數
sum()函數用於獲得一組數據的和。該函數同樣只能應用於數值型。
例子:爲了獲得employees中所有員工年齡之和,可以利用如下SQL語句。
SQL.>select sum(employee_age ) sum_age from employees;
1.5 統計記錄數-----count()函數
count()函數用於統計記錄數目。該函數的常見使用場景有3種。
(1)統計單列
對於統計單列來說,列名作爲count()函數的參數,當列值不爲空時,將計數1;否則,將計數0。
(2)統計所有列
當表的所有列被作爲count()函數的參數,即count(*)進行統計時,即使所有列值均爲空,oracle仍將進行計數。
select count(*) from employees;
(3)利用count(1)進行統計
對於count()函數來說,還可以利用count(1)的形式進行統計。count(1)與count(*)返回的值相同,對每條記錄都計數1.
SQL>select count(1) from employee;
2、oracle中的常用技巧
除了針對基本數據類型的各種函數之外,oracle還提供了一些其他技巧性函數。比如:
多值判斷---decode()函數、爲空值重新賦值---nvl()函數、結果集的行號----rownum()函數、強制轉換數據類型-----cast()函數
2.1 多值判斷-----decode()函數
在oracle中,可以利用if else和case語句進行判斷,當然還有decode()函數處理該問題,從而減少了代碼量,並增強了SQL語句的可讀性。
decode()函數的使用語法如下:
decode(表達式,比較值1,結果值1,比較值2,結果值2,....,默認值)
decode()函數的處理過程類似於解碼過程,第一個參數表達式往往爲變量或者數據表中的列;其後的參數總是以“比較值---結果值”對的形式出現,表達式的值與“比較值”進行比較,如果二者相等,則返回相應的“結果值”;若果所有比較都不成功,那麼將返回默認值。
例子:在表employees所存儲的數據表中,列employee_position標識了員工的職位,現需要對員工進行分類:職位是工程師的員工規劃技術部,其他員工劃爲行政管理部。那麼可以利用decode()函數來實現這一用法。
decode(sign(instr(employee_position,'工程師')), 1, '技術部', '行政管理部')中 sign(instr(employee_position,'工程師'))用於獲得列employee_position中字符串“工程師”的位置,並判斷其正負性;1,‘技術部’是第一個“比較值---結果值”鍵值對,表示當員工爲工程師時,返回字符串“技術部”;最後一個參數“行政管理部”爲默認值。
2.2 空值處理-----nvl()函數
數據庫中的數據難免出現空值,但是對於用戶來說,空值並不夠友好。用戶更願意獲得有意義的數據,nvl()函數可以判斷表達式的值是否爲空。如果爲空,則可以返回新值;若不爲空,則返回原值。其使用語法如下所示:
nvl(表達式,新值/表達式)
nvl()函數首先判斷第一個表達式參數的值是否爲空;如果爲空,則返回第二個參數的的值;如果不爲空,則返回第一個參數表達式的值。
例子:表employees和表salary分別存儲了員工及員工工資信息,可以通過分組獲得員工及員工總額信息。
nvl(sum(salary), 0 ) 用於判斷員工的工資總額是否爲空,如果爲空則返回0,因此記錄1--5的工資總額仍然保持原值,而記錄6--8的工資總額被置爲0.
2.3 結果集的行號----rownum()函數
rownum()函數可以返回結果集的行號,對於select語句,沒捕獲一條記錄,rownum()函數的返回值將累加1,否則,rownum()的返回值保持不變。
(1)利用rownum爲搜尋結果添加一列
例子:rownum的最簡單應用場景是爲搜尋結果添加一列,如下所示。
SQL>select e.employee_id, e.employee_name, rownum from emplyees e;
select e.employee_id, e.employee_name, rownum from emplyees e用於遍歷表employees,並捕獲每條記錄中的employee_id和employee_name列;每捕獲一條記錄,rownum的返回值將累加1,因此,rownum依次返回1--8的值。
(2)rownum與order by子句。
對錶中數據排序,然後獲得排名在某個範圍之內的記錄是一種常見需求。例如,要求獲得表employees中、按員工姓名排序前3位的員工信息。一種常見的思路爲綜合利用rownum與order by子句排序並增加過濾條件----rownum小於等於3.
SQL>select e.employee_id, employee_name, rownum from employees e where rownum <= 3 order by e.employee_name;
EMPLOYEE_ID EMPLOYEE_NAME ROWNUM
------------------- ------------------------- -----------
3 劉俊 3
1 王曉 1
2 鍾小平 2
where rownum<=3用於限制rownum小於等於3的記錄;order by e.employee_name用於對錶employees中的記錄按照employee_name列進行排序。
從上面的查詢結果可以看出,並不是預期的效果。原因在於where條件先於order by子句執行。也就是說,Oracle總是先利用where條件過濾搜尋記錄,最後才利用order by進行排序。而rownum的返回值用於where條件判斷,這造成了所有rownum執行完畢之後在再執行排序操作。
該需求的正確解決方式爲,首先利用內嵌式圖獲得排序之後的結果,然後對內嵌視圖所代表的結果集使用rownum()函數,SQL語句如下所示:
SQL>select t.*, rownum from (
select e.employee_id, employee_name from employees e order by e.employee_name) t where rownum<=3
EMPLOYEE_ID EMPLOYEE_NAME ROWNUM
-------------------- ------------------------- ---------------
7 李四 1
3 劉俊 2
4 王龍 3
內嵌視圖 t 的定義爲select e.employee_id, employee_name from employees e order by e.employee_name.該內嵌視圖所代表的結果集如下:
EMPLOYEE_ID EMPLOYEE_NAME
--------------------- ---------------------------
7 李四
3 劉俊
4 王龍
8 王五
1 王曉
6 張三
5 鍾文
2 鍾小平
對該結果集來說,rownum<=3將返回前3條記錄,即爲:
EMPLOYEE_ID EMPLOYEE_NAME
------------------- ----------------------------
7 李四
3 劉俊
4 王龍
因此,對於rownum()函數的使用來說,首先要觀察rownum()函數出現在查詢語句的哪個子句中,而子句的執行時機往往決定rownum()函數的返回值。
(3)rownum與比較運算符“=‘
rownum()函數常常出現在查詢條件中,SO,rownum()函數與比較運算符“=”的結合使用。
例子:現需要獲得employees中,行號爲1的員工信息,最容易想到的SQL語句如下:
SQL>select e.employee_id, e.employee_name, rownum from employees e where rownum =1;
分析查詢結果可知,利用rownum=1可以獲得預期的結果,但是,利用該方法無法成功獲得行號爲4的員工信息。
【分析】這是因爲rownum總是從1開始,如果不能獲得rownum爲1的記錄,那麼rownum的返回值永遠無法達到大於1的數字。可以通過分析該SQL語句的執行過程解釋查詢失敗的原因。
select e.employee_id, e.employee_name, rownum from employees e 用於自表employees中獲取記錄;where rownum=4則指定了過濾條件;當Oracle遍歷至表employees的第一條記錄時,rownum爲1,但是where rownum=4爲假,那麼該記錄不在捕獲範圍;當遍歷至表employees的第二條記錄時,因爲捕獲記錄爲0,rownum仍然返回 1,;以此類推,無論Oracle遍歷多少條記錄,rownum總是爲1,也永遠無法滿足rownum=4的條件。
事實上,單純利用rownum=n作爲查詢語句的過濾條件,當n大於1室,返回的查詢結果永遠爲空。此處,仍然可以通過內嵌視圖來解決該問題。
(4)rownum與比較運算符“>”
例子:與比較運算符“=”類似,如果對rownum使用了對於運算,而比較值又大於等於 1 時,Oracle同樣返回空的結果集。
如果,當rownum>n中的 n 小於1,那麼查詢語句將返回所有記錄。
2.4 強制轉換數據類型-----cast()函數
Oracle中的cast()函數可以強制轉換列或變量的數據類型。其語法如下所示:
cast( 元數據 as 新的數據類型 )
3、Oracle中的運算
Oracle中的常用運算包括數學運算、邏輯運算、比較運算和按位運算。
4、Oracle中的特殊判式
Oracle進行條件判斷時,最常見的操作符爲“=’。除此之外,oracle還提供了若干特殊判式進行邏輯判斷。這些判式包括:
between-----範圍測試;in-----集合成員測試;like----模糊匹配;is null-----空值判斷;exits-----存在性判斷;all、some、any----數量判斷。
4.1 between-----範圍測試
between可以用於判斷列或表達式的值是否處於某個範圍之內。其使用語法如下:
between x and y
其中,x和y限定了範圍的臨界值。
4.2 in -------集合成員測試
in判式用於判斷某個列或表達式的值是否處於某個結合之內
4.3 like-----模糊匹配
用戶在查詢數據時,往往並不能提供精確的匹配條件。例如:用戶試圖通過公司名稱查詢記錄時,並不能提供精確的公司全稱;又如,用戶可能希望獲得某位員工的信息,而只能確定員工的姓氏。這些情況下,即可使用模糊查詢,oracle中提供了like判式實現模糊匹配。
(1)、匹配任意字符串----“%”
對於like判式,最常用的通配符爲“%”,該通配符可用於匹配任意長度的任意字符。
比如:'劉%',指定查詢條件爲該列的值以“劉”爲開頭,後面跟任意長度的任意字符,因此將返回所有劉姓員工的姓名。
(2)、匹配單個字符-----“_”
對於like判式,另外一個常用通配符爲“_”。該通配符可用於匹配任意的單個字符。
例子:'劉_',指的是劉後面只能跟一個字符。。
當然,多個通配符“_”可以同時使用,比如:'劉__',劉後面跟着兩個“_”。
(3)原義字符
在like判式中,通配符“%”和“_” 有着特殊的意義。但是有時候用戶希望判斷標準中出現了這兩個字符,那麼將需要二者的原義字符。
例子:對於一個字符串,百分比“20%”,用戶希望判斷是否該字符串以“%”結尾,直接在判式中使用“%”無法達到預期效果。
因此,需要用到"\"; like ‘%\%’中的第一個%,表示通配符;而後面的表示原義字符。
4.4 is null -----空值判斷
oracle中不能使用“=”判斷一個列或者表達式的值是否爲空 ,而是利用特殊判式 is null.
當然,is null判式的對立面是is not null,爲了獲得所有列值均完整無缺的記錄,相應的SQL語句如下所示。
SQL> select * from employees
where employee_id is not null
and employee_name in not null
and ....
............
利用is not null對錶中的所有列進行判斷,可以獲得所有列值均不爲空的記錄。
4.5 exits---存在性判斷
exits判式可以用於判斷記錄的存在性,exits判式的操作對象是結果集,當結果集匯中記錄大於0時,將返回爲真,否則,將返回爲假。