1. 程式人生 > >Oracle資料庫------------------------------分組統計查詢(分組查詢)

Oracle資料庫------------------------------分組統計查詢(分組查詢)

Oracle資料庫的學習記錄:

十九、分組統計查詢----分組查詢
能夠分組的時候往往是指的是部分資料具備某些共性
要想分組,使用GROUP BY子句
SELECT [DISTINCT] 分組欄位 [別名],分組欄位 [別名],...|統計函式
,...FROM 表名稱 [別名] [WHERE 過濾條件] [GROUP BY 分組欄位,分組欄位...] [ORDER BY 欄位 [ASC|DESC],...,欄位 [ASC|DESC],];
先FROM,再WHERE,再GRUOP BY,再SELECT,最後ORDER BY
範例:要求按照職位分組,統計出每個職位的名稱、平均人數、平均工資
SELECT job,COUNT(*),AVG(sal) FROM emp GROUP BY job;
範例:要求查詢出每個部門編號,以及每個部門的人數、最高與最低工資
SELECT deptno,COUNT(empno),MAX(sal),MIN(sal) FROM emp GROUP BY deptno;
所選擇的job和deptno兩個欄位上都是存在有重複資料的

對於分組操作嚴格來講還是存在一些使用上的限制的,要求如下:
**限制1:在沒有編寫GROUP BY子句的時候(全表一組),那麼SELECT子句之中只允許出現統計函式,不允許出現任何的其他欄位
Wrong:
SELECT COUNT(empno),ename FROM emp ;
**限制2:在使用GROUP BY子句分組的時候,SELECT子句只允許出現分組欄位和統計欄位,其他欄位不允許出現
Wrong:
SELECT job,COUNT(empno),ename FROM emp GROUP BY job;
**限制3:統計函式允許巢狀查詢,但是巢狀後的統計查詢中,SELECT子句裡面不允許出現任何的欄位,包括分組欄位,只能夠使用巢狀的統計函式
Wrong:
SELECT deptno,MAX(AVG(sal)) FROM emp GROUP BY deptno;

範例:查詢每個部門的名稱、人數、平均工資
**確定要使用的資料表:
  |-dept表:部門名稱
  |-emp表:統計出人數、平均工資
**確定已知的關聯欄位:
  |-僱員與部門:emp.deptno=dept.deptno
第一步:查詢每個僱員的編號、工資、部門名稱
SELECT e.empno,d.dname,e.sal FROM emp e,dept d WHERE e.deptno=d.deptno;
第二步:通過以上的查詢可以發現在dname欄位上出現了重複資料,有重複資料才可以分組,另外,明確要求按部門名稱分組
SELECT d.dname,COUNT(e.empno),AVG(e.sal) FROM emp e,dept d WHERE e.deptno(+)=d.deptno GROUP BY d.dname;
以上程式最大的特點是針對於一個多表查詢的結果進行的分組,是行列構成,所以可以理解為一張臨時資料表

範例:查詢出每個部門的編號、名稱、位置、部門人數、平均服務年限
第一步:查詢出每個部門的編號、名稱、位置、僱員編號、僱用日期
SELECT d.deptno,d.dname,d.loc,e.empno,e.hiredate FROM emp e,dept d WHERE e.deptno(+)=d.deptno;
第二步:三個欄位分組
SELECT d.deptno,d.dname,d.loc,COUNT(e.empno),AVG(MONTHS_BETWEEN(SYSDATE,e.hiredate)/12) year FROM emp e,dept d WHERE e.deptno(+)=d.deptno GROUP BY d.deptno,d.dname,d.loc;
多欄位分組,只有多個列的資料完全重複的時候才可以使用

範例:要求查詢出平均工資高於2000的職位名稱以及平均工資
SELECT [DISTINCT] 分組欄位 [別名],分組欄位 [別名],...|統計函式
,...FROM 表名稱 [別名] [WHERE 過濾條件] [GROUP BY 分組欄位,分組欄位...] [HAVING 分組後的過濾條件] [ORDER BY 欄位 [ASC|DESC],...,欄位 [ASC|DESC],];
先FROM,再WHERE,再GROUP BY,再HAVING,再SELECT,最後ORDER
實現分組後的過濾:
SELECT job,AVG(sal) FROM emp GROUP BY job HAVING AVG(sal)>2000;

注意:關於HAVING和WHERE的區別?
**WHERE發生在GROUP BY之前,屬於分組前的篩選
**HAVING發生在GROUP BY之後,是針對於分組後的資料進行篩選
WHERE子句不允許使用統計函式,HAVING允許使用統計函式

範例:顯示非銷售人員工作名稱以及從事同一工作僱員的月工資總和,並且要滿足從事同一工作的僱員的月工資合計大於5000,輸出結果按月工資的合計升序排列
第一步:顯示非銷售人員
SELECT * FROM emp WHERE job<>'SALESMAN';
第二步:按照工作分組,統計出每個工作的工資總和
SELECT job,SUM(sal) FROM emp WHERE job<>'SALESMAN' GROUP BY job;
第三步:才有工資總和大於5000的才進行顯示
SELECT job,SUM(sal) FROM emp WHERE job<>'SALESMAN' GROUP BY job HAVING SUM(sal)>5000;
第四步:資料按照月工資升序排列
SELECT job,SUM(sal) sum FROM emp WHERE job<>'SALESMAN' GROUP BY job HAVING SUM(sal)>5000 ORDER BY sum ASC;

思考題:統計公司所有領取佣金與不領取佣金的僱員人數、平均工資
查詢1:查詢領取佣金的僱員人數和平均工資
SELECT '領取佣金' title,COUNT(empno),AVG(sal) FROM emp WHERE conn IS NOT NULL;
查詢2:查詢不領取佣金的僱員人數和平均工資
SELECT '不領取佣金' title,COUNT(empno),AVG(sal) FROM emp WHERE conn IS NULL;
以上查詢結果結構相同,連線
SELECT '領取佣金' title,COUNT(empno),AVG(sal) FROM emp WHERE conn IS NOT NULL UNION SELECT '不領取佣金' title,COUNT(empno),AVG(sal) FROM emp WHERE conn IS NULL;
在整個分組裡面注意,只有在基數固定的時候才可能分組