如何对记录进行分组并仅检索具有前 N 条记录的第一组
How to group records and retrieve only first group with top N records
我有以下记录集
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
为NULL
的记录,然后按CreatedDateTime
对过滤后的记录进行排序,然后按ClientName
分组,然后取前5来自第一个 组的记录 。
根据上面给定的记录集,它应该 return ClientName 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> 查询returns客户端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]
您必须像这样投影小组结果:
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();
首先,通常 OrderBy
如果在 Queryable
实现中跟随 GroupBy
将 LINQ 查询转换为 SQL.[=18=,则通常 OrderBy
没有效果(被忽略) ]
其次,EF Core 目前不会将 GroupBy
查询转换为 SQL,而是在内存中处理它们(所谓的 client evaluation),这使得它们非常低效。考虑到这一点,您最好将工作分成两个查询 - 一个获取第一组的 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();
我有以下记录集
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
为NULL
的记录,然后按CreatedDateTime
对过滤后的记录进行排序,然后按ClientName
分组,然后取前5来自第一个 组的记录 。
根据上面给定的记录集,它应该 return ClientName B
这是我的查询
var result = await _DBContext.BatchRequests
.Where(x => x.BatchID.HasValue == false)
.OrderBy(x => x.CreatedDateTime)
.GroupBy(x => x.ClientName)
.FirstAsync();
问题
1> 查询returns客户端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]
您必须像这样投影小组结果:
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();
首先,通常 OrderBy
如果在 Queryable
实现中跟随 GroupBy
将 LINQ 查询转换为 SQL.[=18=,则通常 OrderBy
没有效果(被忽略) ]
其次,EF Core 目前不会将 GroupBy
查询转换为 SQL,而是在内存中处理它们(所谓的 client evaluation),这使得它们非常低效。考虑到这一点,您最好将工作分成两个查询 - 一个获取第一组的 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();