How to get a group ordered by the count column - linq

It is hard to ask the question in plain english so I'll show what I'm trying to do.
Here's my SQL code:
select top 100 [Name], COUNT([Name]) as total from ActivityLog
where [Timestamp] between '2010-10-28' and '2010-10-29 17:00'
group by [Name]
order by total desc
I need to write that in LinQ. So far I have the following:
var groups = from ActivityLog log in ctx.ActivityLog
where log.Timestamp > dateFrom
where log.Timestamp <= dateTo
group log by log.Name;
but I don't have the COUNT(*) column to sort from :(

I'm afraid I am far more comfortable with the fluent syntax (as opposed to query syntax), but here is one possible LINQ answer:
ctx.ActivityLog
.Where(x => x.TimeStamp > dateFrom && x.TimeStamp <= dateTo)
.GroupBy(x => x.Name)
.Select(x => new { Name = x.Key, Total = x.Count() })
.OrderByDescending(x => x.Total)
.Take(100)
EDIT:
Alright, I stepped out of my comfort zone and came up with a query syntax version, just don't expect too much. I warned you about my abilities above:
(from y in (
from x in (
from log in ActivityLog
where log.Timestamp > dateFrom
where log.Timestamp <= dateTo
group log by log.Name)
select new { Name = x.Key, Total = x.Count() })
orderby y.Total descending
select new { Name = y.Name, Total = y.Total }).Take(100)

diceguyd30's answer technically is LINQ and is correct. In fact, the query syntax gets translated to those Queryable/Enumerable methods by the compiler. That said what's missing is using the group ... by ... into syntax. The equivalent query should be close to this:
var query = from log in ctx.ActivityLog
where log.TimeStamp > dateFrom && log.TimeStamp <= dateTo
group log by log.Name into grouping
orderby grouping.Count() descending
select new { Name = grouping.Key, Total = grouping.Count() };
var result = query.Take(100);
Note that in C# the Take(100) method has no equivalent in query syntax so you must use the extension method. VB.NET, on the other hand, does support Take and Skip in query syntax.

Related

Dynamic select in query with linq

I see Dynamic linq in below link:
ScottGu
I want to use this method to select a dynamic query like this:
I have a complex select and this way not solve my problem,
this is my select:
Select sUserName,sname, sFamily,sMobail,sid,sNumberSt,sActive,sPic,sDate from Student where {0} order by sid desc";
which {0} is a complex Condition:
sname like %somthing% and susername=N'something' and sid in (select sidfk from tablex where userteacher=N'name1')
and this condition is passed to method.
I must say that:
I don's know my condition,my condition specified with user search params.this condition that I say,Is only one example of what I want to do.
How can I do this?
Only way that solve my problem:
I send tow parameters instead of one,one for student and one for tablex:
var az = db.tablex.Where(p => p.userteacher== name1)
.Select(p => p.sidfk).ToList();
var query = db.Students.Where(textSearch).Where(s=>az.Contains(s.sid)).OrderByDescending(s => s.sid)
.Select(s => new
{
s.sUserName,
s.sname,
s.sFamily,
s.sMobail,
s.sid,
s.sNumberSt,
s.sActive,
s.sPic,
s.sDate,
});
wiche textSearch is :
sname like %somthing% and susername=N'something'
with dynamic linq
any better way is exist?
You don't need to use dynamic linq for this situation.
string paramA = "", paramB = "";
var query = from x in context.table1
where x.name == paramA
where context.table2.Where(y => y.field1 == paramB).Any(y => y.id == x.id)
select x;
Dynamic Linq usually use if in query you don't know what field will be use, so in your sample you use only params for conditions with field, so you don't ned dynamic linq
you can little optimize you query like this
var query = from student in db.Students
join teacher in db.tablex on student.sid equals teacher.sidfk
where student.sname.Contains('somthing') &&
susername=='something' &&
teacher.userteacher=='name1'
orderby s.sid descending
select new
{
s.sUserName,
s.sname,
s.sFamily,
s.sMobail,
s.sid,
s.sNumberSt,
s.sActive,
s.sPic,
s.sDate,
};

Linq, how to write regular query with aggregate function?

