統計函數及分組查詢
1、統計函數
在之前曾看過count()函數,此函數功能可以統計表中的數據量,實際上這個也是一個統計函數,且常用的統計 函數 有如下幾個:
.Count():查詢表中的數據記錄;
.Avg():求出平均值;
.Sum(): 求出;
.Max():求出最大值;
.Min():求出最小值;
范例:測試Count/avg/sum函數
.統計出公司的所有雇員,每個月支付的平均工資和總工資.
select count(empNo), sum(sal), avg(sal) from emp;
select max(sal), min(sal) from emp;
注意點:關於Count()函數
count函數的主要功能是進行數據的統計,但是在進行數據統計的時候,如果一張表中沒有統計記錄,count()也會返回結果,只是這個數據是“0”。
select count(eName) from bonus;
如果使用的是其他函數,則有可能返回null,但是count永遠都會返回一個具體的數字,這一點以后在開發之中都有用。
2、分組統計
在對分組之前必須明確一點,什么情況下可能分組,例如:.公司的所有雇員,要求男性一組,女性一組,之后可以統計男性和女性的數量;
.按照年齡分組,18歲以上的分一組,18以下的分一組;
.按照地區分組:北京一組,上海一組,四川一組;
這些信息如果都保存在了數據庫中,肯定在數據的某一列上會存在重復的內容,例如:在性別分組的時候,性別肯定有重復,按照年齡分組(有一個范圍重復),按照地區分組有一個地區的信息重復。
所有分組之中有一個不成文的規定:當數據重復的時候分組才有意義,分組的關鍵字是Group by子句完成,此時sql語法如下:select [distinct] *|分組字段1[別名][,分組字段2[別名],...]|統計函數
from 表名稱[別名] [,表名稱[別名],...]
[where 條件(s)]
[Group by 分組字段1[分組字段2,...]
[Order by 排序字段 Asc|Desc [,排序字段 Asc|desc,..]
范例:按照部門編號分組,求出每個部門的人數,平均工資。
select deptNO count(empNo), avg(sal)
from emp
Group by deptNo;
但是現在一旦分組后,實際上對於語法上就會出現了新的限制,對於分組以下要求:
.分組函數可以在沒有分組的時候單獨使用,可是卻不能出現其他查詢字段。
select count(empNo) from emp;這樣可以
select empNo ,count(empNo) from emp 錯誤
還可以:select job, count(empNo), from emp
group by job;正確(驗證了不能出現其他查詢字段)
.分組函數允許嵌套,但是嵌套之后的分組函數的查詢之中不能出現任何的其他字段。
范例:按照職位分組,統計平均工資最高的工資
select 這里不能出現其他字段的查詢 max(avg(sal)) from emp group by job;
.如果現在要分組的話,則select子句之后,只能出現分組的字段和統計函數,其他的字段不能出現;
select job, count(empNo),avg(sal)
from emp group by job;
范例:查詢每個部門的名稱、位置、部門的人數、平均工資
select d.dName,e.empno, e.sal
from dept d, emp e
where d.deptNo=e.deptNo
按照上述查詢結果中,可以發現在dname字段上顯示除了重復的數據,按照之前對分組的理解,只要數據重復了,那么就有可能進行分組的查詢操作,但是此時與之前的分組不太一樣,之前的分組是針對於一張實體表進行的分組(emp,dept都屬於實體表),但是對於以上的數據是通過查詢結果顯示的,是一張臨時的虛擬表,但是不管是否是實體表還是虛擬表,只要有重復,那么直接進行分組。
select d.dname,count(e.empno),NVL(avg(e.sal), 0)
from dept d, emp e
where d.deptno= e.deptno(+)
group by d.dname;
之前的所有操作都是針對於單子段分組的,而實際上分組操作之中也可以是多字段分組。(多/單前提是要重復)
范例:select d.deptno,d.dname, d.loc, count(e.empno), NVL(avg(e.sal), 0)
from dept d, emp e
where d.deptno=e.deptno(+)
group by d.deptno, d.dname, d.loc;
范例:要求統計出每個部門的詳細信息,並且要求這些部門的平均工資高於2000。(之前唯一只有where限定查詢的語法,且where子句不能使用統計函數)
此時如果要對分組后的數據再次進行過濾,則要使用having子句完成,此時的SQL語法格式如下:
select [distinct] *|分組字段1[別名][,分組字段2[ 別名],...]|統計函數
from 表名稱[別名] [,表名稱[別名],...]
[where 條件(s)]
[Group by 分組字段1[分組字段2,...]
[Having分組后的過濾條件(可以使用統計函數)]
[Order by 排序字段 Asc|Desc [,排序字段 Asc|desc,..]
Select d.deptNO, d.dname,d.loc, count(e.empno) myCount, NVL(avg(e.sal)) mySal
from dept d, emp e
where d.deptno=e.deptno(+)
Group by d.deptno, d.dname, d.loc
Having avg(sal)>2000;
總結:where和Having的區別:
.where:是在執行Group by操作之前進行的過濾,表示從全部數據之中篩選出部分數據,在where中不能使用統計函數;
.Having:是在group by分組之后的再次過濾,可以在Having子句中使用統計函數;
-------------------------------------------------子查詢
子查詢=簡單查詢+限定查詢+多表查詢+ 統計查詢的綜合體,多表查詢效率很好,針對小型的數據量是不錯的選擇,大數據量下,多表查詢性能很差,但是最有利的子查詢可以替代多表查詢,實際上在開發中使用這種方式也很多。所謂子查詢就是在一個查詢之中嵌套了其他的查詢,嵌套子查詢之后的查詢SQL語法如下:
select [distinct] *|分組字段1[別名][,分組字段2[ 別名],...]|統計函數 (
select [distinct] *|分組字段1[別名][,分組字段2[ 別名],...]|統計函數
from 表名稱[別名] [,表名稱[別名],...]
[where 條件(s)]
[Group by 分組字段1[分組字段2,...]
[Having分組后的過濾條件(可以使用統計函數)]
[Order by 排序字段 Asc|Desc [,排序字段 Asc|desc,..] )
from 表名稱[別名] [,表名稱[別名],...] (
select [distinct] *|分組字段1[別名][,分組字段2[ 別名],...]|統計函數
from 表名稱[別名] [,表名稱[別名],...]
[where 條件(s)]
[Group by 分組字段1[分組字段2,...]
[Having分組后的過濾條件(可以使用統計函數)]
[Order by 排序字段 Asc|Desc [,排序字段 Asc|desc,..] )
[where 條件(s)] (
select [distinct] *|分組字段1[別名][,分組字段2[ 別名],...]|統計函數
from 表名稱[別名] [,表名稱[別名],...]
[where 條件(s)]
[Group by 分組字段1[分組字段2,...]
[Having分組后的過濾條件(可以使用統計函數)]
[Order by 排序字段 Asc|Desc [,排序字段 Asc|desc,..])
[Group by 分組字段1[分組字段2,...]
[Having分組后的過濾條件(可以使用統計函數)]
[Order by 排序字段 Asc|Desc [,排序字段Asc|desc,..]
理論上子查詢可以出現在查詢語句中的任意位置上,但是從個人而言,子查詢出現在where和from子句中較多:
總結:.where:子查詢一般只返回單行單列、多行單列 、單行多列的數據;
.from:子查詢返回的一般是多行多列的數據, 當作一張臨時表出現。
范例:select * from emp
where (sal, job)=(
select sal,job from emp
where ename='ALLEN');返回單行多列的結果
如果現在的子查詢返回的是多行單列數據的話,這個時候就需要使用三種判斷符判斷:IN、ANY、ALL;
1、IN操作符:用於指定一個子查詢的判斷范圍
這個操作符的使用實際上於前面的IN一樣,唯一不同的是,里面的范圍是由子查詢指定。
select * from emp
where sal IN (
select sal
from emp
where job='MANAGER');
但是在使用IN的時候還要注意NOT IN問題,在子查詢之中,如果一個內容是null,則不會查詢出任何結果。
2、ANY操作符:與每一個內容相匹配,有三種匹配形式
.=ANY: 功能與IN操作符是完全相同;
select * from emp
where sal= any( select sal
from emp
where job='MANAGER');
.>ANY: 比子查詢返回的記錄最小的還要大的數據;
select * from emp
where sal>any( select sal
from emp
where job='MANAGER');
.<ANY: 比子查詢返回的記錄最大的還要小的數據;
select * from emp
where sal<any( select sal
from emp
where job='MANAGER');
3、ALL操作符:與每一個內容相匹配,有兩種形式:
.>ALL:比子查詢中返回的最大的記錄還要大;
select * from emp
where sal<any( select sal
from emp
where job='MANAGER');
.<ALL:比子查詢中返回的最小的記錄還要小;
select * from emp
where sal<any( select sal
from emp
where job='MANAGER');
以上的所有子查詢都是Where子句中出現的,下面的是在from子句中出現的子查詢,這個子查詢一般返回的是多行多列的數據,當作一張臨時表的方式來處理。
范例:查詢出每個部門的編號,名稱,位置,部門人數,平均工資
第一種方法:多表方法:
select d.deptno, d.dname,d.loc, count(e.empno), avg(e.sal)
from emp e, dept d
where e.deptno(+)=d.deptno
group by d.deptno,d.dname, d.loc;
第二種方法:子查詢法:通過子查詢完成,所有的統計查詢只能在Group by中出現,所以在子查詢中負責統計數據,而在外部查詢中,負責將統計數據和dept表數據相統一。
select d.deptno ,d.dname,d.loc,temp.count,temp.avg
from dept d,(
select deptno dno, count(empno) count, avg(sal) avg
from emp
group by deptno) temp
where d.deptno= temp.dno(+);
大部分情況下,如果最終的查詢結果之中需要出現select子句,但是又不能直接使用統計函數的時候,就在子查詢中統計信息,即:有復雜統計的地方都需要子查詢。
-------------------------------------------