50

I have a table with a datetime field. I want to retrieve a result set grouped by the month/year combination and the number of records that appear within that month/year. How can this be done in LINQ?

The closest I've been able to figure out is in TSQL:

select substring(mo,charindex(mo,'/'),50) from (
select mo=convert(varchar(2),month(created)) + '/' + convert(varchar(4), year(created)) 
 ,qty=count(convert(varchar(2),month(created)) + '/' + convert(varchar(4), year(created)))
from posts 
group by convert(varchar(2),month(created)) + '/' + convert(varchar(4), year(created))
) a
order by substring(mo,charindex(mo,'/')+1,50)

But I wouldn't say that works...

tsilb
  • 7,977
  • 13
  • 71
  • 98

5 Answers5

86
var grouped = from p in posts
     group p by new { month = p.Create.Month,year= p.Create.Year } into d
     select new { dt = string.Format("{0}/{1}",d.Key.month,d.Key.year), count = d.Count() };

Here's the list of DateTime functions available in LINQ. For this to work you'll also need to understand multi-column grouping

ordered descending

var grouped = (from p in posts 
  group p by new { month = p.Create.Month,year= p.Create.Year } into d 
  select new { dt = string.Format("{0}/{1}",d.Key.month,d.Key.year), count = d.Count()}).OrderByDescending (g => g.dt);
Jeremy
  • 6,580
  • 2
  • 25
  • 33
29

This is for those who are trying to accomplish the same but using lambda expressions.

Assuming that you already have a collection of entities and each entity has OrderDate as one of its properties.

yourCollection
// This will return the list with the most recent date first.
.OrderByDescending(x => x.OrderDate)
.GroupBy(x => new {x.OrderDate.Year, x.OrderDate.Month})
// Bonus: You can use this on a drop down
.Select(x => new SelectListItem
        {
           Value = string.Format("{0}|{1}", x.Key.Year, x.Key.Month),
           Text = string.Format("{0}/{1} (Count: {2})", x.Key.Year, x.Key.Month, x.Count())
        })
.ToList();

If you do not need the collection of SelectListItem then just replace the select with this one:

.Select(x => string.Format("{0}/{1} (Count: {2})", x.Key.Year, x.Key.Month, x.Count()))
Miguel
  • 1,575
  • 1
  • 27
  • 31
7

you could also do it this way

from o in yg
group o by o.OrderDate.ToString("MMM yyyy") into mg
select new { Month = mg.Key, Orders = mg }

Your result will be

{Jan 2014, 25} {Feb 2015, 15} etc...

Rolwin Crasta
  • 4,219
  • 3
  • 35
  • 45
  • Works great for objects, but not for `IQueryable<>` that will get sent to a database. There you get `Method 'System.String ToString(System.String)' has no supported translation to SQL.` – Thymine Jun 10 '19 at 18:18
1

This Site has an example that should fill your need.

This is the basic syntax:

from o in yg
group o by o.OrderDate.Month into mg
select new { Month = mg.Key, Orders = mg }
Jimmie R. Houts
  • 7,728
  • 2
  • 31
  • 38
  • 14
    With a list containing orders from mulitple years, this will group orders from january 2010, 2011 and 2012 into the same group. – Moulde Mar 05 '12 at 13:40
0

Here is a simple solution for grouping in DateTime.

List<leaveallview> lav = new List<leaveallview>();
lav = dbEntity.leaveallviews.Where(m =>m.created==alldate).ToList();
dynamic lav1 = lav.GroupBy(m=>m.created.Value.GetDateTimeFormats()).FirstOrDefault().ToList();
SilverNak
  • 3,283
  • 4
  • 28
  • 44