Oracle 中關於 Group By 子句與多行函數嵌套搭配使用的注意事項


你需要知道的

提到 Group by 子句,你需要先理解一個東西:函數的分類。提到函數分類,你腦海里面需要瞬間想到Oracle中的函數分類:單行函數(Single-row functions)、多行函數(Multiple-row functions)。請把中文英文都背下來,也就這么兩個,這是Oracle的函數分類的體系,很重要。以后再遇到這個知識點,你至少能夠胸有成竹,張口就來。

啥叫單行函數

舉個現炒板栗:你說你要查 EMP 表中,所有人員的名字和他對應的工資,於是發出下面的語句並得到結果。

SQL> select ename,sal from emp;

ENAME			    SAL
-------------------- ----------
SMITH			    800
ALLEN			   1600
WARD			   1250
JONES			   2975
MARTIN			   1250
BLAKE			   2850
CLARK			   2450
SCOTT			   3000
KING			   5000
TURNER			   1500
ADAMS			   1100
JAMES			    950
FORD			   3000
MILLER			   1300

14 rows selected.

你會發現,14行結果中,每個人的名字都是大寫(注意:Oracle 語句不區分大小寫,但是存的值是區分大小寫的,SCOTT 和 scott 是兩個值)。你說你看的不習慣,問能否把名字處理成“小寫”字母來顯示?

這里我們給出一個東西 lower(),它是什么?你先不管,先叫它“函數”,我們用它把名字處理一下:發出以下命令並得到結果。

SQL> select lower(ename),sal from emp;

LOWER(ENAME)		    SAL
-------------------- ----------
smith			    800
allen			   1600
ward			   1250
jones			   2975
martin			   1250
blake			   2850
clark			   2450
scott			   3000
king			   5000
turner			   1500
adams			   1100
james			    950
ford			   3000
miller			   1300

14 rows selected.

你會發現,名字通過 lower 函數處理之后,全部變為了小寫,更重要的是,處理完畢后,結果集的行數(14行)和處理前結果集的行數(14行)完全一致,也就是說,用了這個 lower 函數處理數值,最終的結果條目數是一比一的呈現,於是,我們稱 lower 這個函數為:單行函數(針對結果集的每一行都返回一個值)。

啥叫多行函數

你說你要查 EMP 表中,所有人員工資的總和,於是發出下面的語句並得到結果。

SQL> select sum(sal) from emp;

  SUM(SAL)
----------
     29025

這個 sum 是什么,也是個函數,你會發現,使用了這個 sum 求和函數后,最終返回一行數據。原來 14 行,使用了 sum 變為 1 行,於是,我們稱 sum 這個函數為:多行函數(針對每個結果集只返回一個值)。不要這么記針對多行只返回一個值的稱作多行函數

如何理解<每個結果集>這個概念

再看個例子:按照部門,查詢每個部門的工資總和,於是發出下面的語句並得到結果。

SQL> select deptno,sum(sal) from emp group by deptno order by 1;

    DEPTNO   SUM(SAL)
---------- ----------
	10	 8750
	20	10875
	30	 9400

呈現的結果為3行數據,處理前一共 14 行,通過 sum 求和函數處理后得到 3 行數據,請問:sum 是多行函數嗎?當然是!這里涉及到一個基本概念的理解,如果你認為:針對多行返回一行稱為多行函數。那么我通過這個例子就可以反駁你,因為我針對多行(14行)返回了 3 行,不是 1 行。你能告訴我說 sum 不是多行函數嗎?所以,這種說法本身就存在歧義。

而官方教材對多行函數的精准描述是這樣的:Return one result per set of rows.什么意思?針對每個行集(或理解為結果集)返回一個值(就是一行)。這么記,你對多行函數的概念就不會迷迷糊糊了。

那如何理解行集(結果集)這個概念?我們求所有部門的工資總和 sum(sal) ,這個行集就是 14 行數據,最終返回 1 行,就是總額。我們按照部門,求每個部門的工資總和,因此要按照部門分開,求出每個部門的工資總和,我們先看下 10 號部門的行數:

SQL> select count(1) from emp where deptno=10;

  COUNT(1)
----------
	 3

10 號部門有 3 行數據,因此,對於 10 號部門工資求和的行集就是 3 行,通過計算這 3 行的數據,最終返回 1 行,就是 10 號部門的工資總額。

再來看 20 號部門:這個部門一共 5 行數據,因此,對於 20 號部門來說,行集就是 5 行,最終返回 1 行,就是 20 號部門的工資總額。

SQL> select count(1) from emp where deptno=20;

  COUNT(1)
----------
	 5

30 號部門也一樣:一共 6 行數據,因此,對於 30 號部門來說,行集就是 6 行,最終返回 1 行,就是 30 號部門的工資總額。

SQL> select count(1) from emp where deptno=30;

  COUNT(1)
----------
	 6

Group by 子句使用規則

  • 使用多行函數不一定要使用 group by 子句

例如:查詢所有部門工資總和

SQL> select sum(sal) from emp;
  • select 子句中包含的所有字段(除使用了多行函數的字段)都必須包含在 group by 子句中

例如:按照部門分組查詢每個部門的工資總和

SQL> select deptno,sum(sal) from emp group by deptno;

注意:select 子句中包含兩個字段 deptno 和 sum(sal) ,因為 sal 字段使用了多行函數,所以在后面 group by 子句中只需要包含 deptno 即可。

  • select 子句所有字段都使用了多行函數,group by 子句可以根據需求指定分組字段
# 以下語句都是正確的。從業務邏輯層面來說,毫無意義,只是為了展示語句規則。
SQL> select sum(sal) from emp group by ename;
SQL> select sum(sal) from emp group by ename,empno;
SQL> select sum(sal) from emp group by ename,empno,sal;
  • 多行函數嵌套必須使用 group by 子句

注意下嵌套函數:嵌套函數不是一個函數,而是對函數疊加使用的描述。例如:求出哪個部門工資總和最大。

SQL> select max(sum(sal)) from emp group by deptno;

MAX(SUM(SAL))
-------------
	10875

這個 max(sum(sal)) 就是一個嵌套函數,多行函數嵌套最多嵌套 2 層。單行函數嵌套無限制。

  • select子句中不允許出現除多行函數嵌套的其他字段

例如:下面語句報錯

SQL> select deptno,max(sum(sal)) from emp group by deptno;
select deptno,max(sum(sal)) from emp group by deptno
       *
ERROR at line 1:
ORA-00937: not a single-group group function

看一道 071 考題

Which query is valid?

A. SELECT dept_id,join_date,sum(salary) FROM employees GROUP BY dept_id,join_date;
B. SELECT dept_id,join_date,sum(salary) FROM employees GROUP BY dept_id;
C. SELECT dept_id,MAX(AVG(salary)) FROM employees GROUP BY dept_id;
D. SELECT dept_id,AVG(MAX(salary)) FROM employees GROUP BY dept_id;

答案:A


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM