I have a list of records, by multiple UserID's.
TableID UserID Status
------------------------
1 3 3
2 4 3
3 3 4
4 4 3
5 5 4
6 5 3
I'm trying to get all the UserID's where the most recent record for them (TableID) has a status of 4. From the example, it should return just 1 record : TableID 3, UserID 3.
UserID 5 should not be returned, as although they have a Status of 4, the most recent entry for them was Status 3.
I've tried this:-
await _context.Orders!
.GroupBy(u => u.UserID)
.Select(g => g.OrderBy(x => x.TableID).Where(x => x.Status == 4).FirstOrDefault())
.ToListAsync();
But this is returning any UserID that has a Status of 4, even though it's not the most recent record.
1 Answer 1
You need to put the Where after the Select. The OrderBy also needs to be Descending.
await _context.Orders!
.GroupBy(u => u.UserID)
.Select(g => g.OrderByDescending(x => x.TableID).FirstOrDefault())
.Where(x => x.Status == 4))
.ToListAsync();
However an ongoing bug in EF Core may cause this type of query to fail.
3 Comments
Explore related questions
See similar questions with these tags.
LAST_VALUE(Status) OVER (PARTITION BY User ID ORDER BY TableID)to get the last status per user.GroupByfollowed bySelectcontaining aFirstOrDefaultusually results in aROW_NUMBERstyle query.LAST_VALUEwhich returns the actual result. Especially ifStatusis covered by an index. I see the current efforts to introduce Window functions) go through GroupBy+SelectMany though, so I wouldn't be surprised if.SelectMany(........g....Last()was translated toLAST_VALUEat some point. I'd rather useFromSqlRaweven thenLAST_VALUEuses a worktable under the hood, so is actually less efficient whne you only need the last row. And an index overStatuswon't help you because theWHEREis after the window function. See dbfiddle.uk/RT3g9AIh note how the index is just scanned and re-sorted.INDEX ix (UserID, TableID, Status)the second query cost is0.003whileROW_NUMBERremains 0.014.