Oracle_子查詢和常用函式
1、子查詢
子查詢在 SELECT、UPDATE、DELETE 語句內部可以出現 SELECT 語句。內部的 SELECT 語句結果可以作為外部語句中條件子句的一部分,也可以作為外部查詢的臨時表。子查詢的型別有:
- 單行子查詢:不向外部返回結果,或者只返回一行結果。
- 多行子查詢:向外部返回零行、一行或者多行結果。
案例 1:查詢出銷售部(SALES)下面的員工姓名,工作,工資。
案例分析:該問題可以用聯接查詢實現,由於所需的結果資訊都在 Emp 表中,可以先從 Dept 表中查詢出銷售部對應的部門號,然後根據當前部門號再到 Emp 表中查詢出符合該部門的員工記錄即可。從銷售表中查詢出的結果可以作為 Emp 表中查詢的條件,SQL 語句實現如下:
程式碼解析:
內部查詢的結果作為外部查詢的條件。需要注意:如果內部查詢不返回任何記錄,則外部條件中欄位 DEPTNO 與 NULL 比較永遠為假,也就是說外部查詢不返還任何結果。
- 在單行子查詢中外部查詢可以使用=、>、<、>=、<=、<>等比較運算子。
- 內部查詢返回的結果必須與外部查詢條件中的欄位(DEPTNO)匹配。
- 如果內部查詢返回多行結果則出現錯誤。
案例 2:查詢出 Emp 表中比任意一個銷售員(“SALESMAN”)工資低的員工姓名、工作、工資。
案例分析:銷售員在 Emp 表中有很多條記錄,每個人工資不相等,如果返回“比任意員工的工資還低”的條件,返回比“最高工資還低”即可。如果用子查詢做,子查詢中就會返回多條記錄。用普通的關係符(>、<等)執行就會出錯。這時候需要用關鍵字 ANY。ANY 放在比較運算子後面,表示“任意”的意思。
程式碼演示:ANY 子查詢
程式碼解析:
<any:比子查詢結果中任意的值都小,也就是說,比子查詢結果中最大值還小,那麼同理>any 表示比子查詢結果中最小的還大。
案例 3:查詢出比所有銷售員的工資都高的員工姓名,工作,工資。
案例分析:ANY 可以表示任意的,但本案例中要求比所有銷售員工資都高,那麼就要使用另外一個關鍵字 ALL。ALL 與關係操作符一起使用,表示與子查詢中所有元素比較。
程式碼解析:
- >ALL:比子查詢結果中所有值還要大,也就是說,比子查詢結果中最大值還要大。
- <ALL 表示比最小值還要小。
對於子查詢還可以使用 IN 和 NOT IN 操作符進行操作。
2、Oracle 中的偽列
在 Oracle 的表的使用過程中,實際表中還有一些附加的列,稱為偽列。偽列就像表中的列一樣,但是在表中並不儲存。偽列只能查詢,不能進行增刪改操作。接下來學習兩個偽列:ROWID 和 ROWNUM。
(1) ROWID
表中的每一行在資料檔案中都有一個實體地址,ROWID 偽列返回的就是該行的實體地址。使用 ROWID 可以快速的定位表中的某一行。ROWID 值可以唯一的標識表中的一行。由於 ROWID 返回的是該行的實體地址,因此使用 ROWID 可以顯示行是如何儲存的。
程式碼演示:ROWID
(2) ROWNUM
在查詢的結果集中,ROWNUM 為結果集中每一行標識一個行號,第一行返回 1,第二行返回 2,以此類推。通過 ROWNUM 偽列可以限制查詢結果集中返回的行數。
PS:ROWNUM 與 ROWID 不同,ROWID 是插入記錄時生成,ROWNUM 是查詢資料時生成。ROWID 標識的是行的實體地址。ROWNUM 標識的是查詢結果中的行的次序。
案例 4:查詢出員工表中前 5 名員工的姓名,工作,工資。
程式碼演示:ROWNUM
案例 5:查詢出工資最高的前 5 名員工的姓名、工資和工資。
案例分析:“工資最高的前 5 名”需要先降序排序,再取前 5 名,但是生成 ROWNUM 操作比排序要早,排序時已經連同 ROWNUM 一起排序了,因此不能直接在案例 1 的語句中直接加上Order by 就行,而是需要對排序的結果重新做二次查詢,產生新的 ROWNUM 才能作為查詢的條件依據。
程式碼演示:ROWNUM 應用
案例 6:查詢出表 EMP 中第 5 條到第 10 條之間的記錄。
案例分析:這是分頁的應用。在查詢條件中,如果查詢條件中 ROWNUM 大於某一正整數,則不返還任何結果。
程式碼演示:ROWNUM 分頁
3、 Oracle 函式
Oracle SQL 提供了用於執行特定操作的專用函式。這些函式大大增強了 SQL 語言的功能。函式可以接受零個或者多個輸入引數,並返回一個輸出結果。Oracle 資料庫中主要使用兩種型別的函式:
- 單行函式:對每一個函式應用在表的記錄中時,只能輸入一行結果,返回一個結果,比如:MOD(x,y)返回 x 除以 y 的餘數(x 和 y 可以是兩個整數,也可以是表中的整數列)。常用的單行函式有:
- 聚合函式:聚合函式同時可以對多行資料進行操作,並返回一個結果。比如 SUM(x)返回結果集中 x 列的總合。
- 字元函式:對字串操作。
- 數字函式:對數字進行計算,返回一個數字。
- 轉換函式:可以將一種資料型別轉換為另外一種資料型別。
- 日期函式:對日期和時間進行處理。
(1)字元函式
字元函式接受字元引數,這些引數可以是表中的列,也可以是一個字串表示式。下表列出了常用的字元函式。
函式 | 說明 |
ASCII(x) | 返回字元 x 的 ASCII 碼。 |
CONCAT(x,y) | 連線字串 x 和 y。 |
INSTR(x, str [,start] [,n) | 在 x 中查詢 str,可以指定從 start 開始,也可以指定從第 n 次開始。 |
LENGTH(x) | 返回 x 的長度。 |
LOWER(x) | x 轉換為小寫。 |
UPPER(x) | x 轉換為大寫。 |
LTRIM(x[,trim_str]) | 把 x 的左邊截去 trim_str 字串,預設截去空格。 |
RTRIM(x[,trim_str]) | 把 x 的右邊截去 trim_str 字串,預設截去空格。 |
TRIM([trim_str FROM] x) | 把 x 的兩邊截去 trim_str 字串,預設截去空格。 |
REPLACE(x,old,new) | 在 x 中查詢 old,並替換為 new。 |
SUBSTR(x,start[,length]) | 返回 x 的字串,從 staart 處開始,擷取 length 個字元,預設 length,預設到結尾。 |
SQL> SELECT ASCII('a') FROM DUAL;
ASCII('A')
----------
97
SQL> SELECT CONCAT('Hello', ' world') FROM DUAL;
CONCAT('HEL
-----------
Hello world
SQL>SELECT INSTR('Hello world','or') FROM DUAL;
INSTR('HELLOWORLD','OR')
------------------------
8
SQL> SELECT LENGTH('Hello') FROM DUAL;
LENGTH('HELLO')
---------------
5
SQL> SELECT LOWER('hElLO') FROM DUAL;
LOWER
-----
hello
SQL> SELECT UPPER('hello') FROM DUAL;
UPPER
-----
HELLO
SQL> SELECT LTRIM('===HELLO===', '=') FROM DUAL;
LTRIM('=
--------
HELLO===
SQL> SELECT '=='||LTRIM(' HELLO===') FROM DUAL;
'=='||LTRI
----------
==HELLO===
SQL> SELECT RTRIM('===HELLO===', '=') FROM DUAL;
RTRIM('=
--------
===HELLO
SQL> SELECT '='||TRIM(' HELLO ')||'=' FROM DUAL;
'='||TR
-------
=HELLO=
SQL> SELECT TRIM('=' FROM '===HELLO===') FROM DUAL;
TRIM(
-----
HELLO
SQL> SELECT REPLACE('ABCDE','CD','AAA') FROM DUAL;
REPLAC
------
ABAAAE
SQL> SELECT SUBSTR('ABCDE',2) FROM DUAL;
SUBS
----
BCDE
SQL> SELECT SUBSTR('ABCDE',2,3) FROM DUAL;
SUB
---
BCD
(2)數字函式
數字函式接受數字引數,引數可以來自表中的一列,也可以是一個數字表達式。
函式 | 說明 | 示例 |
ABS(x) | x 絕對值 | ABS(-3)=3 |
ACOS(x) | x 的反餘弦 | ACOS(1)=0 |
COS(x) | 餘弦 | COS(1)=1.57079633 |
CEIL(x) | 大於或等於 x 的最小值 | CEIL(5.4)=6 |
FLOOR(x) | 小於或等於 x 的最大值 | FLOOR(5.8)=5 |
LOG(x,y) | x 為底 y 的對數 | LOG(2,4)=2 |
MOD(x,y) | x 除以 y 的餘數 | MOD(8,3)=2 |
POWER(x,y) | x 的 y 次冪 | POWER(2,3)=8 |
ROUND(x[,y]) | x 在第 y 位四捨五入 | ROUND(3.456,2)=3.46 |
SQRT(x) | x 的平方根 | SQRT(4)=2 |
TRUNC(x[,y]) | x 在第 y 位截斷 | TRUNC(3.456,2)=3.45 |
說明:
1、ROUND(X[,Y]),四捨五入。
在預設 y 時,預設 y=0;比如:ROUND(3.56)=4。
y 是正整數,就是四捨五入到小數點後 y 位。ROUND(5.654,2)=5.65。
y 是負整數,四捨五入到小數點左邊|y|位。ROUND(351.654,-2)=400。
2、TRUNC(x[,y]),直接擷取,不四捨五入。
在預設 y 時,預設 y=0;比如:TRUNC (3.56)=3。
y 是正整數,就是四捨五入到小數點後 y 位。TRUNC (5.654,2)=5.65。
y 是負整數,四捨五入到小數點左邊|y|位。TRUNC (351.654,-2)=300。
(3)日期函式
日期函式對日期進行運算。常用的日期函式有:
1.ADD_MONTHS(d,n),在某一個日期 d 上,加上指定的月數 n,返回計算後的新日期。d 表示日期,n 表示要加的月數。
2.LAST_DAY(d),返回指定日期當月的最後一天。
3.ROUND(d[,fmt]),返回一個以 fmt 為格式的四捨五入日期值,d 是日期,fmt 是格式模型。預設 fmt 為 DDD,即月中的某一天。
- 如果 fmt 為“YEAR”則舍入到某年的 1 月 1 日,即前半年捨去,後半年作為下一年。
- 如果 fmt 為“MONTH”則舍入到某月的 1 日,即前月捨去,後半月作為下一月。
- 預設為“DDD”,即月中的某一天,最靠近的天,前半天捨去,後半天作為第二天。
- 如果 fmt 為“DAY”則舍入到最近的周的週日,即上半周捨去,下半周作為下一週週日。
與 ROUND 對應的函式時 TRUNC(d[,fmt])對日期的操作,TRUNC 與 ROUND 非常相似,只是不對日期進行舍入,直接擷取到對應格式的第一天。
4. EXTRACT(fmt FROM d),提取日期中的特定部分。
fmt 為:YEAR、MONTH、DAY、HOUR、MINUTE、SECOND。其中 YEAR、MONTH、DAY可以為 DATE 型別匹配,也可以與 TIMESTAMP 型別匹配;但是 HOUR、MINUTE、SECOND 必須與 TIMESTAMP 型別匹配。HOUR 匹配的結果中沒有加上時區,因此在中國執行的結果小 8 小時。
(4)轉換函式
轉換函式將值從一種資料型別轉換為另外一種資料型別。常用的轉換函式有:
1. TO_CHAR(d|n[,fmt])。 把日期和數字轉換為制定格式的字串。
程式碼演示:TO_CHAR 對日期的處理
程式碼解析:
在格式化字串中,使用雙引號對非格式化字元進行引用。針對數字的格式化,格式化字元有:
引數 | 示例 | 說明 |
9 | 999 | 指定位置處顯示數字。 |
* | 9.9 | 指定位置返回小數點 |
, | 99,99 | 指定位置返回一個逗號 |
$ | $999 | 數字開頭返回一個美元符號 |
EEEE | 9.99EEEE | 科學計數法表示 |
L | L999 | 數字前加一個本地貨幣符號 |
PR | 999PR | 如果數字式負數則用尖括號進行表示 |
程式碼演示:TO_CHAR 對數字的處理
2. TO_DATE(x [,fmt]) 把一個字串以 fmt 格式轉換為一個日期型別
3. TO_NUMBER(x[,fmt]) 把一個字串以 fmt 格式轉換為一個數字。
程式碼演示:TO_NUM 函式
(4)其他單行函式
1. NVL(x,value) 如果 x 為空,返回 value,否則返回 x。
案例 7:對工資是 2000 元以下的員工,如果沒有發獎金,每人獎金 100 元。
程式碼演示:NVL 函式
2. NVL2(x,value1,value2) 如果 x 非空,返回 value1,否則返回 value2。
案例 8:對 EMP 表中工資為 2000 元以下的員工,如果沒有獎金,則獎金為 200 元,如果有獎金,則在原來的獎金基礎上加 100 元。
程式碼演示:NVL2 函式
(5)聚合函式
聚合函式同時對一組資料進行操作,返回一行結果,比如計算一組資料的總和,平均值等。
名稱 | 作用 | 語法 |
AVG | 平均值 | AVG(表示式) |
SUM | 求和 | SUM(表示式) |
MIN、MAX | 最小值、最大值 | MIN(表示式)、MAX(表示式) |
COUNT | 資料統計 | COUNT(表示式) |
案例 9:求本月所有員工的基本工資總和。
程式碼演示:SUM 函式
案例 10:求不同部門的平均工資。
程式碼演示:AVG 函式下的分組查詢