on my page, I need to show a list of tools.
var tools = _toolRepository.GetAll().Where(t => t.IsActive == true).OrderByDescending(t => t.PostDate).Take(50).ToList();
I also need to show how many Votes each tool got, I can write a separate query to do that, but that will double the number of queries.
is there a way to combine them together?
here's my database structure.
Tool
id
name
postDate
ToolVote
id
ToolId
UserId
How about:
var tools = _toolRepository.GetAll().Where(t => t.IsActive == true).OrderByDescending(t => t.PostDate).Take(50).Select(tool => new { Tool = tool, votes = ToolVotes.Where(tv => tv.ToolID == tool.ToolID)} ).ToList();
Assuming that you have 1 to * relationship you can use left join.
I can't test this query but it should look something like this
var query = (from tool in _toolRepository.GetAll().Where(t => t.IsActive == true).OrderByDescending(t => t.PostDate).Take(50)
join toolVote in toolVotes on tool.id equals toolVote.ToolId
into toolsTemp
from toolTemp in toolsTemp.DefaultIfEmpty()
select new { Tool = tool, Count = toolTemp == null ? 0 : toolTemp.Count})
.ToList();

In Linq2SQL, how do I get a record plus the previous and next in the sequence in a single query?

Given a date, what is the most efficient way to query the last record before that date, any record that equals that date, and the next one after that date.
It should be functionally equivalent to a query like this:
from asset in Assets
where asset.Id == assetId
select new {
Previous = (from a in a.Orders where a.Date < myDate orderby a.Date descending select a).FirstOrDefault(),
Current = (from a in a.Orders where a.Date == myDate select a).SingleOrDefault(),
Next = (from a in a.Orders where a.Date > myDate orderby a.Date select a).FirstOrDefault()
}
As is, this query runs three queries, and presumably has to sort the dataset by myDate three times to do it.
Some similar questions:
How do I get 5 records before AND after a record with a specific ID? (just uses two queries)
How do I get records before and after given one? Not in Linq, and therefore hard for me to take advantage of (my team will get annoyed).
To provide the "most efficient" query depends on what you mean by efficient.
If you want a single query to the database, a single sort of orders by date and finally fast look-ups by date then I suggest the following might be the most efficient. :-)
var orders =
(from a in Assets
where a.Id == assetId
from o in a.Orders
orderby o.Date
select o).ToArray();
var previous = orders.LastOrDefault(o => o.Date < myDate);
var current = orders.SingleOrDefault(o => o.Date == myDate);
var next = orders.FirstOrDefault(o => o.Date > myDate);
This should query the database once for the orders associated with the required asset Id, sort them by date, and return them as an array in memory. Since this is in memory it is now blindingly fast to look for the current, previous & next records for the specified date.
Does your Orders table have a sequential ID field? If so, you might be able to do it with:
from asset in Assets
where asset.Id == assetID
let current = asset.Orders.Where(x => x.Date == myDate).FirstOrDefault()
where current != null
let previous = asset.Orders.Where(x => x.id == current.id - 1).FirstOrDefault()
let next = asset.Orders.Where(x => x.id == current.id + 1).FirstOrDefault()
select new {
Previous = previous,
Current = current,
Next = next
};
If it doesn't, then it'd be a bit more code:
from asset in Assets
where asset.Id == assetID
let current = asset.Orders.Where(x => x.Date == myDate).FirstOrDefault()
where current != null
let previous = asset.Orders.Where(x => x.Date < current.Date).OrderByDescending(x => x.Date).FirstOrDefault()
let next = asset.Orders.Where(x => x.Date > current.Date).OrderBy(x => x.Date).FirstOrDefault()
select new {
Previous = previous,
Current = current,
Next = next
};
That should get compiled into a single SQL query that utilizes sub-queries. IE: the database server will execute multiple queries, but your client program is only submitting one.
Edit One other idea that would work if your Order table had sequential IDs:
var sample = (from asset in Assets
where asset.Id == assetID
let current = asset.Orders.Where(x => x.Date == myDate).FirstOrDefault()
where current != null
from order in asset.Orders
where order.Id == current.id - 1
select order)
.Take(3)
.ToArray();
var Previous = sample[0];
var Current = sample[1];
var Next = sample[2];
Other Answers, for example, SkipWhile etc. very very slow. Good luck ^^
//Current Record
var query
= (from item in db.Employee
where item.UserName.Equals(_username)
select item).SingleOrDefault();
//Next Record
var query
= (from item in db.Employee
where item.UserName.CompareTo(_username) > 0
select item).FirstOrDefault();
//Previous Record
var query
= (from item in db.Employee
where item.UserName.CompareTo(_username) < 0
orderby item.UserName Descending
select item).FirstOrDefault();
Almost the same, but the SQL query plan might be different.
var q =
from asset in Assets
where asset.Id == assetID
select new
{
Previous = asset.Orders.where(a => a.Date == asset.Orders.Where(x => x.Date < myDate).Max(x => x.Date)).FirstOrDefault(),
Current = asset.Orders.Where(x => x.Date == myDate).FirstOrDefault(),
Next = asset.Orders.where(a => a.Date == asset.Orders.Where(x => x.Date > myDate).Min(x => x.Date)).FirstOrDefault()
};

