2017-05-27 3 views
1

は(値がエンティティとフィールドの偽だけでなく、名前である)なしでの個別注文した要素を取得します:私は必要LINQの.GroupBy()データベースで、次の値を使用して製品>のIQueryable <考える

Id  | CategoryName | Price 
------ | -------------|------- 
1  | car   | 10000 
2  | boat   | 15000 
3  | boat   | 20000 
4  | car   | 5000 
5  | boat   | 30000 
6  | food   | 100 
7  | car   | 15000 
8  | food   | 200 

これをIQueryableに変換する<Product>をIOrderedQueryableに変更<Product>カテゴリ内で最も高価な製品の値を価格順にソートしたもの。だから、次のようになります。のIQueryableは、基礎となるSQLクエリでグループ化と並べ替えを実行することができます(そして実際のテーブルには、値をソートする方法をグループでより複雑なのcriteriasで約10kの行を含む)として

Id  | CategoryName | Price 
------ | -------------|------- 
5  | boat   | 30000 
7  | car   | 15000 
8  | food   | 200 

、ここで重要なのはのパフォーマンスです。 GROUP BYおよびネストされた選択(長いク​​エリの結果は、正しい行を選択し、MAX(p.Price)を計算するために、このソリューション

IQueryable<Product> queryable = ...; 
var result = queryable 
    .GroupBy(
     x => x.CategoryName, 
     (_, productsInGroup) => productsInGroup 
      .FirstOrDefault(x => x.Price == productsInGroup.Max(p => p.Price)) 
    .OrderByDescending(x => x.Price); 

私はすでにのように見える作業ソリューションを持っていますグループなど)

GroupByなしでも実行できますか? 私が何かしたいのですが:、

Id  | CategoryName | Price 
------ | -------------|------- 
5  | boat   | 30000 
3  | boat   | 20000 
7  | car   | 15000 
2  | boat   | 15000 
1  | car   | 10000 
4  | car   | 5000 
8  | food   | 200 
6  | food   | 100 

してからちょうど何とか行3,2,1を除外する:このような問合せは、最初の降順で値をソートなるように

var result = queryable 
    .OrderByDescending(x => x.Price) 
    .ExcludeRowsWithDuplicateCategoryName(); // Distinct by predicate 

を上記の行にすでに存在するCategoryNameを持つので、4,6となります。

どうすればよいですか?私はポストにクエリを伝えることができるものから、

+0

GROUP BYの問題点を教えてください。クエリはどのくらいの期間かかりますか? SQLプロファイラでクエリを分析し、適切なインデックスを追加しましたか? 10k行は小さいです。必要に応じてそれらをすべてメモリに読み込みます。 – Phil

+0

これはエンティティに対するlinqなので、価格が – user6144226

+0

で注文されたRANK/ROW_NUMBERカテゴリに分割されたクエリを必要とする可能性があります。@Philページングされたクエリを実行するには1.5-2秒かかる(行をスキップして別の行を取ります) 。この例の* Price *で表される値は、他のいくつかのテーブルを使用する複雑なルールによって計算され、CategoryNameは実際には関連テーブルの列です。いくつかのインデックスが存在しますが、正直言ってSQLプロファイラは使用していません。それはパフォーマンスを向上させることができると思います。 –

答えて

1

: まずグループ

productsInGroup.Max(p => p.Price) 

で最高の価格を見つける、その後のマッチング価格で最初の要素を検索します。あなたが実際にして、グループをスキップすることができますが、価格で注文後にグループからの最初の要素を取るために単純かもしれない場合

FirstOrDefault(x => x.Price == productsInGroup.Max(p => p.Price)) 

わかりません。このような

var result = Products.GroupBy(f => f.CategoryName).Select(gr => gr.OrderByDescending(p => p.Price).First()); 
2

私の心に来る唯一の選択肢は自己抗比較条件(またはNOT EXISTSベースのクエリ)とへの参加を使用することです:

var result = queryable 
    .Where(x => !queryable.Any(y => y.CategoryName == x.CategoryName && y.Price > x.Price)) 
    .OrderByDescending(x => x.Price) 
    .ToList(); 

それはよりパフォーマンスかないのかどうかが依存します具体的なクエリ可能とデータベーステーブルのインデックス。

これは、上記グループごとの最大の価格で2つ以上の要素が存在する場合、完全に同等では以下のように追加の条件を必要とするので、それは、カテゴリごとに複数のレコードを返しますので、完全に同等ではないことを言及する価値があります:

y => y.CategoryName == x.CategoryName && 
    (y.Price > x.Price || (y.Price == x.Price && y.Id > x.Id)) 
関連する問題