假設我們需要從兩張表中統計出熱門商圈,這兩張表內容如下:
- 上表是所有政區,商圈中的餐飲個數,名為FoodDistrict
- 下表是所有政區,商圈中的SPA個數,名為SPADistrict
現在要把這兩張表,根據政區和商圈合並,然后相加Counts,根據Counts的總大小排序,統計熱門商圈和熱門政區。
在這里僅討論合並的問題,以演示在SQLServer和C#中LINQ的實現方法:
通常,我們可以直接通過在SQLServer里面首先通過Union All,然后再通過GroupBy語句來執行查詢操作即可滿足要求,過程如下:
SELECT d.CityLocationId , d.CityLocationName , d.BusinessDistrctID , d.BusinessDistrctName , SUM(Counts) AS Counts FROM ( SELECT * FROM FoodDistrict UNION ALL SELECT * FROM SPADistrict ) d GROUP BY d.CityLocationId , d.CityLocationName , d.BusinessDistrctID , d.BusinessDistrctName ORDER BY Counts DESC
執行結果為:
這里面需要注意的是,Union和Union All的區別,Union會對相同的記錄去重,所以這里采用的是Union All,另外Union或者Union All的兩個字表或者查詢中,不能夠有Order By子句。一般是Union之后再進行Order By。
但是有些時候,以上兩張表可能存在與不同的數據庫中,或者即使存在同一個數據庫中,業務邏輯方面也不應該都放到數據庫中,否則容易會使得數據庫性能成為瓶頸。所以在某些時候,以上操作可能需要移到業務邏輯中處理。
在C#中,我們可能會先取回兩個List實體,這兩個實體分別從數據庫中獲得,在C#中,我們使用LINQ語句的聚合,分組也能實現SQLServer類似的功能。
private List<BusinessDistrictWithCountModel> CombineDistrict(List<BusinessDistrictWithCountModel> foodBusinessDistrict, List<BusinessDistrictWithCountModel> spaBusinessDistrict) { List<BusinessDistrictWithCountModel> result; result = new List<BusinessDistrictWithCountModel>(); result = foodBusinessDistrict.Concat(spaBusinessDistrict). GroupBy(x => new { x.CityLocationID, x.CityLocationName, x.BusinessDistrctID, x.BusinessDistrctName }) .Select(g=> new BusinessDistrictWithCountModel { CityLocationID = g.Key.CityLocationID, CityLocationName = g.Key.CityLocationName, BusinessDistrctID = g.Key.BusinessDistrctID, BusinessDistrctName = g.Key.BusinessDistrctName, ProductCount = g.Sum(a => a.ProductCount) }) .OrderByDescending(x => x.ProductCount) .ToList(); return result; }
在LINQ中將兩個集合合並有兩個方法,Union和Concat,其中Union會對集合中相同的元素進行去重,而Concat則不會。這兩個關鍵字分別對應SQLServer中的Union和Union All。
Linq中的GroupBy和SQLServer中的GoupBy也類似,將需要Group的字段放到一個匿名對象里,然后在緊接着的Select中,我們可以從key中拿到Group里的字段,然后還可以進行一些諸如Sum,Count等統計操作。
另外,在C#中將一個集合對象轉換為另外一個集合對象的時候,可以使用Select或者ConvertAll這兩個關鍵字,Select是LINQ里面的擴展方法,對於任何實現IEnumerable<>泛型接口的對象都可以使用,在.NET 3.5及以上平台上支持,並且和其他LINQ操作符一樣,他是延遲執行(lazy evaluation)的;而ConvertAll則是List<>對象的方法,在.NET 2.0及以上版本中均可以使用,它是立即執行,但是他們的作用相同,我們只需要傳入轉換的方法即可。