有朋友反饋說我提供的sample不能編譯。大概是版本的問題,可以到
http://msdn2.microsoft.com/en-us/bb330936.aspx
下載for beta1的版本。本節(jié)接著講groupby。
上一節(jié),我們講了如何理解groupby返回的結(jié)果。本節(jié)會延這個思路闡述下去。先來看下面的例子
GroupBy操作中Select的匿名類
????????????
var
?q?
=
?
from
?p?
in
?db.Products
????????????????????
group
?p?
by
?p.CategoryID?
into
?g
????????????????????
select
?new?{?CategoryID?
=
?g.
Key
,?g?};
本例中,select操作中使用了匿名類。本系列中第一次提到匿名類是在
http://www.cnblogs.com/126/archive/2006/12/20/503519.html
?一文中。本文將再一次,闡述匿名類的理解。所謂匿名類,其實(shí)質(zhì),并不是匿名,而是編譯器幫你去創(chuàng)建了這么一個類,在用戶看來,好像并沒有去創(chuàng)建,此所謂匿名類。也就是說,編譯器在編譯時,還是有這個類的,這個類是編譯器自己創(chuàng)建的,其名稱是編譯器界定的。 在上例的匿名類中,有2個property,一個叫CategoryID, 一個叫g(shù)。 大家要注意了,這個匿名類,其實(shí)質(zhì)是對返回結(jié)果重新進(jìn)行了包裝。而那個叫做g的property,就封裝了一個完整的分組。如圖,仔細(xì)比較和上篇圖的區(qū)別。
如果,使用下面的語句。
????????????
var
?q?
=
?
from
?p?
in
?db.Products
????????????????????
group
?p?
by
?p.CategoryID?
into
?g
????????????????????
select
?new?{?CategoryID?
=
?g.
Key
,GroupSet?
=
?g?};
只是把g重新命名為GroupSet.需要用下面的遍歷,獲取每個產(chǎn)品紀(jì)錄。
????????????
foreach
?(var?gp?
in
?q)
????????????
{
????????????????
if
?(gp.CategoryID?
==
?
7
)
????????????????
{???
????????????????????
foreach
?(var?p?
in
?gp.GroupSet)
????????????????????
{?
????????????????????
????????????????????}
????????????????}
????????????}
這里groupby的操作相對難理解些,主要原因,它包含了整個分組的具體信息,而不是簡單的求和,取平均值等。如果在最終結(jié)果中,也就是在select語句中,不包含g的全部信息,而只是g的聚合函數(shù)。又會是怎么樣的一番風(fēng)景呢?
GroupBy中的Max, Min, Sum, Average,Count
如果,只想取每類產(chǎn)品中,單價為最大,用T-sql該怎么辦呢?是不是要這么來寫
SELECT
?
MAX
(
[
t0
]
.
[
UnitPrice
]
)?
AS
?
[
MaxPrice
]
,?
[
t0
]
.
[
CategoryID
]
FROM
?
[
dbo
]
.
[
Products
]
?
AS
?
[
t0
]
GROUP
?
BY
?
[
t0
]
.
[
CategoryID
]
我們來看看,dlinq如何來做同樣的事情.如下,先按CategoryID歸類,然后,只取CategoryID值和同類產(chǎn)品中單價最大的。
????
var
?q?
=
????????
from
?p?
in
?db.Products
????????
group
?p?
by
?p.CategoryID?
into
?g
????????
select
?new?{
????????????g.
Key
,
????????????MaxPrice?
=
?g.
Max
(p?
=>
?p.UnitPrice)
????????};
在這里,Max函數(shù)只對每個分組進(jìn)行操作。我們來看看其結(jié)果
呀,這次,dlinq并沒有把組里所有的紀(jì)錄都取出來的嗎。(請參考
http://www.cnblogs.com/126/archive/2006/09/01/486388.html
一文中的方法,配置sample.) dlinq只是簡單做了統(tǒng)計(jì),并返回結(jié)果。
每類產(chǎn)品中,單價為最小的,
????
var
?q?
=
????????
from
?p?
in
?db.Products
????????
group
?p?
by
?p.CategoryID?
into
?g
????????
select
?new?{
????????????g.
Key
,
????????????MinPrice?
=
?g.
Min
(p?
=>
?p.UnitPrice)
????????};
每類產(chǎn)品的價格平均值
????
var
?q?
=
????????
from
?p?
in
?db.Products
????????
group
?p?
by
?p.CategoryID?
into
?g
????????
select
?new?{
????????????g.
Key
,
????????????AveragePrice?
=
?g.Average(p?
=>
?p.UnitPrice)
????????};
每類產(chǎn)品,價格之和
????
var
?q?
=
????????
from
?p?
in
?db.Products
????????
group
?p?
by
?p.CategoryID?
into
?g
????????
select
?new?{
????????????g.
Key
,
????????????TotalPrice?
=
?g.
Sum
(p?
=>
?p.UnitPrice)
????????};
各類產(chǎn)品,數(shù)量之和
????
var
?q?
=
????????
from
?p?
in
?db.Products
????????
group
?p?
by
?p.CategoryID?
into
?g
????????
select
?new?{
????????????g.
Key
,
????????????NumProducts?
=
?g.
Count
()
????????};
如果用OrderDetails表做統(tǒng)計(jì),會更好些,因?yàn)椋还饪梢越y(tǒng)計(jì)同一種產(chǎn)品,還可以統(tǒng)計(jì)同一訂單。
接著統(tǒng)計(jì),同各類產(chǎn)品中,斷貨的產(chǎn)品數(shù)量。使用下面的語句。
????
var
?q?
=
????????
from
?p?
in
?db.Products
????????
group
?p?
by
?p.CategoryID?
into
?g
????????
select
?new?{
????????????g.
Key
,
????????????NumProducts?
=
?g.
Count
(p?
=>
?p.Discontinued)
????????};
在這里,count函數(shù)里,使用了Lambda表達(dá)式。在上篇中,我們已經(jīng)闡述了g是一個組的概念。那在該Lambda表達(dá)式中的p,就代表這個組里的一個元素或?qū)ο螅茨骋粋€產(chǎn)品。還可以使用where條件來限制最終篩選結(jié)果
????
var
?q?
=
????????
from
?p?
in
?db.Products
????????
group
?p?
by
?p.CategoryID?
into
?g
????????
where
?g.
Count
()?
>=
?
10
????????
select
?new?{
????????????g.
Key
,
????????????ProductCount?
=
?g.
Count
()
????????};
這句在翻譯成sql語句時,欠套了一層,在最外層加了條件。
SELECT
?
[
t1
]
.
[
CategoryID
]
,?
[
t1
]
.
[
value2
]
?
AS
?
[
ProductCount
]
FROM
?(
????
SELECT
?
COUNT
(
*
)?
AS
?
[
value
]
,?
COUNT
(
*
)?
AS
?
[
value2
]
,?
[
t0
]
.
[
CategoryID
]
????
FROM
?
[
dbo
]
.
[
Products
]
?
AS
?
[
t0
]
????
GROUP
?
BY
?
[
t0
]
.
[
CategoryID
]
????)?
AS
?
[
t1
]
WHERE
?
[
t1
]
.
[
value
]
?
>=
?
@p0
--
?@p0:?Input?Int32?(Size?=?0;?Prec?=?0;?Scale?=?0)?[10]
--
?Context:?SqlProvider(Sql2005)?Model:?AttributedMetaModel?Build:?2.0.20612.0
GroupBy操作中GroupBy的匿名類
在
第一次談到匿名類
時,我們就提到不光Select操作可以使用匿名類,其他操作符也可以。但是,OrderBy不支持。請參考
C#3.0入門系列(六)-之OrderBy操作
當(dāng)用戶既想按產(chǎn)品的分類,又想按供應(yīng)商來做分組,該怎么辦呢。這時,我們就該使用匿名類。
????
var
?categories?
=
????????
from
?p?
in
?db.Products
????????
group
?p?
by
?new?{?p.CategoryID,?p.SupplierID?}?
into
?g
????????
select
?new?{g.
Key
,?g};
在by后面,new出來一個匿名類。這里,Key其實(shí)質(zhì)是一個類的對象,Key包含兩個Property,一個是CategoryID,再一個是SupplierID ,要想取到具體CategoryID的值,需要g.Key.CategoryID,才能訪問到。我們來看dlinq翻譯的T-sql語句。
SELECT
?
[
t0
]
.
[
SupplierID
]
,?
[
t0
]
.
[
CategoryID
]
FROM
?
[
dbo
]
.
[
Products
]
?
AS
?
[
t0
]
GROUP
?
BY
?
[
t0
]
.
[
CategoryID
]
,?
[
t0
]
.
[
SupplierID
]
--
?Context:?SqlProvider(Sql2005)?Model:?AttributedMetaModel?Build:?2.0.20612.0
先按CategoryID,再按SupplierID ,和匿名類中的循序一樣。
最后一個例子。
????
var
?categories?
=
????????
from
?p?
in
?db.Products
????????
group
?p?
by
?new?{?Criterion?
=
?p.UnitPrice?
>
?
10
?}?
into
?g
????????
select
?g;
按產(chǎn)品單價是否大于10分類。其結(jié)果為兩類,大于的是一類,小于及等于為另一類。好了,剩下的,大家自己多去領(lǐng)會。
?
TrackBack:
http://www.cnblogs.com/126/archive/2007/07/10/812621.html
C#3.0入門系列(九)-之GroupBy操作