LINQ to SQL группируется с помощью take - PullRequest
3 голосов
/ 03 сентября 2010

У меня есть таблица, которая выглядит следующим образом:

Id GroupId Value

и содержит около 100 строк

Как я могу вернуть 10 верхних строк для значения, но без дублирования GroupId?

Ответы [ 3 ]

3 голосов
/ 03 сентября 2010

Это должно сделать это:

var results = table
    .GroupBy(x => x.GroupId)
    .Select(x => new { Row = x, Value = x.Max(y => y.Value) })
    .OrderByDescending(x => x.Value)
    .Select(x => x.Row)
    .Take(10);

Редактировать : Изменено для возврата всего объекта.

1 голос
/ 03 сентября 2010

Этот получит полные значения строки (он работает для меня с примерами данных, которые я показываю ниже):

static void Main(string[] args)
{ 
    Whatever one = new Whatever() {GroupId = 1, Id = 1, Value = 2};
    Whatever two = new Whatever() { GroupId = 1, Id = 2, Value = 8 };
    Whatever three = new Whatever() { GroupId = 2, Id = 3, Value = 16 };
    Whatever four = new Whatever() { GroupId = 2, Id = 4, Value = 7 };
    Whatever five = new Whatever() { GroupId = 3, Id = 5, Value = 21 };
    Whatever six = new Whatever() { GroupId = 3, Id = 6, Value = 12 };
    Whatever seven = new Whatever() { GroupId = 4, Id = 7, Value = 5 };
    Whatever eight = new Whatever() { GroupId = 5, Id = 8, Value = 17 };
    Whatever nine = new Whatever() { GroupId = 6, Id = 9, Value = 13 };
    Whatever ten = new Whatever() { GroupId = 7, Id = 10, Value = 44 };

    List<Whatever> list = new List<Whatever>();
    list.Add(one);
    list.Add(two);
    list.Add(three);
    list.Add(four);
    list.Add(five);
    list.Add(six);
    list.Add(seven);
    list.Add(eight);
    list.Add(nine);
    list.Add(ten);

    var results = (from w in list
                   group w by w.GroupId into g
                   select new { GroupId = g.Key,
                                Value = g.Max(w => w.Value),
                                Id = g.OrderBy(w=>w.Value).Last().Id }).
                   OrderByDescending(w=>w.Value).Take(5);

    foreach (var r in results)
    {
        Console.WriteLine("GroupId = {0},
                           Id = {1},
                           Value = {2}",
                           r.GroupId, r.Id,  r.Value);
    }

}

Выход:

GroupId = 7, Id = 10, Value = 44
GroupId = 3, Id = 5, Value = 21
GroupId = 5, Id = 8, Value = 17
GroupId = 2, Id = 3, Value = 16
GroupId = 6, Id = 9, Value = 13
1 голос
/ 03 сентября 2010

Не уверен, что это переводится в LINQ-to-SQL, но вот идея из L2Obj

var query = (from foo in foos
                group foo by foo.GroupId into fg
                select fg.OrderByDescending(f => f.Value).First())
                .OrderByDescending(f => f.Value)
                .Take(10);

На английском языке он группируется по GroupId, а затем выбирает Foo с наибольшим значением из каждой группы, упорядочивает их, а затем занимает 10. Если что-нибудь, вы можете получить конкретный список ваших объектов из L2SQL, а затем выполнить Группировка в памяти не должна быть проблемой производительности / памяти, так как вы говорите, что есть только 100 строк.

Для LINQ-to-SQL, вы могли бы попробовать что-то вроде этого

var sqlQuery = (from foo in foos
                join y in
                    (from f2 in foos
                        join x in
                            (from f1 in foos
                            group f1 by f1.GroupId into vg
                            select new { GroupId = vg.Key, MaxVal = vg.Max(f => f.Value) })
                            on f2.GroupId equals x.GroupId
                        where f2.Value == x.MaxVal
                        group f2 by f2.GroupId into mg
                        select new { GroupId = mg.Key, MinId = mg.Min(f => f.Id) })
                on foo.Id equals y.MinId
                orderby foo.Value descending
                select foo).Take(10);

Это основано на запросе SQL для выполнения той же операции

Select top 10 f.*
From Foos f
Inner Join 
(Select f.GroupID, min(f.Id) as MinId
From Foos f
Inner Join
(Select GroupId, Max(Value) as MaxVal
From Foos
Group By GroupId) x
on f.GroupId = x.GroupId 
and f.Value = x.MaxVal
Group By f.GroupId) y
on f.Id = y.MinId
order by f.Value desc

Он в основном выполняет две группировки. Первый получает максимальное значение для каждой группы, второй получает минимальный идентификатор для каждой записи из каждой группы, которая имеет максимальное значение (в случае, если 2 записи в группе имеют одинаковое значение), а затем выбирает первые 10 записей.

...