Get the sum after a linq join - c#

I'm using this linq query to get a list of doubles. The list looks correct, but now I need to total the doubles in the list.
var total = from sauId in schools
join item in entities.AmountTable
on sauId equals item.sauId
select item.amount;

Use Sum() on the result:
var total = (from sauId in schools
join item in entities.AmountTable
on sauId equals item.sauId
select item.amount).Sum();
If item.amount is a double, then total is also a double.

For anyone looking for fluent syntax, I believe this would be the way to do it:
var total = schools
.Join(
entities.AmountTable,
s => s.sauId,
at => at.sauId,
(s, at) => at.amount)
.Sum();

Try to group data by its sauId:
var qry = from item in entities.AmountTable
group item by item.sauId into grp
select new {
sauId = grp.Key,
amuont = grp.Sum(c=>c.amount)
};

Related

EF LINQ Group By and Sum

I'm trying to do select with group by and sum while selecting other columns using LINQ and i come out with this
var inputList = from c in db.InputItem
join o in db.ItemsDefinition on c.ItemsDefinitionID equals o.ItemsDefinitionID
group c by new { c.ItemsDefinitionID, o.ItemsAName } into g
select new
{
Name = g.Key,
Sum = g.Sum(c => c.Quantity)
};
what I'm trying to do is to preform this SQL statement
Select i.ItemsDefinitionID,
ID.ItemsAName,
sum(Quantity) as avialable
from InputItem i
Left Outer Join ItemsDefinition ID On i.ItemsDefinitionID=ID.ItemsDefinitionID
group by i.ItemsDefinitionID,ID.ItemsAName
Warm Thanks
you can do this way too:
var inputList = d.InputItem
.GroupBy(s =>s.ItemsDefinitionID, s.ItemsDefinition.AName)
.Select(g => new
{
ItemsDefinitionID=g.Key.ItemsDefinitionID,
Name = g.Key.AName,
Available= g.Sum(s =>s.Quantity),
})
.ToList();
You don't really need to do manual joins in EF if your relationships are properly defined in the model.
This query will suffice
var result = db.ItemsDefinition.Select(id => new { id.ItemsDefinitionID,
id.ItemsAName, Quantity = id.Items.Sum(i => i.Quantity) });
Either leave the SQL generation to EF or stop using EF. There's no point in using an ORM if you keep worrying about the queries it will generate.

Converting SQL to LINQ with Multiple Tables and Group

