LINQ Query with Aggregates and Group By - c#

i have the following SQL query...
select seaMake AS Make,
seaModel AS Model,
COUNT(*) AS [Count],
MIN(seaPrice) AS [From],
MIN(seaCapId) AS [CapId]
from tblSearch
where seaPrice >= 2000
and seaPrice <= 7000
group by seaMake, seaModel
order by seaMake, seaModel
Im trying to write this as a LINQ to Entities Query, but im having problems. This is what i have so far but i cannot access the make and model values from the var S
var tester = from s in db.tblSearches
where s.seaPrice >= 2000
&& s.seaPrice <= 7000
orderby s.seaMake
group s by s.seaMake into g
select new
{
make = g.seaMake,
model = s.seaModel,
count = g.Max(x => x.seaMake),
PriceFrom = g.Min(s.seaPrice)
};
Where am i going wrong ?

This should be a straightforward translation of the SQL:
from s in db.tblSearches
where
s.seaPrice >= 2000 &&
s.seaPrice <= 7000
group s by new {s.seaMake, s.seaModel} into g
orderby g.Key
select new
{
Make = g.Key.seaMake,
Model = g.Key.seaModel,
Count = g.Count(),
From = g.Min(x => x.seaPrice),
CapId = g.Min(x => x.seaCapId)
}

Instead of your original collection of IEnumerable<TypeOfS> when you grouped into g you converted that collection into an IEnumerable> so the collection in current scope is g. So the following would be valid
from s in db.tblSearches
where s.seaPrice >= 2000
&& s.seaPrice <= 7000
orderby s.seaMake
group s by s.seaMake into g // the collection is now IEnumerable<IGrouping<TypeOfSeaMake, TypeofS>>
select new {
make = g.Key, // this was populated by s.seaMake
model = g.First().seaModel, // get the first item in the collection
count = g.Max(x => x.seaMake), // get the max value from the collection
PriceFrom = g.Min(x => x.seaPrice), // get the min price from the collection
};
there will now be one item returned for each grouping

Related

Adding Summed columns together using Linq

