[英]LINQ for getting the 5 latest records for each distinct name
I have been trying to get the 5 most recent records from a database with distinct names from the "Name" Column.我一直在尝试从数据库中获取 5 条最新记录,这些记录的名称与“名称”列不同。 Meaning I want the 5 latest records for each of the unique names in the table.
意思是我想要表中每个唯一名称的 5 个最新记录。
Here is a sample table:这是一个示例表:
id | Name | Status | Start | End <br />
1 | Bob | Pass | 2020-01-01 | 2020-01-01<br />
2 | Chris | Pass | 2020-01-01 | 2020-01-02<br />
3 | James | Fail | 2020-01-01 | 2020-01-03<br />
4 | Bob | Pass | 2020-01-01 | 2020-01-04<br />
5 | Chris | Fail | 2020-01-01 | 2020-01-05<br />
6 | Bob | Pass | 2020-01-01 | 2020-01-06<br />
7 | Bob | Fail | 2020-01-01 | 2020-01-07<br />
8 | Bob | Fail | 2020-01-01 | 2020-01-08<br />
9 | Chris | Pass | 2020-01-01 | 2020-01-09<br />
10 | Bob | Pass | 2020-01-01 | 2020-01-10<br />
I would expect the latest 5 Bob records (out of the 6 ), the 3 Chris records, and the one James record to be returned.我希望返回最新的 5 个 Bob 记录(共 6 个)、3 个 Chris 记录和一个 James 记录。
I have tried to methods so far:到目前为止,我已经尝试过方法:
// GET: api/Student/latestRecords
[HttpGet("latestRecords")]
public async Task<ActionResult<IEnumerable<Student>>> GetLatestRecordsOnAllStudent()
{
var distinctStudentNames = _context.Students.Select(x => x.name).Distinct();
IQueryable<Student> allRecords = new Student[] { }.AsQueryable();
foreach (string studentName in distinctStudentNames)
{
var newList = _context.Students.OrderByDescending(x => x.endTime).DistinctBy(y => y.name).Select( z => z).Take(5);
allRecords.Concat(newList);
}
return allRecords.ToList();*/
}
// GET: api/Student/latestRecords
[HttpGet("latestRecords")]
public async Task<ActionResult<IEnumerable<Student>>> GetLatestRecordsOnAllStudents()
{
var distinctStudentsNames = _context.Students.DistinctBy(x => x.name).OrderByDescending(x => x.endTime).Select(z => z).Take(5).ToList();
return distinctStudentsNames;
}
I would love it if method 2 would work, but I feel like I might be stepping on my own toes trying to do it all in one single call.如果方法 2 可行,我会很高兴,但我觉得我可能会踩到自己的脚趾,试图在一次调用中完成所有操作。 If anyone has some advice, it would be greatly appreciated.
如果有人有任何建议,将不胜感激。
As @NetMerge pointed out this won't work in EF Core, so I'll leave the answer here for now in case the OP wants to take a look at it anyway.正如@NetMerge 指出的那样,这在 EF Core 中不起作用,所以我暂时将答案留在这里,以防 OP 无论如何都想查看它。
Here's a sample class with just the two properties we're focusing, and your sample list.这是一个示例 class,其中仅包含我们关注的两个属性以及您的示例列表。
public class Student
{
public string Name { get; set; }
public DateTime End { get; set; }
}
var students = new List<Student>
{
new Student() { Name = "Bob", End = new DateTime(2020, 1, 1) },
new Student() { Name = "Chris", End = new DateTime(2020, 1, 2) },
new Student() { Name = "James", End = new DateTime(2020, 1, 3) },
new Student() { Name = "Bob", End = new DateTime(2020, 1, 4) },
new Student() { Name = "Chris", End = new DateTime(2020, 1, 5) },
new Student() { Name = "Bob", End = new DateTime(2020, 1, 6) },
new Student() { Name = "Bob", End = new DateTime(2020, 1, 7) },
new Student() { Name = "Bob", End = new DateTime(2020, 1, 8) },
new Student() { Name = "Chris", End = new DateTime(2020, 1, 9) },
new Student() { Name = "Bob", End = new DateTime(2020, 1, 10) }
};
You can do a GroupBy()
and then OrderByDescending()
the End
property, and take 5 from each.您可以执行
GroupBy()
,然后OrderByDescending()
的End
属性,并从每个属性中取 5 个。
var recentFiveForEachName = students
.GroupBy(x => x.Name, (key, g) => g.OrderByDescending(y => y.End).Take(5));
Since you are using EF Core, you are limited in what you can do with GroupBy
.由于您使用的是 EF Core,因此您可以使用
GroupBy
执行的操作受到限制。 Instead, you can replace GroupBy
with a sub-query that returns which records you want for each name
:相反,您可以将
GroupBy
替换为一个子查询,该子查询返回您想要的每个name
的记录:
var allRecords = from s in _context.Students
where (from s2 in _context.Students
where s2.name == s.name
orderby s2.endTime descending
select s2.id).Take(5).Contains(s.id)
orderby s.name, s.endTime descending
select s;
Or, if you prefer the fluent version:或者,如果您更喜欢流利的版本:
var allRecords2 = _context.Students.Where(s => _context.Students.Where(s2 => s2.name == s.name)
.OrderByDescending(s2 => s2.endTime)
.Select(s2 => s2.id)
.Take(5)
.Contains(s.id))
.OrderBy(s => s.name)
.ThenByDescending(s => s.endTime);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.