I'm trying to find a way to group records by date (not taking into account time) using the LINQ method syntax but only select one instance of each record (which is ItemId within the model)
My simple query is as follows:
range1.Count(x => ((x.OpenedDate >= todayFirst) && (x.OpenedDate <= todayLast))
How could I count the unique records within this range by ItemId?
Sounds like you want:
var query = range1.Where(x.OpenedDate >= todayFirst && x.OpenedDate <= todayLast)
.GroupBy(x => x.ItemId)
.Select(g => new { ItemId = g.Key, Count = g.Count() });
foreach (var result in query)
{
Console.WriteLine("{0} - {1}", result.ItemId, result.Count);
}
It's possible that I haven't really understood you properly though - it's not clear whether you really want to group by date or item ID
EDIT: If you just want the count of distinct item IDs in that range, you can use:
var count = range1.Where(x.OpenedDate >= todayFirst && x.OpenedDate <= todayLast)
.Select(x => x.ItemId)
.Distinct()
.Count();
Related
When I run this expression i can see that the list order is correctly in sequence by the highest ActionId's
var list = db.Actions.Where(z => z.RunId
== RunId).OrderByDescending(w =>
w.ActionId).ToList();
I only want to select the highest ActionId's of each ActionName so I now do:
var list = db.Actions.Where(z => z.RunId
== RunId).OrderByDescending(w =>
w.ActionId).GroupBy(c => new
{
c.ActionName,
c.MachineNumber,
})
.Select(y =>
y.FirstOrDefault()).ToList();
When I look at the contents of list, it hasn't selected the ActionName/MachineNumber with the highest ActionId, which I assumed would be the case by ordering then using FirstOrDefault().
Any idea where I'm going wrong? I want to group the records by the ActionName and MachineId, and then pick the record with the highest ActionId for each group
Instead of grouping an ordered collection, group the collection first, and then select the record with the highest ID for each of the groups. GroupBy is not guaranteed to preserve the order in each group in LINQ to SQL - it depends on your database server.
var list = db.Actions.Where(z => z.RunId == RunId).GroupBy(c => new
{
c.ActionName,
c.MachineNumber,
})
.Select(y => y.OrderByDescending(z => z.ActionId).FirstOrDefault()).ToList();
I have this query
SELECT
DISTINCT TOP 10 COUNT([ServicesTracking].[dbo].[SearchLogs].[recordCount]) AS [RecordCount],
[ServicesTracking].[dbo].[SearchLogs].[searchValue] AS [SearchValue] FROM [ServicesTracking].[dbo].[SearchLogs]
WHERE (([ServicesTracking].[dbo].[SearchLogs].[searchType] = 'something'
AND [ServicesTracking].[dbo].[SearchLogs].[searchValue] <> ''
AND [ServicesTracking].[dbo].[SearchLogs].[recordCount] > 0
AND [ServicesTracking].[dbo].[SearchLogs].[appDomain] = 'localhost'))
GROUP BY [ServicesTracking].[dbo].[SearchLogs].[searchValue]
ORDER BY RecordCount DESC
And I am trying to convert it into EF LINQ Lambda. This is what I came up with. EDIT: Fixed a bug with my successive queries.
IQueryable<SearchLog> query = _context.SearchLogs
.Where(sl => sl.appDomain == AppDomain)
.Where(sl => sl.searchType == SearchType)
.Where(sl => sl.searchValue != string.Empty);
// Are we looking for terms that brought back results?
if (_greaterThanZero) query = query.Where(sl => sl.recordCount > 0);
else query = query.Where(sl => sl.recordCount == 0);
// Date range being used?
if (StartDate != DateTime.MinValue) query = query.Where(sl => sl.createDate > DateUtilities.GetStartOfDay(StartDate));
if (EndDate != DateTime.MinValue) query = query.Where(sl => sl.createDate < DateUtilities.GetEndOfDay(EndDate));
List<SearchResultSet> results = query
.GroupBy(sl => sl.searchValue)
.Select(sl => new SearchResultSet
{
SearchValue = sl.Key,
RecordCount = sl.Select(r => r.recordCount)Distinct().Count()
})
.OrderByDescending(sl => sl.RecordCount)
.Take(10)
.ToList();
foreach (SearchResultSet result in results)
result.SearchValue = HttpContext.Current.Server.UrlDecode(result.SearchValue);
return results;
It's not returning the same results. I'm fairly certain I have something mixed up in the GroupBy or Select statements. Any ideas?
Just
RecordCount = sl.Select(r => r.recordCount).Count()
You don't need the Distinct(), and it is not the same as the DISTINCT in the SQL Query, which does nothing, since each row has a distinct searchValue after GROUP BY searchValue.
But why
COUNT([ServicesTracking].[dbo].[SearchLogs].[recordCount]) AS [RecordCount]
? You are counting the rows with non-null recordCount. Should this be SUM()?
probably a simple Q but still a beginner at this and not sure on how to....
Each WorkStation can have a number of Invoices So my below code will....
store all the workStations, go Through each workStation,
get the last (most recent) invoice for that workStation,
If the invoices date (for the most recent Invoice) is < 12 Months
Add it to the list of sites...
EDIT:
Thanks for all the help guys but I am trying to do it through c# and avoid the LINQ searche you guys have mentioned...thanks for everyone who replied...
My new problem being i need to sort the ChosenInvoices list into asceding order and return the first...as i think it is selecting anyone in the list:
var allWorkSites =
(from worksites in db.Work_Sites
select worksites).Distinct().ToList();
List<Object> chosenInvoices = new List<Object>();
foreach (Work_Site worksite in allWorksites)
{
Invoice lastInvoice = worksite.Invoices.LastOrDefault();
if (lastInvoice != null)
{
if (lastInvoice.Invoice_Date < DateTime.Now.AddMonths(-12))
{
chosenInvoices.Add(workstation);
}
}
}
List<invoice> actualInvoices = db.Work_Stations.Distinct()
.Where(w => w.Invoices.Last().Invoice_Date < DateTime.Now.AddMonths(-12)).Select(w => w.Invoices.Last()).ToList();
This code will return you the list of most recent invoices from each workstation.
To sort your invoice in asscending order list have a method OrderBy(), so order it with this method and then take the first one.
Also list have Sort() method.
allWorkStations
.Where(w => w.Invoices.Last().Invoice_Date < DateTime.Now.AddMonths(-12))
.Select(w => list.add(w));
Or better yet:
List<Work_Station> list = db.Work_Stations
.Distinct()
.Where(w => w.Invoices.Last().Invoice_Date < DateTime.Now.AddMonths(-12))
.ToList();
var allWorkStations =
(from workstation in db.Work_Stations
where workstation.Invoices.Last().Invoice_Date < DateTime.Now.AddMonths(-12)
select workstation).Distinct();
The following code will create list of workstations which had invoice in last year
var checkDate = DateTime.Now.AddMonths(-12);
var resultList = db.Work_Stations
.Distinct()
.Select(ws => new {Ws = ws, Li = ws.Invoices.OrderBy(i => i.Invoice_Date).LastOrDefault()})
.Where(item => item.Li != null && Li.Invoice_Date < checkDate)
.Select(item => item.Ws)
.ToList();
This will work even if the invoices are not in date order:
invoiceLst.AddRange(allWorkStations
.Where(w => w.Invoices.Max(i => i.Invoice_Date) < DateTime.Now.AddMonths(-12)));
This query looks at the record before it and subtracts the times to calculate the total amount of time. However, when the first record is evaluated it throws an error on the third line after the subtraction. Index out of bounds. When I remove the Sum() then the error goes away, but I need the sum efficiently.
var allRecorded = queryable.Where(x => x.DataId== Id);
var dataFiltered = allRecorded.Where(x => x.DataValue >= lowerThreshold && x.DataValue < upperThreshold);
var sumOfExactTimes = dataFiltered.Select(times => (times.EndTime - allRecorded.Where(time2 => time2.EndTime < times.EndTime).Select(x => (DateTime?) x.EndTime).Max()).GetValueOrDefault().TotalMinutes).Sum();
Is there anything else I'm missing?
The problem with the query you have above is that when you reach the item with the minimum EndTime, nothing is found giving you an empty result. You then try to take the maximum of an empty collection which causes the error.
However this query could be simplified tremendously. It would be easier to sort it first then aggregate to find the differences.
var data = queryable
.Where(item => item.DataId == id
&& item.DataValue >= lowerThreshold
&& item.DataValue < upperThreshold)
.OrderBy(item => item.EndTime)
.ToList();
var sumOfExactTimes = data.Skip(1)
.Aggregate(
Tuple.Create(data.First(), 0.0), // [1] Prev Item [2] Result
(seed, item) =>
Tuple.Create(
item,
seed.Item2 + (item.EndTime - seed.Item1.EndTime).TotalMinutes),
result => result.Item2);
The LINQ query below is working fine but I need to tweak it a bit.
I want all the records in the file grouped by recordId (a customer number) and then ordered by, in descending order, the date. I'm getting the grouping and the dates are in descending order. Now, here comes the tweaking.
I want the groups to be sorted, in ascending order, by recordId. Currently, the groups are sorted by the date, or so it seems. I tried adding a .OrderBy after the .GroupBy and couldn't get that to work at all.
Last, I want to .take(x) records where x is dependent on some other factors. Basically, the .take(x) will return the most-recent x records. I tried placing a .take(x) in various places and I wasn't getting the correct results.
var recipients = File.ReadAllLines(path)
.Select (record => record.Split('|'))
.Select (tokens => new
{
FirstName = tokens[2],
LastName = tokens[4],
recordId = tokens[13],
date = Convert.ToDateTime(tokens[17])
}
)
.OrderByDescending (m => m.date)
.GroupBy (m => m.recordId)
.Dump();
Edit #1 -
recordId is not unique. There may / will likely be multiple records with the same recordId. recordId is actually a customer number.
The output will be a resultset with first name, last name, date, and recordId. Depending on several factors, there many be 1 to 5 records returned for each recordId.
Edit #2 -
The .Take(x) is for the recordId. Each recordId may have multiple rows. For now, let's assume I want the most recent date for each recordId. (select top(1) when sorted by date descending)
Edit #3 -
The following query generates the following results. Note each recordId only produces 1 row in the output (this is okay) and it appears it is the most recent date. I haven't thouroughly checked this yet.
Now, how do I sort, in ascending order, by recordId?
var recipients = File.ReadAllLines(path)
.Select (record => record.Split('|'))
.Select (tokens => new
{
FirstName = tokens[2],
LastName = tokens[4],
recordId = Convert.ToInt32(tokens[13]),
date = Convert.ToDateTime(tokens[17])
}
)
.GroupBy (m => m.recordId)
.OrderByDescending (m => m.Max (x => x.date ) )
.Select (m => m.First () )
.Dump();
FirstName LastName recordId date
X X 2531334 3/11/2011 12:00:00 AM
X X 1443809 10/18/2001 12:00:00 AM
X X 2570897 3/10/2011 12:00:00 AM
X X 1960526 3/10/2011 12:00:00 AM
X X 2475293 3/10/2011 12:00:00 AM
X X 2601783 3/10/2011 12:00:00 AM
X X 2581844 3/6/2011 12:00:00 AM
X X 1773430 3/3/2011 12:00:00 AM
X X 1723271 2/4/2003 12:00:00 AM
X X 1341886 2/28/2011 12:00:00 AM
X X 1427818 11/15/1986 12:00:00 AM
You can't that easily order by a field which is not part of the group by fields. You get a list for each group. This means, you get a list of date for each recordId.
You could order by Max(date) or Min(date).
Or you could group by recordId and date, and order by date.
order by most recent date:
.GroupBy (m => m.recordId)
// take the most recent date in the group
.OrderByDescending (m => m.Max(x => x.date))
.SelectMany(x => x.First
The Take part is another question. You could just add Take(x) to the expression, then you get this number of groups.
Edit:
For a kind of select top(1):
.GroupBy (m => m.recordId)
// take the most recent date in the group
.OrderByDescending (m => m.Max(x => x.date))
// take the first of each group, which is the most recent
.Select(x => x.First())
// you got the most recent record of each recordId
// and you can take a certain number of it.
.Take(x);
snipped I had before in my answer, you won't need it according to your question as it is now:
// create a separate group for each unique date and recordId
.GroupBy (m => m.date, m => m.recordId)
.OrderByDescending (m => m.Key)
This seems very similar to your other question - Reading a delimted file using LINQ
I don't believe you want to use Group here at all - I believe instead that you want to use OrderBy and ThenBy - something like:
var recipients = File.ReadAllLines(path)
.Select (record => record.Split('|'))
.Select (tokens => new
{
FirstName = tokens[2],
LastName = tokens[4],
recordId = tokens[13],
date = Convert.ToDateTime(tokens[17])
}
)
.OrderBy (m => m.recordId)
.ThenByDescending (m => m.date)
.Dump();
For a simple Take... you can just add this .Take(N) just before the Dump()
However, I'm not sure this is what you are looking for? Can you clarify your question?
just add
.OrderBy( g=> g.Key);
after your grouping. This will order your groupings by RecordId ascending.
Last, I want to .take(x) records where
x is dependent on some other factors.
Basically, the .take(x) will return
the most-recent x records.
If you mean by "the most recent" by date, why would you want to group by RecordId in the first place - just order by date descending:
..
.OrderByDescending (m => m.date)
.Take(x)
.Dump();
If you just want to get the top x records in the order established by the grouping though you could do the following:
...
.GroupBy (m => m.recordId)
.SelectMany(s => s)
.Take(x)
.Dump();
If you want something like the first 3 for each group, then I think you need to use a nested query like:
var recipients = File.ReadAllLines(path)
.Select(record => record.Split('|'))
.Select(tokens => new
{
FirstName = tokens[2],
LastName = tokens[4],
RecordId = tokens[13],
Date = Convert.ToDateTime(tokens[17])
}
)
.GroupBy(m => m.RecordId)
.Select(grouped => new
{
Id = grouped.Key,
First3 = grouped.OrderByDescending(x => x.Date).Take(3)
}
.Dump();
and if you want this flattened into a record list then you can use SelectMany:
var recipients = var recipients = File.ReadAllLines(path)
.Select(record => record.Split('|'))
.Select(tokens => new
{
FirstName = tokens[2],
LastName = tokens[4],
RecordId = tokens[13],
Date = Convert.ToDateTime(tokens[17])
}
)
.GroupBy(m => m.RecordId)
.Select(grouped => grouped.OrderByDescending(x => x.Date).Take(3))
.SelectMany(item => item)
.Dump();