I am wondering if there is an easier way of adding together summed columns inside a group by query using Linq. I am wanting to check wether column1 + column2 is greater than 2250, and if so do something...
Below is a snippet of code im using, a much slimmed down version for use here
from contact in _db.Worksheets
join person in _db.MyTable on contact.Email equals
person.EmailAddress
orderby contact.ShiftDate ascending
select new
{
EmployeeNumber = person.EmployeeNumber,
Overtime1= contact.Overtime1,
Overtime2= contact.Overtime2,
ShiftDate = contact.ShiftDate,
} into t1
group t1 by t1.EmployeeNumber into pg
select (new
{
OvertimeTotal = pg.Sum(x => x.ShiftDate >= vStart1 && x.ShiftDate <= vEnd1 ? x.Overtime1 : 0)
+ pg.Sum(x => x.ShiftDate >= vStart1 && x.ShiftDate <= vEnd1 ? x.Overtime2 : 0) > 2250 (....then do something)
I was wondering if you could do something like the below. (Which I have tried and it doesnt work)
I am using entity framework too, so realise there may be complications converting this type of query
OvertimeTotal = pg.Sum(x => x.ShiftDate >= vStart1 && x.ShiftDate <= vEnd1 ? x.Overtime1 + x.Overtime2 : 0)
It would help if you specify what you want when there is overtime. The following will return the employee numbers with overtime.
The approach is a little different from yours, as it filters the worksheet records before joining with the person records for optimization reasons. It then filters to just the employees that have overtime.
I'm assuming an employee has overtime if overtime1 + overtime2 of all their shifts in the specified date range adds up to more than 2250.
var employeesWithOvertime = _db.Worksheets
.Where(w => w.ShiftDate >= vStart1 && w.ShiftDate <= vEnd1)
.Join(_db.MyTable, w => w.Email, p => p.EmailAddress, (w, p) => new
{
EmployeeNumber = p.EmployeeNumber,
Overtime1 = w.Overtime1,
Overtime2 = w.Overtime2
})
.GroupBy(x => x.EmployeeNumber)
.Select(g => new
{
EmployeeNumber = g.Key,
OvertimeTotal = g.Sum(x => x.Overtime1 + x.Overtime2)
})
.Where(x => x.OvertimeTotal > 2250);

LINQ Query with GroupBy, MAX and Count

What could be the LINQ query for this SQL?
SELECT PartId, BSId,
COUNT(PartId), MAX(EffectiveDateUtc)
FROM PartCostConfig (NOLOCK)
GROUP BY PartId, BSId
HAVING COUNT(PartId) > 1
I am actually grouping by two columns and trying to retrieve max EffectiveDateUtc for each part.
This is what I could write. Stuck up on pulling the top record based on the date.
Also not sure, if this is a optimal one.
//Get all the parts which have more than ONE active record with the pat
//effective date and for the same BSId
var filters = (from p in configs
?.GroupBy(w => new
{
w.PartId,
w.BSId
})
?.Select(g => new
{
PartId = g.Key.PartId,
BSId = g.Key.BSId,
Count = g.Count()
})
?.Where(y => y.Count > 1)
select p)
?.Distinct()?.ToList();
var filteredData = (from p in configs
join f in filters on p.PartId equals f.PartId
select new Config
{
Id = p.Id,
PartId = p.PartId,
BSId = p.BSId,
//EffectiveDateUtc = MAX(??)
}).OrderByDescending(x => x.EffectiveDateUtc).GroupBy(g => new { g.PartId, g.BSId }).ToList();
NOTE: I need the top record (based on date) for each part. Was trying to see if I can avoid for loop.
The equivalent query would be:
var query =
from p in db.PartCostConfig
group p by new { p.PartId, p.BSId } into g
let count = g.Count()
where count > 1
select new
{
g.Key.PartId,
g.Key.BSId,
Count = count,
EffectiveDate = g.Max(x => x.EffectiveDateUtc),
};
If I understand well, you are trying to achieve something like this:
var query=configs.GroupBy(w => new{ w.PartId, w.BSId})
.Where(g=>g.Count()>1)
.Select(g=>new
{
g.Key.PartId,
g.Key.BSId,
Count = g.Count(),
EffectiveDate = g.Max(x => x.EffectiveDateUtc)
});

Linq Query with a where condition - count items

How can I change this request :
query = query.Where(item => (from table in context.Table
where table.amount == item.Amount
select table).Count() >= 10);
to not use the subquery (from ... in ...) ?
I tried to create the subquery separately, to use it with the Where condition :
var subQuery = from table in context.Table select table.amount;
var list = subQuery.ToList()
But I don't know how I can use it after that, because of the .Count() operation.
Thank you for your comments.
How about this:
query = query.Where(item => context.Table
.Count(t => t.amount == item.Amount) >= 10);
Or to reduce the number of round-trips:
var counts = context.Table
.GroupBy(t => t.amount)
.Select(g => new {amount = g.Key, count = g.Count()});
query = from q in query
join c in counts
on q.amount equals c.amount
where c.count >= 10
select q;
Just use Count with a predicate directly:
query.Where(item => context.Table.Count(table.amount == item.Amount) >= 10);
what about this one
var subQuery = (from table in context.Table select table.amount).ToList();
query = query.Where(item => subQuery.Count() >= 10);

Linq Getting Customers group by date and then by their type

I am working on generating report for showing customer using LINQ in C#. I want to show no. of customers of each type.
There are 3 types of customer registered, guest and manager. I want to group by customers by registered date and then by type of customer. i.e If today 3 guest, 4 registered and 2 manager are inserted. and tomorrow 4,5 and 6 are registered resp. then report should show Number of customers registerd on the day . separate row for each type.
DATE TYPEOF CUSTOMER COUNT
31-10-2013 GUEST 3
31-10-2013 REGISTERED 4
31-10-2013 MANAGER 2
30-10-2013 GUEST 5
30-10-2013 REGISTERED 10
30-10-2013 MANAGER 3
LIKE THIS .
var subquery = from eat in _customerRepo.Table
group eat by new { yy = eat.CreatedOnUTC.Value.Year, mm = eat.CreatedOnUTC.Value.Month, dd = eat.CreatedOnUTC.Value.Day } into g
select new { Id = g.Min(x => x.Id) };
var query = from c in _customerRepo.Table
join cin in subquery.Distinct() on c.Id equals cin.Id
select c;
By above query I get minimum cutomers registerd on that day
Thanks in advance
var query = _customerRepo.Table
.GroupBy(c => new {Date = c.Date.Date, Type = c.TypeOfCustomer})
.Select(g => new
{
Date = g.Key.Date,
Type = g.Key.Type,
Count = g.Count
}
)
.OrderByDescending (r = r.Date);
var query = from c in _customerRepo.Table
group c by new { c.TypeOfCustomer, c.Date } into g
orderby g.Key.Date descending,
g.Key.TypeOfCustomer == "GUEST" ? 1 :
g.Key.TypeOfCustomer == "REGISTERED" ? 2 : 3
select new {
g.Key.Date,
g.Key.TypeOfCustomer,
Count = g.Count()
};
You can remove second ordering if it's not required for daily results to be in order guest > registered > manager:
var query = from c in _customerRepo.Table
group c by new { c.TypeOfCustomer, c.Date } into g
orderby g.Key.Date descending
select new {
g.Key.Date,
g.Key.TypeOfCustomer,
Count = g.Count()
};

LINQ query to group records by month within a period

I am looking for some help on adapting the following LINQ query to return all dates within the next 6 months, even those where no records fall within the given month.
var maxDate = DateTime.Now.AddMonths(6);
var orders = (from ord in db.Items
where (ord.Expiry >= DateTime.Now && ord.Expiry <= maxDate)
group ord by new
{
ord.Expiry.Value.Year,
ord.Expiry.Value.Month
}
into g
select new ExpiriesOwnedModel
{
Month = g.Select(n => n.Expiry.Value.Month).First(),
Quantity = g.Count()
}).ToList();
I'd really appreciate any assistance or pointers on how best to implement this.
I'm not sure how well it'll interact with your database, but I'd do this as with a join:
var firstDaysOfMonths = Enumerable.Range(0, 7).Select(i =>
new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddMonths(i));
var orders = firstDaysOfMonths.GroupJoin(
db.Items,
fd => fd,
ord => new DateTime(ord.Expiry.Value.Year, ord.Expiry.Value.Month, 1),
(fd, ords) => new { Month = fd.Month, Quantity = ords.Count() });
Note you may end up with an extra month where before you didn't (on the first day of the month?)
Stolen from Rawling's answer, if you prefer query syntax for group joins (I do):
var orders =
from month in Enumerable.Range(0, 7)
.Select(i => new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddMonths(i))
join ord in db.Items
on month equals new DateTime(ord.Expiry.Value.Year, ord.Expiry.Value.Month, 1)
into ords
select new { month.Month, Quantity = ords.Count() };
Alternative if it does not play nice with the database:
var rawGroups = db.Items.Where(item.Expiry >= DateTime.Now && ord.Expiry <= maxDate)
.GroupBy(item => new
{
item.Expiry.Value.Year,
item.Expiry.Value.Month
}, g => new ExpiriesOwnedModel()
{
Month = g.Key.Month,
Quantity = g.Count()
}).ToDictionary(model => model.Month);
var result = Enumerable.Range(DateTime.Now.Month,6)
.Select(i => i > 12 ? i - 12 , i)
.Select(i => rawGroups.Keys.Contains(i) ?
rawGroups[i] :
new ExpiriesOwnedModel()
{ Month = i , Quantity = 0 });

Categories

Resources