[toc]
你需要知道的
提到 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 這個函數爲:多行函數(針對<font color=#FF0000>每個結果集</font>只返回一個值)。<font color=#FF0000>不要這麼記</font>:針對多行只返回一個值的稱作多行函數。
如何理解<每個結果集>這個概念
再看個例子:按照部門,查詢每個部門的工資總和,於是發出下面的語句並得到結果。
SQL> select deptno,sum(sal) from emp group by deptno order by 1;
DEPTNO SUM(SAL)
---------- ----------
10 8750
20 10875
30 9400
呈現的結果爲<font color=#FF0000>3行</font>數據,處理前一共 14 行,通過 sum 求和函數處理後得到 3 行數據,請問:sum 是多行函數嗎?當然是!這裏涉及到一個基本概念的理解,如果你認爲:~~<font color=#FF0000>針對多行返回一行稱爲多行函數。</font>~~那麼我通過這個例子就可以反駁你,因爲我針對多行(14行)返回了 3 行,不是 1 行。你能告訴我說 sum 不是多行函數嗎?所以,這種說法本身就存在歧義。
而官方教材對多行函數的精準描述是這樣的:<font color=#FF0000>Return one result per set of rows.</font>什麼意思?針對每個行集(或理解爲結果集)返回一個值(就是一行)。這麼記,你對多行函數的概念就不會迷迷糊糊了。
那如何理解<font color=#FF0000>行集(結果集)</font>這個概念?我們求所有部門的工資總和 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;
答案:<font color=#F8F8FF>A</font>