LINQ to SQL group by 和 take

发布于 2024-09-17 15:21:44 字数 118 浏览 6 评论 0原文

我有一个看起来像这样的表:

Id GroupId Value

它有大约 100 行

如何返回值的前 10 行但没有重复的 GroupId?

I have a table that looks like this:

Id GroupId Value

and it has about 100 rows

How can I return the top 10 rows for value but with no duplicating GroupId?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

自演自醉 2024-09-24 15:23:05

这将获得完整的行值(它对我来说适用于下面显示的示例数据):

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

This one will get the full row values (it's working for me with the sample data I show bellow):

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);
    }

}

Output:

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
你对谁都笑 2024-09-24 15:22:54

不确定这是否可以转换为 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 进行分组,然后从每个组中选择具有最高 Value 的 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

它基本上执行两个分组。第一个获取每个组的最大值,第二个获取每个组中具有最大值的每条记录的最小 ID(如果一组中的 2 条记录具有相同的值),然后选择前 10 条记录。

Not sure if this translates to LINQ-to-SQL, but here's an idea from 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);

In english, it groups on the GroupId and then selects the Foo with the highest Value from each group, orders those, and then takes 10. If anything, you could get a concrete list of your objects from L2SQL and then perform the grouping in memory, should not be a performance/memory issue since you say there are only 100 rows.

For LINQ-to-SQL, you might try something like this

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);

This is based on a SQL query to perform the same operation

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

It basically performs two groupings. The first gets the max value for each group, the second gets the min ID for each record from each group that has the max value (in case 2 records in a group have the same value), and then selects the top 10 records.

水染的天色ゝ 2024-09-24 15:22:43

这应该可以做到:

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);

编辑:修改以返回整个对象。

This should do it:

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);

Edit: Modified to return the entire object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文