主要用於對數據集的的數據進行彙總統計等操作,基本是聚合函數。
聚合的基本理念:不是返回所有指定的行,而是返回一行計算得到的值(前面指定的行
的某些數據的彙總)。它們彙總了原始數據集。
1、計算總數、平均值
2、統計分析
3、解決聚合問題
4、創建動態的交叉查詢
一、簡單聚合
在SQL查詢的邏輯流程中,聚合函數是在From子句和Where子句之後執行的,這
意味着無須使用子查詢就可以在彙總(使用聚合函數)前對數據進行組裝和篩選。
基本聚合(函數)
聚合函數
支持的數據類型
描述
sum( )
Numeric
計算指定列中所有非空值的總和
avg()
numeric
計算指定列中所有非空值的平均值
min()
numeric、string、datetime
返回指定列中最小的數字或根據排序規則返回最前面的日期或字符串
max()
numeric、string、datetime
返回指定列中最大的數字或根據排序規則返回最前面的日期或字符串
count( [distinct] *)
任何基於行的數據類型
計算結果集中的總行數,
count_big( [distinct] *)
任何基於行的數據類型
與count類似,但是其返回類型是binint比count大
使用一般聚合函數時的規則:
1、由於現在SQL返回數據庫中的信息,而不是建立一個由行組成的記錄集,因此查詢包含
聚合函數時,每一列(列列表、表達式、或order by中的列)都必須參與聚合函數的計算。
2、聚合選項distinct的作用與Select distinct 相同,但聚合選項中的distinct消除重複的
值而不是重複的行。
注:count( distinct * )是非法的,必須指定特定的列。
count(*)計算數據集的總行數,但count(clomun名)計算在指定列中有值的總行數
由於聚合函數屬於表達式,因此結果中沒有列名,最好指定列名
二、在結果集中分組(使用group by )
group by 子句將根據特定列中的值,將數據集劃分成子集。將數據劃分成子集後,再
對每個子集執行聚合函數,最後由聚合函數生成數據(一般是每個子集佔一行。)
如果group by 子句有多列,則是根據這些列的值完全相同的行分爲一組,只要group gy
指定的任何一列的值不同,都不是同一分組。
1、簡單分組
如:根據Category的值的不同分組,相同的爲一值,每個分組根據聚合函數,會生成
一行彙總數據
<span style="font-family:SimSun;font-size:14px;">Select Category,
count(*) as [COUNT],
Sum(Amount) as [Sum]
Avg(Amount) as [Avg]
Min(Amount) as [Min]
From RawData
group by Category</span>
這上面是採用了分組的描述信息進行了分組,所以不需要另外添加分組的描述信息。
但是一般在大型關係數據庫中很少直接使用分組的描述信息作爲分組依據,這就需要
額外添加分組描述信息。這就需要使用子查詢和聯接來實現。
三、聚合查詢(5種常用的聚合問題及解決方案)
1、包含分組依據描述
下面的實例試圖返回一個沒有在group by中出現的列。(也稱百聚合描述列)
有兩種解決方案:1、在group by 子句中包容額外的列(使用聯接)
2、在子查詢中執行聚合函數,並在外部查詢中包含額外的列(使用聯接)
其中這兩個方案一般都會用到聯接。。
方案1:
<span style="font-family:SimSun;font-size:14px;">Select Category,Categoryname
sum(Amount) as [Sum]
avg(amount) as [Avg]
from RawData R
inner join RowCategory C on R.CategoryID=C.RowCategoryID
group by Category,C.Categoryname
order by Category,C.Categoryname</span>
方案2:在子查詢中執行聚合函數,並在外部查詢中包含額外的列
<span style="font-family:SimSun;font-size:14px;">Select SQ.Category,Categoryname,SQ.[Sum],SQ.[Avg]
from
(
Select Category
sum(Amount) as [Sum]
avg(amount) as [Avg]
from RawData R
group by Category
) as SQ
inner join RowCategory C on SQ.CategoryID=C.RowCategoryID
order by SQ.Category,C.Categoryname</span>
2、包含所有的分組依據值
Group by 分組是在where子句之後進行的。
如果查詢需要返回所有分組依據列的值,但如果要顯示where過濾的行,
可使用group by all 選項返回所有分組依據值。
而不管where子句如何。
如:
<span style="font-family:SimSun;font-size:14px;">select bmname 部門名稱,count(bmname) 有工資的員工總數,
sum(A.basic_gz+A.jiaban_gz+A.jiangjin) 部門工資 from gongzi A
inner join yuangong B on A.ygid=B.id
inner join bumen C on B.bmID=C.id
where bmname='管理部'
group by all bmname</span>
結果:
部門名稱 有工資的員工總數 部門工資
管理部 1 702
技術部 0 NULL
客戶部 0 NULL
銷售部 0 NULL
注:如果不加all 結果爲
部門名稱 有工資的員工總數 部門工資
管理部 1 702
如果沒有where 條件結果爲
部門名稱 有工資的員工總數 部門工資
管理部 1 702
技術部 2 5469
客戶部 1 1878
銷售部 1 2200
3、嵌套聚合
對聚合過的結果集,再進行聚合查詢
如:根據每種類別在每年/每季度的銷售情況,求每年每季度銷售最好的類別的銷售
情況信息。
1、先根據種類以及每年/季度進行分組,並調用相關的聚合函數
這樣就得到了不同種類在每年/每季度的銷售情況
2、對上一個結果集,根據每年/每季度進行分組,並計算每個分組中銷售最好的。
SQL語句:
--根據每年每季度分組,求出銷售最多的一個分組。這裏沒有包含類別信息,如果需要
添加,可以通過再聯接一個查詢實現(下面會介紹到)
<span style="font-family:SimSun;font-size:14px;">Select Y,Q,Max(SQ.[SUM]) as MaxSum
from
(--求出每年每季度不同類型的產品銷售情況
select Category ,Year(SalesDate) as Y, DatePart(q,SalesDate) as Q,sum(Amount) as [SUM]
from RowData group by Category,Year(SalesDate),DatePart(q,SalesDate)
) as SQ
group by Y,Q
order by Y,Q</span>
4、包含詳細描述
一般通過子查詢來實現(並使用聯接),使用group by 會導致分組的不同,如果有多
列與一列分組效果是不一樣的。多列必須這些列值全部相同纔會成爲一個分組,這樣如果只
是爲了添加顯示依據單列分組中的某些信息,會使原來的分組發生變換,就得不到應有的信
息。
5、篩選分組結果
SQL Select 語句的執行順序
1、From子句使用數據源組裝數據集
2、Where子句根據條件限制返回的行
3、Group By 子句組裝數據子集
4、對每個分組執行聚合函數
5、having 子句篩選數據子集
6、計算表達式
7、Order By 子句對結果進行排序
SQL Server使用Having 子句來篩選分組
如:
--根據每年每季度分組,求出銷售最多的一個分組。這裏沒有包含類別信息,如果需要
添加,可以通過再聯接一個查詢實現
Select Y,Q,Max(SQ.[SUM]) as MaxSum
from
(--求出每年每季度不同類型的產品銷售情況
<span style="font-family:SimSun;font-size:14px;">select Category ,Year(SalesDate) as Y, DatePart(q,SalesDate) as Q,sum(Amount)
as [SUM]
from RowData group by Category,Year(SalesDate),DatePart(q,SalesDate)
) as SQ
group by Y,Q
having avg(Amount)>25
order by Y,Q</span>
1.Group By 子句用於對結果集進行分組,並對每一組數據進行彙總計算。
語法格式:
Group By [列名] [HAVING 條件表達式]
Group By按“列名”指定的列進行分組,將該列列值相同的記錄組成一組,並對每一組進行彙總計算。每一組生成一條記錄。若有“HAVING 條件表達式”,則表示對生成的組進行篩選。
假如,TableX 表包含:
--------------------------------
ColumnA ColumnB ColumnC
1 abc 5
1 def 4
1 ghi 9
2 jkl 8
2 mno 3
如果 ColumnA 是組合列,則結果集中最終將有兩行,其中一行彙總值 1 的信息,而另一行彙總值 2 的信息。
如果 ColumnA 是組合列,要引用 ColumnB 或 ColumnC,這兩列必須是能爲 ColumnA 中的每個值返回單個值的聚合函數中的參數。選擇列表中可以包含諸如 MAX (ColumnB)、SUM (ColumnC) 或 AVG (ColumnC) 之類的表達式:
<span style="font-family:SimSun;font-size:14px;">SELECT ColumnA,
MAX(ColumnB) AS MaxB,
SUM(ColumnC) AS SumC
FROM TableX
GROUP BY ColumnA
</span>
此選擇語句返回兩行,爲 ColumnA 中的每個唯一值各返回一行:
ColumnA MaxB SumC
----------- ---- -----------
1 ghi 18
2 mno 11
(2 row(s) affected)
但是,選擇列表中不能只包含 ColumnB 表達式:
<span style="font-family:SimSun;font-size:14px;">SELECT
ColumnA,
ColumnB,
SUM(ColumnC) AS SumC
FROM TableX
GROUP BY ColumnA</span>
由於 GROUP BY 只能返回一行,該行在 ColumnA 中的值爲 1,因此無法返回與 ColumnA 中的值 1 關聯的 ColumnB 中的三個值(abc、def 和 ghi)。
不能對 ntext、text、image 或 bit 列使用 GROUP BY 或 HAVING,除非它們所在的函數返回的值屬於其他數據類型。這樣的函數包括 SUBSTRING 和 CAST。
四、範圍分組查詢(group by, case)
需求:查詢在指定年齡段的人數<span style="font-family:SimSun;font-size:14px;">select case when age>1 and age <26 then 1
when age>25 and age <27 then 2
else 0 end as stage ,count(*) as population from student
group by case when age>1 and age <26 then 1
when age>25 and age <27 then 2
else 0 end</span>
結果
stage population
1 1 2
2 2 5
可通過stage的值區分該條記錄是屬於哪個年齡段
五、sql多表分組查詢
一般group by 放在查詢語句的最外邊,如果外層查詢列包含了非聚集函數也不在group by子查詢裏面就在內層查詢裏面使用group by
<span style="font-family:SimSun;font-size:14px;">select * from
(
select t0=CONVERT(VARCHAR(10),[TimeStamp],120)
from table0 S
INNER JOIN ACDGroupMember M on
S.LoginID=M.AgentID
WHERE M.ACDGroupID=10016 AND S.TimeStamp BETWEEN '2012-10-2' AND '2012-11-2'
group by CONVERT(VARCHAR(10),[TimeStamp],120)
)a
left join
(
select t1= COUNT(M.AgentID),t2=CONVERT(VARCHAR(10),[TimeStamp],120)
from table1 S
INNER JOIN ACDGroupMember M on
S.LoginID=M.AgentID
WHERE M.ACDGroupID=10016 AND S.TimeStamp BETWEEN '2012-10-2' AND '2012-11-2'
group by CONVERT(VARCHAR(10),[TimeStamp],120)
)b on t0=t2</span>