Entity Framework Linq Group by DateRange - c#

I have an application that records page visits and I need to be able to query by day by week and by month, sample output of a table query is as follows (each row represents a visit:
Visits result set
DateTimeLanding | PageViews
2016-05-12 | 2
2016-05-16 | 3
2016-05-16 | 8
2016-05-16 | 3
2016-05-17 | 7
2016-05-19 | 4
2016-05-28 | 6
2016-05-28 | 3
2016-05-30 | 1
If I want to query this result set for daily visits I do this:
var visitData = visits.GroupBy(v => v.DateLanding)
.OrderBy(g => g.Key)
.Select(g => new { From = g.Key, Count = g.Count() });
visitNodes.Num = visits.Count().ToString();
visitNodes.Nodes = visitData.Select(p => new ReferralTrafficNode()
{
MetricDateTimeFrom = p.From,
MetricDateTimeTo = p.From.AddDays(1),
Value = p.Count
}).ToList();
This works fine for daily visits as I can group date.
How can I group the result set into groups of 7 days to get weekly visit data?
Essentially I need to be able to group by a date range

If you change your group by to this:
v => v.DateLanding.AddDays(-(int)v.DateLanding.DayOfWeek)
This should group by the Sunday of the week selected.

Related

Linq to SQL duplicate rank

I'm trying to build a leaderboards based on an int score. I'm pulling the records out and calculating the rank like so:
//Base query
var query = UoW.Repository<UserProfile>().Get().OrderByDescending(u => u.Points);
//Fetch the data including a groupby count
var data = await query
.Skip(skip)
.Take(pageSize)
.Select(u => new UserListItem
{
Points = u.Points.ToString(),
Username = u.DisplayName,
Rank = query.Count(o => o.Points > u.Points) + 1 //Calculates the rank (index)
})
.GroupBy(u => new { Total = query.Count() })
.FirstOrDefaultAsync();
This works fine except when I have 2 or more values with the same points it duplicate the position. I need it to be continuously incremented regardless of ties. This is how is currently displays the results:
Rank | User | Points
1 | User 1 | 456
2 | User 2 | 420
3 | User 3 | 402
4 | User 4 | 380
4 | User 5 | 380
Any idea how I can get it to auto increment correctly?
The solution is to add more conditions to the Rank function, to determine which comes first when the scores are tied. It could even be ranking by username a- > z if you like.
Answers to point you in the right direction to use multiple criteria can be found in this SO answer.

how to group by in LINQ and not select all columns

I am trying to write a LINQ query which is complex for me now since I am a newbie to LINQ.
I have a table like below...
UserId | CompanyId | ProblemDescription | CreatedTime | TimeSpentMins
-----------------------------------------------------------------------
1 | 95 | Sysmtem is crashed | 2016-01-01 15:23 | 25
1 | 95 | Total is incorrect | 2016-01-01 15:45 | 45
I want to write a LINQ query that will do the job below. CreatedTime has date and time but I want to group it by only date.
SELECT UserId, CompanyId,CreateTime Sum(TimeSpentMins)
FROM TransactionLogs
GROUP BY UserId, CompanyId, Convert(DATE,CreatedTime)
How can I write this LINQ? I wanted to put my code below but I got nothing :(
Simply use the GroupBy extension method and use EntityFunctions.TruncateTime method to get only the date part:-
var result = db.TransactionLogs
.GroupBy(x => new
{
CreateTime = EntityFunctions.TruncateTime(x.CreatedTime),
UserId,
CompanyId
})
.Select(x => new
{
UserId = x.Key.UserId,
CompanyId = x.Key.CompanyId,
CreateTime = x.Key.CreateTime,
TotalTimeSpentMins = x.Sum(z => z.TimeSpentMins)
});
try this one:
var result = db.TransactionLogs
.GroupBy(_ => new {
_.UserId, _.CompanyId, DbFunctions.TruncateTime(_.CreatedTime)})
.Select(_ => new {
_.UserId, _.CompanyId, DbFunctions.TruncateTime(_.CreatedTime),
Total = _.Sum(t => t.TimeSpentMins)});

Distinct Count x and Grouping by Date y

I'm trying to get from the following data in an SQL database
date | user |
(DateTime) | (string)|
--------------------------------------------------
2013-06-03 13:24:54.013 | 3 |
2013-06-04 13:25:54.013 | 5 |
2013-06-04 13:26:54.013 | 3 |
2013-06-04 13:27:54.013 | 3 |
a list in the form
date | DistinctCountUser
---------------------------------
2013-06-03 | 1
2013-06-04 | 2
I've tried several ways to do this with linq but always end up with a) not the result I expected or b) a linq exception.
var result = input.GroupBy(x=>x.date.Date,(key,x)=> new {
date = key,
DistinctCountUser = x.Select(e=>e.user).Distinct().Count()
});
If you are using Entity Framework, then you should use EntityFunctions.TruncateTime to get date part of date time field:
from x in context.TableName
group x by EntityFunctions.TruncateTime(x.date) into g
select new {
date = g.Key,
DistinctCountUser = g.Select(x => x.user).Distinct().Count()
}
Otherwise use #KingKong answer
Here is how to use query expression when grouping in Linq. Query Expressions may be easier to read in some cases and I find grouping to be one of them.
from thing in things
group thing by thing.date.Date into g
select new {
Date = g.Key,
DistinctCountUser = g.Select(x => x.user).Distinct().Count()
}

Linq - Group by multiple tables

Using Linq to Sql how do i group the following 2 tables.
Orders Table:
CustomerID | Name |Date
1 | order1 | 2010-01-01
2 | order2 | 2010-01-01
2 | order3 | 2010-04-01
Calls Table:
CustomerID | Name |Date
1 | call1 | 2010-01-01
3 | call2 | 2010-06-01
2 | call3 | 2010-05-01
I want to group the two tables by date , Result:
Date | Orders | Calls
2010-01-01 | 2 | 1
2010-04-01 | 1 | 0
2010-05-01 | 0 | 1
2010-06-01 | 0 | 1
i know how to group a single table ,
from o in Orders
group o by o.Date.Date into og
select new {Date = og.Key,Orders= og.Count()};
how do i group both?
thx!
Since both tables seem to have a similar structure I'd recommend projecting both into an equivalent form and then group on the concatenation of those two sets.
var orders = from o in Orders
select new { IsOrder = true, o.Date };
var calls = from c in Calls
select new { IsOrder = false, c.Date };
var result = from x in orders.Concat(calls)
group x by x.Date into og
select new {Date = og.Key, Orders= og.Count(o=>o.IsOrder), Calls = og.Count(c=>!c.IsTrue)};
Due to the lazy nature of Linq2Sql this might actually be reduced to a single query. In the interest of performance I would make sure this is not a query from hell.
You can use the Union method:
var result =
(from c in Calls group c by c.Date into cg select new {Date = cg.Key, Calls = cg.Count(), Orders = 0})
.Union(from o in Orders group o by o.Date into og select new {Date = og.Key, Calls = 0, Orders = og.Count()})
.GroupBy(x => x.Date)
.Select(g => new {Date = g.Key, Calls = g.Max(r => r.Calls), Orders = g.Max(r => r.Orders)});
foreach (var row in result)
{
Trace.WriteLine(row);
}
This is very similar to the SQL you would write (a union of the two tables, and then an outer query to merge the results into a row)

List of unique strings in database table using Linq?

I have a "Tickets" table with somewhat following structure (removed unnecessary columns)
int | string | int |
ID | Window | Count |
------------------------
0 | Internet | 10 |
1 | Phone | 20 |
2 | Fax | 15 |
3 | Fax | 10 |
4 | Internet | 5 |
. | . | . |
. | . | . |
And I have mapped this table to a class "Ticket". So I can get all records like this:
var tickets = from t in db.Tickets
select t;
Now I need to get the list of unique window names in the table. For above table, list would look something like:
Internet
Phone
Fax
Is there anyway to create this list without fetching all records and iterating over them?
I am using SQL Server 2008 express edition.
EDIT:
Thanks for the answers guys it solved the above problem. Just being greedy but is there any way to also get the total of count for each window. For example:
Internet = 15
Phone = 25
Fax = 20
How about:
var tickets = db.Tickets.Select(t => t.Window).Distinct();
I prefer to only use query expressions when I'm doing more than one operation, but if you like them the equivalent is:
var tickets = (from t in db.Tickets
select t.Window).Distinct();
To get the counts, you need to group:
var tickets = from t in db.Tickets
group t by t.Window into grouped
select new { Window=grouped.Key,
Total=grouped.Sum(x => x.Count) };
foreach (var entry in tickets)
{
Console.WriteLine("{0}: {1}", entry.Window, entry.Total);
}
Note that this should all end up being performed at the database side - examine the SQL query to check this.
var query2 = from ticket in db.tickets
group window by ticket.Window into result
select new
{
Name = result.Window,
Sum = result.Sum(i => i.Count)
};
The query will be evaluated inside the store.
var windows = db.Tickets.Select(ticket => ticket.Window).Distinct();
Linq Samples Part 11 by Bill Wagner should help you. Just call the Distinct() function on your Linq result. It's as simple as that.
var tickets = (from t in db.Tickets
select t).Distinct();
[EDIT]
Concering the numbers of the occurences, see this example as a hint.
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 5 };
var numberGroups =
from n in numbers
group n by 5 into g
select g;
g.Count(); // occurences
You can use the .Distinct() operator - it'll make a SELECT DISTINCT to the database, giving exactly what you ask for.

Categories