There seem to be lots of questions about SQL to LINQ, but I can't seem to find examples with joined tables and grouping; specifically with a need to get data from multiple tables.
Take this simple SQL:
SELECT
s.showId, s.showName, v.venueName, Min(dateTime) startDate
FROM
shows s
INNER JOIN venues v ON s.venueId = v.venueId
INNER JOIN showDates d ON s.showId = d.showId
GROUP BY
s.showId
The best I can come up with is the following
var ungrouped = (
from s in db.Shows
join v in db.Venues on s.VenueId equals v.VenueId
join d in db.ShowDates on s.ShowId equals d.ShowId
select new { s, v, d }
).ToList();
var grouped = (
from s in ungrouped
group s by s.s.ShowId into grp
select new
{
showId = grp.Key,
name = (from g in grp select g.s.showName).FirstOrDefault(),
venue = (from g in grp select g.v.VenueName).FirstOrDefault(),
startDate = grp.Max(g => g.d.DateTime)
}
);
This works but it feels messy. I don't like:
It being split into two statements
Having to repeatedly write (from g in grp select ...).FirstOrDefault()
Bits like s.s.ShowId
How its vastly more lines of code than the SQL
This example is a simple one, it only gets worse when I have 5+ tables to join and 10+ columns to select.
Question: Is this the best way to do this, and I should just accept it; or is there a better way to write this query?
I am not sure if you are looking for something like this but it's a bit cleaner, it's not split in 2 statements and you might find it helpful. I couldn't use a dbcontext so I used lists to make sure the syntax is correct.
var res = Shows.Join(Venues,
show => show.VenueID,
venue => venue.VenueID,
(show, venue) => new { show, venue })
.Join(ShowDates,
val => val.show.ShowID,
showdate => showdate.ShowID,
(val, showDate) => new { val.show, val.venue, showDates = showDate })
.GroupBy(u => u.show.ShowID)
.Select(grp => new
{
showId = grp.Key,
name = grp.FirstOrDefault()?.show.showName,
venue = grp.FirstOrDefault()?.venue.VenueName,
startDate = grp.Max(g => g.showDates.DateTime)
});
we need to now realation beetwen them one to one or one to many , but not too far from this answer.
var GrouppedResult = Shows.Include(x=>x.Veneu).Include(x=>x.ShowDates)
.Where(x=>x.Veneu.Any()&&x.ShowDates.Any())
.GroupBy(x=>x.ShowId)
.Select(x=>///anything you want);
or
from show in Shows
join veneu in Veneu on veneu.VeneuId equals show.VeneuId
join showDates in ShowDates on showDates.ShowId=show.ShowID
group show by show.Id into grouppedShows
select new { ///what you want };

Query to select worst-selling products

I have these 3 tables/classes in the Entity Framework model:
Orders (OrderedItems, OrderTime)
OrderedItems (Product, Qty)
Products (Name, CreatedTime)
I can select the best-selling products by doing this
var items = Orders.SelectMany(o => o.OrderedItems);
var products = items.GroupBy(oi => oi.Product)
.OrderByDescending(g => g.Sum(oi => oi.Qty))
.Select(g => g.Key).Take(10);
How do I select the worst-performing products (ie. the opposite)?
Note: Worst-performing products may not exists in the Orders table because they may never be ordered.
You can start with the Products table and find matches from there. One way is to use the join into clause to group join the Products table with the OrderedItems:
var items = Orders.SelectMany(o => o.OrderedItems);
var products = (from product in Products
join item in items on product equals item.Product into matchingItems
orderby matchingItems.Sum(oi => oi.Qty)
select product).Take(10);
Another way, which is probably less efficient but you might find more readable, is to filter the items using Enumerable.Where():
var items = Orders.SelectMany(o => o.OrderedItems);
var products = (from product in Products
orderby items.Where(oi => oi.Product == product).Sum(oi => oi.Qty)
select product).Take(10);
This translates nicely into method syntax:
var items = Orders.SelectMany(o => o.OrderedItems);
var products = Products.OrderBy(p => items.Where(oi => oi.Product == product)
.Sum(oi => oi.Qty))
.Take(10);
var items = Orders.SelectMany(o => o.OrderedItems);
var products = items.GroupBy(oi => oi.Product)
.OrderBy(g => g.Sum(oi => oi.Qty))
.Select(g => g.Key).Take(10);
Try
OrderBy(g => g.Sum(oi => oi.Qty))
it will put minimum sums first.
Just change OrderByDescending to OrderBy and it should order them in ascending order.
It seems you need a left outer join from Products to OrderedItems. productsQty should contain a list of Products with Qty from OrderedItems or 0 if there was none.
var productQty = from p in Products
join oi in OrderedItems on p equals oi.Product into joined
from poi in joined.DefaultIfEmpty()
select new { Product = p, Qty = poi == null ? 0 : poi.Qty };
var products = productQty.GroupBy(p => p.Product).OrderBy(g => g.Sum(oi => oi.Qty)).Take(10);
UPDATE: Query corrected.

How to filter entity framework result with multiple columns using a lambda expression

I have the following table:
And the following data:
How can i filter the result, so that i only get the latest row from each omraade_id (sorted descending by timestamp)?
Which in this case would be the rows with id: 1010 and 1005
--
From #lazyberezovsky's answer, i have created the following expression:
dbConnection = new ElecEntities();
var query = from data in dbConnection.Valgdata
orderby data.timestamp descending
group data by data.omraade_id into g
select g.FirstOrDefault();
return query.ToList();
It returns two rows with the ID 3 and 4, which are the first two rows in the database, and also the ones with the lowest timestamp. Any idea why?
var query = dbConnection.Valgdata
.GroupBy(x => x.omraade_id)
.Select(g => g
.OrderByDescending(x => x.timestamp)
.FirstOrDefault());
I have no experience with EF, so I'm unsure if only SQL-esque linq works here. A plain C#-ish:
var query = dbConnection.Valgdata.GroupBy(u => u.omraade_id)
.Select(x => x.FirstOrDefault(y => x.Max(p => p.timestamp) == y.timestamp));
You have put filter on every item. It should be applied on complete query result, not on every item.
Following is updated query.
var query = (from data in dbConnection.Valgdata
orderby data.timestamp descending
group data by data.omraade_id into g
select g).FirstOrDefault();
var query = from v in dbConnection.Valgdata
orderby v.timestamp descending
group v by v.omraade_id into g
select g.First();
This will return only record with max timestamp for each omraade_id.
UPDATE query above works fine to me (at least for MS SQL Linq provider). Also you don't need to do FirstOrDefault - if omraade_id is grouped, then it definitely has at least one row.
var query = from v in dbConnection.Valgdata
group v by v.omraade_id into g
select g.OrderByDesc(x => x.timestamp).First();
This is my solution so far:
var data = dbConnection.Valgdata.Where(x => x.godkendt == false).ToList();
var dataGrouped = data.GroupBy(x => x.omraade_id).ToList();
List<Valgdata> list = new List<Valgdata>();
foreach (var grpdata in dataGrouped)
{
var dataGroup = grpdata.OrderByDescending(x => x.timestamp).ToList();
list.Add(dataGroup.FirstOrDefault());
}
return list;
I dont know if it is the most effective, but it works.

Linq Grouping Order By Date then Time

Good Evening,
I've managed to get my Linq query almost correct. There is just one more issue I'm struggling to resolve.
My query is
var o =
(from c in x
group c by x.Date.Date into cc
select new
{
Group = cc.Key.Date,
Items = cc.ToList(),
ItemCount = cc.Count()
}).OrderByDescending(p => p.Group);
Now this query works fine. It groups within a ListView by the date. x.Date is a DateTime field in my SQL Database. Therefore I'm selecting x.Date.Date to Group by the actual Date of the DateTime field, as if it was just x.Date it would Group by the date and time.
My question is, how do I group by time so the newest time is at the top of the group?
Many thanks
Use the linq "ThenBy()" method:
var o = (from c in x group c by x.Date.Date into cc select new
{
Group = cc.Key.Date,
Items = cc.OrderByDescending(y=>y.Date).ToList(),
ItemCount = cc.Count()
})
.OrderByDescending(p => p.Group)
Change Items = cc.ToList() to Items = cc.OrderBy(c => c.[field_you_want_to_sort_by]).ToList()
var o =
(from c in x
group c by c.Date.Date into cc
select new
{
Group = cc.Key.Date,
Items = cc.OrderByDescending(a=>a.Date.Time).ToList(),
ItemCount = cc.Count()
}).OrderByDescending(p => p.Group);

Categories