I want to write a Linq to Sql query that does a count and groups by a Username and DateTime. I want the DateTime to be formatted like following "YYYY-MMM" (i.e. 2009-Mar).
I thought this would work but Linq to Sql can't parse the ToString "format" argument.
dc.MyTable
.GroupBy(r => new
{
Name = r.UserName,
YearMonth = r.SomeDateTime.ToString("yyyy-MMM")
})
.Select(r => new
{
Name = r.UserName,
YearMonth = r.YearMonth,
Count = r.Count()
})
.OrderBy(r => r.YearMonth)
.ThenBy(r => r.Name);
Does anyone have any thoughts/suggestions?
Thanks.
I wonder if you shouldn't do that the "long" way...
dc.MyTable
.GroupBy(r => new
{
Name = r.UserName,
Year = r.SomeDateTime.Year,
Month = r.SomeDateTime.Month
})
.Select(r => new
{
Name = r.UserName,
Year = r.Year,
Month = r.Month,
Count = r.Count()
})
.OrderBy(r => r.Year)
.ThenBy(r => r.Month)
.ThenBy(r => r.Name);
If you need the format as a string, do that later at the UI. Either by reconstructing a DateTime etc, or using CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(...).
I would avoid turning anything into a string at the database. Group by r.SomeDateTime.Year and r.SomeDateTime.Month, ordering by year then month then name, select the year and the month separately (along with the count), and then if you need to do the projection to a string format back in the client code.
By the way, I suspect your second OrderBy should be a ThenBy - currently the Name is actually the most important thing you're ordering by.
Related
I am using a LINQ query to get the data order by descending date. but when the year is changed then descending order of date is not in the proper way
Here is my code
In this code, LastLogin is a column with DateTime datatype. I have to sort data by this column name.
var res = objUI.Where(x => x.LastLogin != null)
.GroupBy(x => x.LastLogin.Value.Date)
.Select(x => new { LastLogin = string.Format("{0:MM/dd/yyyy}", x.Key) })
.OrderByDescending(x => x.LastLogin)
.ToList();
You shouldn't to try order the date as string;
var res = objUI.Where(x => x.LastLogin != null)
.GroupBy(x => x.LastLogin.Value.Date)
.OrderByDescending(x => x.Key)
.Select(x => new { LastLogin = string.Format("{0:MM/dd/yyyy}", x.Key) })
.ToList();
You're ordering by your string representation which starts with the month.
It looks like you're actually only interested in distinct dates though - grouping and then discarding everything other than the key is equivalent to just projecting and then taking distinct data. I'd also suggest avoiding an anonymous type unless you really need it - an anonymous type with only a single property is usually a bad idea.
Finally, if you're formatting a single value - certainly a DateTime value - it's simpler to just call the ToString method. In the code below I've explicitly specified the invariant culture too - otherwise you may find an unexpected calendar system is used...
So I'd write:
var res = objUI.Where(x => x.LastLogin != null)
.Select(x => x.LastLogin)
.Distinct()
.OrderByDescending(x => x)
.Select(x => x.ToString("MM/dd/yyyy", CultureInfo.InvariantCulture))
.ToList();
I'm trying to group a list of records by hour and store the number of record for each hour. Here is my code :
DateTime firstTimeStamp = myRecords.DataBaseRecords.First().TimeStamp;
Statistics = myRecords.DataBaseRecords
.GroupBy(x => x.TimeStamp.Hour)
.Select(group => new GraphModel() { Date =firstTimeStamp.AddHours(group.Key), Value = group.Count() })
.ToList();
The problem is that when I'm on the select fuction, I cannot acces to the DateTime anymore so the field group.key contains a value between 0 and 24. I just need to group all the records by hour and foreach hour, I need to have the number of records in the Value parameter.
You have to group the data by absolute hours as of the first timestamp, i.e. the differences in hours calculated for each TimeStamp value:
Statistics = myRecords.DataBaseRecords
.GroupBy(x => DbFunctions.DiffHours(firstTimeStamp, x.TimeStamp) into g
.Select(g => new GraphModel
{
Date = g.FirstOrDefault().TimeStamp,
Value = g.Count()
};
If this is plain LINQ to objects (not Entity Framework) you can replace ...
DbFunctions.DiffHours(firstTimeStamp, x.TimeStamp)
... by
(x.TimeStamp - firstTimeStamp).TotalHours
If it's LINQ to SQL, use
SqlMethods.DateDiffHour(firstTimeStamp, x.TimeStamp)
Perhaps something like this may work out for you:
DateTime myDateTime = new DateTime(DateTime.Parse(firstTimeStamp).AddHours(group.Key).Ticks);
Question specific to answer above:
...Date = new DateTime(DateTime.Parse(firstTimeStamp).AddHours(group.Key))...
I'm trying to convert query of queries used in ColdFusion to LINQ and C#. The data come from data files, rather than from the database.
I converted the first query, but have no clue as to
how to use it to query the second query.
how to include count(PDate) as DayCount in the second query.
Below is the code using query of queries in ColdFusion:
First query
<cfquery name="qSorted" dbtype = "query">
SELECT OA, CD,PDate,
FROM dataQuery
GROUP BY CD,OA,PDate,
</cfquery>
Second query
<cfquery name="qDayCount" dbtype = "query">
SELECT OA, CD, count(PDate) as DayCount
FROM qSorted // qSorted is from the first query.
GROUP BY
OA, CD
ORDER BY
OA, CD
</cfquery>
Here's the first converted LINQ query, and it works fine:
var Rows = allData.SelectMany(u => u._rows.Select(t => new
{
OA = t[4],
CD = t[5],
PDate = t[0]
}))
.GroupBy(x => new { x.CD, x.OA, x.PDate })
.Select(g => new
{
g.Key.OA,
g.Key.CD,
g.Key.PDate
})
.ToList();
Here's the pseudo-code for the second LINQ query, which I need your assistance:
var RowsDayCount = Rows //Is this correct? If not, how to do it?
.GroupBy(x => new { x.OA, x.PDate, x.CD, })
.Select(g => new
{
g.Key.OA,
g.Key.CD,
g.Key.PDate,//PDate should be PDate.Distinct().Count() asDayCount
// See DayCount in cfquery name="qDayCount" above.
})
.OrderBy(u => u.OA)
.ThenBy(u => u.CD)
.ToList();
Your second query origionally wasn't grouping on PDate, but your translation is. That's wrong. If you want to count the number of PDates for each OA/CD pair, you need to not group on PDate. Once you've made that change, you can modify the Select to pull out all of the PDate values from the group, and count the distinct values.
.GroupBy(x => new { x.OA, x.CD, })
.Select(g => new
{
g.Key.OA,
g.Key.CD,
DayCount = g.Select(item => item.PDate).Distinct().Count(),
})
Done a lot of research but still having a tough one with this. Consider a database which has a transactions table of "CreatedOn", "Amount", "Type". I need to be able to do an entity query to get transactions of a certain type grouped together by different date granularities (month / day etc).
So imagine a table with:
2011/1/22 $300 Deposit
2011/2/18 $340 Deposit
2011/3/6 $200 Other
2011/3/6 $100 Deposit
2011/3/7 $50 Deposit
I could have a query which would pull all deposits grouped by month so it could yield:
2011-1 $300 1deposit
2011-2 $340 1deposit
2011-3 $150 2deposits
How would I then adapt this query to be by day rather than month?
Here's my current block of code but I get an inner linq exception
Can't group on A1
var result = context.TransactionEntities.Where(d => d.Type == "Deposit")
.GroupBy(g => new { g.CreatedOn.Year, g.CreatedOn.Month })
.Select(g => new
{
DateKey = g.Key,
TotalDepositAmount = g.Sum(d => d.Amount),
DepositCount = g.Count()
}).ToList();
Note: I am currently using the MySql connector and I've read possibly this is a bug?
Func<DateTime, object> groupByClause;
if (groupByDay) groupByClause = date => date.Date;
else if (groupByMonth) groupByClause = date => new { date.Year, date.Month};
else throw new NotSupportedException("Some option should be chosen");
var result = data.Where(d => d.Type == "Deposit")
.GroupBy(groupByClause)
.Select(g => new { DateKey = g.Key,
TotalDepositAmount = g.Sum(d => d.Amount),
DepositCount = g.Count(),
});
Of course this should be checked whether linq-2-entities will accept it.
Check the code mentioned in my question: Group by Weeks in LINQ to Entities. It shows how you can group your data by days and months. Let me know if you have any other questions.
This is probably a bug in MySQL connector. My solution for that was to place .ToList() just before .GroupBy().
I have a order list and want to group them by the created date.
Each order's created datetime will be like "2010-03-13 11:17:16.000"
How can I make them only group by date like "2010-03-13"?
var items = orderList.GroupBy(t => t.DateCreated)
.Select(g => new Order()
{
DateCreated = g.Key
})
.OrderByDescending(x => x.OrderID).ToList();
Update: How can I group order by month? And the following code is not correct.
var items = orderList.GroupBy(t => t.DateCreated.Month)
.Select(g => new Order()
{
DateCreated = g.Key
})
.OrderByDescending(x => x.OrderID).ToList();
Many thanks.
Use the Date property.
var items = orderList.GroupBy( t => t.DateCreated.Date )
Using the .Date will discard the time component, e.g.
var items = orderList.GroupBy(t => t.DateCreated.Date)
Use t => t.DateCreate.Date.