如何对记录进行分组并仅检索前N条记录的第一组

4

我有以下的记录集

ID          BatchID     ClientName           CreatedDateTime
----------- -------------- --------------- -----------------------
1           NULL           B             2018-02-16 19:07:46.320
2           NULL           B             2018-02-16 19:07:46.320
3           NULL           B             2018-02-16 19:07:46.597
4           NULL           B             2018-02-16 19:07:46.597
5           NULL           B             2018-02-16 19:10:10.260
6           NULL           B             2018-02-16 19:10:10.260
7           NULL           B             2018-02-16 19:21:34.303
8           NULL           B             2018-02-16 19:21:34.303
9           NULL           B             2018-02-16 19:21:44.780
10          NULL           B             2018-02-16 19:21:44.780
11          NULL           A             2018-02-16 19:24:35.623
12          NULL           A             2018-02-16 19:24:35.623
13          NULL           A             2018-02-16 19:24:42.867
14          NULL           A             2018-02-16 19:24:42.867

我正在使用EF Core中的LINQ to SQL技术。 我想要过滤那些BatchID为空的记录,然后按照CreatedDateTime排序,再按ClientName分组,最后从第一组中取出前5条记录。 根据上面给定的记录集,它应该返回客户名为B的Id为1,2,3,4,5的记录。 所以这是我的查询:
 var result = await _DBContext.BatchRequests
                .Where(x => x.BatchID.HasValue == false)
                .OrderBy(x => x.CreatedDateTime)
                .GroupBy(x => x.ClientName)
                .FirstAsync();

问题
1> 查询返回客户端 A
2> 如何只取前5条记录

更新 1

SQL Profiler 显示如下,甚至都不在 SQL 中分组

SELECT [x].[ID], [x].[BatchID], [x].[ClientName], [x].[CreatedDateTime]
FROM [BatchRequests] AS [x]
WHERE CASE
    WHEN [x].[BatchID] IS NULL
    THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END <> 0
ORDER BY [x].[ClientName]

你的 OrderByGroupBy 之后没有太多意义 - 你必须对分组进行排序。那么你想如何对分组进行排序呢?(另外,一个简单的 x.BatchID == null 可能会产生更好的 SQL。) - NetMage
FYI,EF Core与LINQ to SQL或EF6没有任何共同之处。例如,正如您已经注意到的那样,它目前无法将“GroupBy”查询转换为SQL。 - Ivan Stoev
分组必须在 SQL 中完成。将所有记录检索到内存中并在内存中进行分组,然后只取前 N 条记录有什么用呢? - LP13
你将不得不等待EF Core 2.1版本。这也是我认为EF Core还没有准备好用于生产的原因之一。 - NetMage
2个回答

4

首先,通常情况下,在Queryable实现的LINQ查询中,如果在GroupBy后面跟随OrderByOrderBy则没有效果(被忽略)。

其次,EF Core目前不会将GroupBy查询转换为SQL,而是在内存中处理它们(所谓的客户端评估),这使它们变得非常低效。考虑到这一点,你最好将工作分成两个查询 - 一个查询获取第一组的ClientName,另一个查询获取所需结果:

var baseQuery = _DBContext.BatchRequests
    .Where(x => x.BatchId == null)
    .OrderBy(x => x.CreatedDateTime);

var clientName = await baseQuery
    .Select(x => x.ClientName)
    .FirstOrDefaultAsync();

var result = await baseQuery
    .Where(x => x.ClientName == clientName)
    .Take(5)
    .ToListAsync();

实际上你可以将这两个查询合并,但我不确定它是否更加高效(可能会更差):

var baseQuery = _DBContext.BatchRequests
    .Where(x => x.BatchId == null)
    .OrderBy(x => x.CreatedDateTime);

var result = await baseQuery
    .Where(x => x.ClientName == baseQuery.Select(y => y.ClientName).FirstOrDefault())
    .Take(5)
    .ToListAsync();

2
您需要像这样展示小组结果:

您将需要像这样展示小组结果:

result = await _DBContext.BatchRequests
            .Where(x => x.BatchID.HasValue == false)
            .OrderBy(x => x.CreatedDateTime)
            .ThenBy(x => x.ClientName)
            .GroupBy(x => x.ClientName)
            .Select( x => new { ClientName= x.ClientName,
                                 TopFive = x.Take(5)
                         })
            .FirstAsync();

没有起作用。它产生了相同的结果并返回客户端B。事实上,SQL分析器显示的SQL与我在上面发布的查询完全相同。 - LP13
你确定这就是所生成的 SQL 语句吗? - Ehsan Sajjad
是的,正如有人指出的那样,当您使用group by时,order by没有影响。 - LP13

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接