Groupby and where clause in Linq

I am a newbie to Linq. I am trying to write a linq query to get a min value from a set of records. I need to use groupby, where , select and min function in the same query but i am having issues when using group by clause. here is the query I wrote
var data =newTrips.groupby (x => x.TripPath.TripPathLink.Link.Road.Name)
.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link.Speed).Min();
I am not able to use group by and where together it keeps giving error .
My query should
Select all the values.
filter it through the where clause (pathnum).
Groupby the road Name
finally get the min value.
can some one tell me what i am doing wrong and how to achieve the desired result.
Thanks,
Pawan
It's a little tricky not knowing the relationships between the data, but I think (without trying it) that this should give you want you want -- the minimum speed per road by name. Note that it will result in a collection of anonymous objects with Name and Speed properties.
var data = newTrips.Where(x => x.TripPath.PathNumber == pathnum)
.Select(x => x.TripPath.TripPathLink.Link)
.GroupBy(x => x.Road.Name)
.Select(g => new { Name = g.Key, Speed = g.Min(l => l.Speed) } );
Since I think you want the Trip which has the minimum speed, rather than the speed, and I'm assuming a different data structure, I'll add to tvanfosson's answer:
var pathnum = 1;
var trips = from trip in newTrips
where trip.TripPath.PathNumber == pathnum
group trip by trip.TripPath.TripPathLink.Link.Road.Name into g
let minSpeed = g.Min(t => t.TripPath.TripPathLink.Link.Speed)
select new {
Name = g.Key,
Trip = g.Single(t => t.TripPath.TripPathLink.Link.Speed == minSpeed) };
foreach (var t in trips)
{
Console.WriteLine("Name = {0}, TripId = {1}", t.Name, t.Trip.TripId);
}

Joins with multiple fields on GroupBy table data in LINQ query/method

I have to work out how to write the following SQL query usingLINQ query or method syntax. (Edit: This is to return a list of latest AgentActivities for all Agents).
SELECT
a.[AgentActivityId],
a.[AgentId],
a.[ActivityId],
a.[StartedAt],
a.[EndedAt],
a.[Version]
FROM
[dbo].[AgentActivity] a
INNER JOIN
(
SELECT
[AgentId],
MAX([StartedAt])[StartedAt]
FROM
[dbo].[AgentActivity]
WHERE
([StartedAt] > '2010/01/24 23:59:59')
AND ([StartedAt] < '2010/10/25')
GROUP BY
AgentId
)grouped
ON (a.[AgentId] = grouped.[AgentId]
AND a.[StartedAt] = grouped.[StartedAt])
Just to recap, here's how I interpret the question:
What you want is a list with the most recently started activity for an agent, with the added requirement that the activity must be started within a given date interval.
This is one way to do it:
// the given date interval
DateTime startDate = new DateTime(2010, 1, 24);
DateTime endDate = new DateTime(2010, 10, 25);
IEnumerable<AgentActivity> agentActivities =
... original list of AgentActivities ...
IEnumerable<AgentActivity> latestAgentActivitiesByAgent = agentActivities
.Where(a => a.StartedAt >= startDate && a.StartedAt < endDate)
.GroupBy(a => a.AgentId)
.Select(g => g
.OrderByDescending(a => a.StartedAt)
.First());
(If the question involves LINQ to SQL, there may be some gotchas. I haven't tried that.)

Resources