はじめに
先日業務にて表題の件について調べたので共有します。
本記事は LINQ to Entities にて、テーブルデータをグルーピングしたのち、グループごとに列の最大値を持つレコードを抽出するという内容となっています。
本題
例えば下の表のように元テーブルのデータをName列でグルーピングし、グループごと(Nameごと)にScore列の最大値を持つレコードを抽出したい場合を想定します。
元テーブル
Id
Name
Score
Age
1
taro
60
20
2
hanako
90
19
3
hanako
50
19
4
taro
100
20
5
jiro
70
22
抽出したいデータ
Name
Score
Age
hanako
90
19
taro
100
20
jiro
70
22
SQL Server で書いた場合
サブクエリではGroupBy句によりName列でグルーピングし、Max関数によりグループごとのScore列の最大値を取得します。
メインクエリではサブクエリで取得したScore値を持つレコードを抽出します。
qiita.sql
Select Name, Score, Age From Table1 As T1 /* メインクエリ */
Where Score = (
Select Max(Score) From Table1 /* サブクエリ */
Group By Name Having Name = T1.Name
);
LINQ to Entities で書いた場合
group句でName列とAge列でグルーピングした結果を G1 に格納します。
select句でName列、Score列、Age列を持つ新しいオブジェクトを作成します。
Score列にはサブクエリにて取得した、グループごとにScore列の最大値を持つレコードを格納します。
※ T は任意のデータ型
qiita.cs
1: List<T> record = (from T1 in db.Table1
2: group T1 by new { /* グルーピングのKey要素にName列とAge列を追加 */
3: NAME = T1.Name,
4: AGE = T1.Age
5: } into G1 /* グルーピング後のデータセットをG1に格納する */
6: select new {
7: Name = G1.Key.NAME,
8: Score = (from T2 in G1 select T2.Score).Max(), /* サブクエリにてグループごとにScore列の最大値を持つレコードを抽出 */
9: Age = G1.Key.AGE
10: }).ToList();
補足
2行目の group句 の戻り値は IGrouping<TKey, TElement> のオブジェクトとなる。
6行目の select句 の戻り値は IQueryable<IGrouping<TKey, TElement>> のオブジェクトとなる。
10行目の ToListメソッド の戻り値は List<T> のオブジェクトとなる。
3, 4行目でグルーピングの Key要素に Name列と Age列を指定したことで、T1 は Name列, Age列でグルーピングされます。
また、7, 9行目のように TKey を指定することで TElement にアクセスすることができます。
ちなみに
group句 の Key要素 に Name列のみ を指定した場合、TKey を指定してアクセスできる TElement は Name列のみ となります。
また、IGrouping<TKey, TElement> のオブジェクトは基本的に二重リストで実現されているため、各グループのアイテムにアクセスするには二重ループによって反復処理する必要があります。
※以下のプログラムではデータセットのグルーピングのみを実装しています。
qiita.cs
1: var record = from T1 in db.Table1
2: group T1 by T1.Name
3: into G1
4: select G1;
5:
6: foreach(var itemKey in record)
7: {
8: foreach(var item in itemKey)
9: {
10: Console.WriteLine("{0} {1} {2}", item.Name, item.Score, item.Age);
11: // item.Name は itemKey.key としてもアクセスできます
12: }
13: }
14:
15: // OutPut
16: // taro 60 20
17: // hanako 90 19
18: // hanako 50 19
19: // taro 100 20
20: // jiro 70 22
さいごに
今回の記事内容に対して至らない点がありましたら、ご指摘いただけると幸いです。
最後までお読みいただきありがとうございました。
また逢う日まで。
参考文献
↧