Sometimes, we need to select a record that has the maximum or minimum value from a group. Some examples are:
- We have a PersonOrders table and we want to find the last Order for each Person
- We have a UserOperations table and we need to find the first Operation for each User
- We have a Persons table and we need to find the person with maximum salary for each Department
Such scenarios are beautifully handled by TSQL’s Ranking_functions over partition by clauses. Here’s a typical example that uses Row_Number() function to assign a rank to each row per Person.
;With PersonOrderWithRank as ( Select *, Rnk = ROW_NUMBER() over (partition by PersonID order by OrderDate desc) from PersonOrders ) Select * from PersonOrderWithRank where Rnk=1
In LINQ, similar result can be achieved by using the let keyword. Here’s an example:
from p in PersonOrders //where conditions or joins with other tables to be included here group p by p.PersonID into grp let MaxOrderDatePerPerson = grp.Max ( g=>g.OrderDate ) from p in grp where p.OrderDate == MaxOrderDatePerPerson select p
Another more compact method would be to retrieve the first record in the grouping like this:
from p in PersonOrders //where conditions or joins with other tables to be included here group p by p.PersonID into grp select grp.OrderByDescending(g=>g.OrderDate).First()
The above LINQ approaches can be used for both LINQ To SQL as well as Entity Framework. Although the SQL and the LINQ approaches I described above are not exactly identical (since I used Row_Number() and not Rank() or Dense_Rank() ) but the purpose of this post is to provide an starting point to write similar queries using LINQ.
December 29, 2009 at 11:55 PM
LINQ: How to get the latest/last record with a group by clause « Mehroz’s Experiments…
Thank you for submitting this cool story – Trackback from DotNetShoutout…
February 12, 2010 at 4:29 AM
Thanks a ton! This was exactly what I needed!
April 18, 2010 at 1:21 PM
I need to convert the following sql query into LINQ: Can anybody help me.
SELECT*( SELECT ROW_NUMBER() OVER (PARTITION BY fieldname ORDER BY errordate Desc) AS ‘RowNo’,
id, dcn, fieldname, value, errordate, userid
FROM input_error where dcn=@dcn and corrected=’N') where RowNo=1
April 19, 2010 at 12:27 PM
@Miru,
So want to get the record that has the maximum error date per fieldName. Here’s the LINQ query:
from i in input_error
where i.Dcn = dcnVariable && i.Corrected = “N”
group i by i.FieldName into grp
let maxErrorDate = grp.Max( g=>g.ErrorDate)
from g in grp
where g.ErrorDate == maxErrorDate
select g
July 20, 2010 at 2:44 PM
Thank you very much. This article helped me a lot.
August 10, 2010 at 1:36 PM
Thanks a lot. I think it’s a common situation but your example was the only one that explain how to do it with linq.
I would have found it before…
Thanks a lot!
September 14, 2010 at 2:29 PM
Hi
I’m trying to get the record ID of the record that’s just been saved with Entity Framework. Is there a simple way to accomplish this?
… or is something like this viable?
CLIENTS LastestClient = (from c in ent.CLIENTS
select c).Last();
I’m still new to EF and can’t find what I’m looking for on the net.
September 18, 2010 at 8:57 AM
Nick,
EF automatically populates your business objects with the db-generated values after your call to SaveChanges(). Something like:
September 21, 2010 at 1:22 PM
Awesome.
Thanks
January 12, 2011 at 8:46 AM
I am using Silverlight with EF, and I need to add an Include(). When I modify your code as shown below, I get a null for the linked object X. It works fine when I don’t group. Can anyone help?
from p in PersonOrders.Include(“X”)
group p by p.PersonID into grp
let MaxOrderDatePerPerson = grp.Max ( g=>g.OrderDate )
from p in grp
where p.OrderDate == MaxOrderDatePerPerson
select p
February 1, 2011 at 3:40 PM
Jim,
Include(“X”) should be applied in the last. Have a look at this post from Alex that describes how you need to cast your query into
ObjectQuery<T>and then applyIncludein the last.March 18, 2011 at 4:11 PM
Wonderful!! Thanks a lot for providing such a simple and efficient solution. Have been searching the web for last 2 days and found here the perfect solution. Great work.
June 1, 2011 at 7:13 PM
Get the max date record fom List using the single LINQ query….!!!!!!!!!! ( objListView is the ILIST)
objListView = (from Record in objListView
where Record.COMPLETED_DATE == (from rcd in objListView select rcd).Max(a => a.COMPLETED_DATE)
select Record).ToList();
September 3, 2011 at 12:25 AM
Exactly what I needed. Thanks!
September 10, 2011 at 12:36 AM
Perfect. Thank you.
October 21, 2011 at 12:12 PM
hello