How to sum a field grouped by another in LINQ? - c#

I am trying to find a away to SUM all the QUANTITY for a specific RECIPE (all its ingredients) into a single value to get the TOTAL QUANTITY
Assuming I have the following dataset:
RecipeName IngredientName ReceiptWeight
Food1 Ingredient1 5
Food1 Ingredient2 2
Food2 Ingredient1 12
Food2 Ingredient3 1
And I would expect to get the following:
RecipeName ReceiptWeight
Food1 7
Food2 13
The code I have so far is:
Grouping =
(
from data in dataset
group data by data.RecipeName into recipeGroup
let fullIngredientGroups = recipeGroup.GroupBy(x => x.IngredientName)
select new ViewFullRecipe()
{
RecipeName = recipeGroup.Key,
ReceiptWeight = ????
How can I get the value for RecipeWeight?
Thanks,

LINQ does have sum
from d in dataset
group d by new { d.RecipeName } into g
select new {
g.Key.RecipeName,
ReceiptWeight = g.sum(o => o.ReceiptWeight)
}

Related

Find Sum of product of 2 columns in LINQ

Find sum of product of 2 columns in LINQ
I have a list of educationprogram objects with 2 properties NOOfPerson & Hours.
I want a sum of product of 2 properties
SUM[NOOfPersons*Hours]
How can I write a LINQ query for this?
List<educationprogram> edu = (from e in dbContext.educationprograms
where e.YearId == 2015
select e).ToList();
This returns the list of object I have to use. But how can I return SUM[Col1*Col2]?
If the two columns are under the educationprograms table then:
var sum = dbContext.educationprograms.Sum(ep => ep.NoOfPeople * ep.Hours);
you can also add a Where clause:
var sum2 = dbContext.educationprograms.Where(e => e.Year == 2015).Sum(ep => ep.NoOfPeople * ep.Hours);
var edu= from e in dbContext.educationprograms
where e.YearId == 2015
select new
{
sum = e.NoofPersons*e.Hours
}).ToList();
now edu is the list of products of noofperson column and hours column.

Linq to sql calculating a percentage of a group of items in query

New to Linq to SQL and novice in SQL. First post so please be gentle.
I have something similar to the following table I am querying into a dataGridView based on a date range in C#.
HeatNumber ChargeNumber Weight DOB
1 1 500 8/26/15
1 2 3500 8/26/15
1 3 2200 8/26/15
2 1 2000 8/27/15
2 2 1100 8/27/15
var query = from SU in dct.GetTable<ScrapInCharge>()
where ((SU.DOB >= dateTimePicker2.Value.Date) &&
(SU.DOB <= dateTimePicker1.Value.Date))
orderby SU.HeatNumber descending
select SU;
scrapInChargeBindingSource.DataSource = query;
I need to add a column that shows the percentage of the total HeatNumber weight that each ChargeNumber makes up. I did figure how to get the total weight of each heat by HeatNumber.
var TotalHeatWgt = from a in dct.ScrapInCharges
where ((a.DOB >= dateTimePicker2.Value.Date) &&
(a.DOB <= dateTimePicker1.Value.Date))
group a.Weight by a.HeatNumber
into b
select new { HeatNumber = b.Key, TotalWgt = b.Sum() };
I am currently stuck on how to combine this into a single C# query inserting a % of Heat column after the weight column. Can this be done or would I need to add an unbound column to the dataGridView % of Heat and iterate over the rows using my return values of the TotalHeatWgt query?
Simple attempt:
var results = data.Select(d => new {
d.HeatNumber,
d.ChargeNumber,
d.Weight,
Percent = 100.0 * d.Weight / data.Where(dd => dd.HeatNumber == d.HeatNumber).Sum(dd => dd.Weight)
});
or
from row in data
select new {
row.HeatNumber,
row.ChargeNumber,
row.Weight,
Percent = 100.0 * row.Weight / (from innerRow in data
where innerRow.HeatNumber == row.HeatNumber
select innerRow.Weight
).Sum()
};
The one below will be more performant (at least in memory, I'm not sure if it'll be better in SQL):
var results = data.GroupBy (d => d.HeatNumber)
.SelectMany (grp => grp.Select(row => new {
row.HeatNumber,
row.ChargeNumber,
row.Weight,
Percent = 100.0 * row.Weight / grp.Sum(dd => dd.Weight)
})
);
And with query syntax:
from row in data
group row by row.HeatNumber into grp
from innerRow in grp
select new {
innerRow.HeatNumber,
innerRow.ChargeNumber,
innerRow.Weight,
Percent = 100.0 * innerRow.Weight / grp.Sum(dd => dd.Weight)
};
They both print this result:
HeatNumber ChargeNumber Weight Percent
1 1 500 8.06451612903226
1 2 3500 56.4516129032258
1 3 2200 35.4838709677419
2 1 2000 64.5161290322581
2 2 1100 35.4838709677419
Is that what you're after? I've omitted the filtering by date just for simplicity, since the actual problem comes after that

Linq query to sum by group

I have a data table like this:
Category Description CurrentHours CTDHours
LC1 Cat One 5 0
LC2 Cat Two 6 0
LC3 Cat Three 18 0
LC1 Cat One 0 9
LC2 Cat Two 0 15
LC4 Cat Four 0 21
That I need to Group and Sum to this:
Category Description CurrentHours CTDHours
LC1 Cat One 5 14
LC2 Cat Two 6 21
LC3 Cat Three 18 0
LC4 Cat Four 0 21
In other words I need to sum the two Hours columns grouping by the Category and Description columns.
I know that I could build a new table and loop through the existing data and sum the data into the new table but I thought there would be an easier way to do it using Linq. I've googled it for a few hours but all the examples I found didn't seem to fit what I was trying to do.
BTW, the odbc driver that creates the data table does not have the capability for sub queries, etc. or I would have just done it using SQL.
Use anonymous object to group by category and description. Here is Linq to DataSet query which returns grouped hours:
from r in table.AsEnumerable()
group r by new {
Category = r.Field<string>("Category"),
Description = r.Field<string>("Description")
} into g
select new {
Category = g.Key.Category,
Description = g.Key.Description,
CurrentHours = g.Sum(x => x.Field<int>("CurrentHours"),
CTDHours = g.Sum(x => x.Field<int>("CurrentHours") + x.Field<int>("CTDHours"))
}
If you are querying database (not clear from question):
from r in context.Table
group r by new {
r.Category,
r.Description
} into g
select new {
g.Key.Category,
g.Key.Description,
CurrentHours = g.Sum(x => x.CurrentHours),
CTDHours = g.Sum(x => x.CTDHours + x.CurrentHours)
}
You need to sum CurrentHours and CTDhours, so -
select new {
...
CTDHours = g.Sum(x => x.Field<int>("CTDHours") + g.Sum(x => x.Field<int>("CurrentHours")
}

Group by in Linq to get further details

I have table data as:
Fname Lname Date ForeignKey
A B 2012-01-01 1
A B 2012-11-01 1
A B 2013-12-25 1
C K 2009-01-01 2
C K 2001-11-01 2
C K 2011-12-25 2
My table is referred as ABC in EF
So I want to group them by Foreign Key, and I am able to do that by using this query, but How to get the details of each row now?
var q = from abc in context.ABC
group abc by abc.ForeignKey into g
join efg in context.EFG on g.Key equals efg.AppId
select new
{
MortgId = g.Key,
TrackingDate = g.Max(val => val.Date),
Fname=g.?,
Lname=g.?,
Sale=efg.SalesAmount
};
foreach(var result in q)
{
if(result.Fname=="A")
{
}
}
It returns me the list.
This gives me the Record of maximum date but I want to get the details of Fname and Lname of this Maximum Date and I am not able to get any clue.
UPDATE:
The result should be like this:
Fname Lname Date ForeignKey
A B 2013-12-25 1
C K 2011-12-25 2
I want to get the details against the maximum date.
NEW UPDATE:
So I want to check on the basis of Fname and I have made a question mark that how to get the Fname of the maximum date result.
I hope it is clear now.
Get object which has max date for each group by ordering by descending, and get first:
var list = context.ABC.GroupBy(abc => abc.ForeignKey)
.Select(g => g.OrderByDescending(a => a.Date).First())
Then you can get other properties easily:
foreach (var abc in list)
{
var fname = abc.Fname;
var lname = abc.Lname;
}

Populating an ObservableCollection of ObservableCollection, delimited by two database columns

My database is as follows :
ID Date Number NumberIWishToRecord
What I wish to do is use a Linq-to-SQL query to populate an ObservableCollection<ObservableCollection<CustomClass>>.
What I want is select only the rows were Number == a given parameter.
ID refers to a person, what I want to do is get all the information about a person and store it in an ObservableCollection, so I will have an ObservableCollection<CustomClass>, with each CustomClass holding information about only one row, and each ObservableCollection<CustomClass> holding information about only one person (recorded on different days).
I then wish to select an ObservableCollection of the ObservableCollection<CustomClass> which will hold information on all people!
So, some sample data :
ID Date Number NumberIWishToRecord
1 27-06-2012 0.1933 25
1 28-06-2012 0.1933 27
1 29-06-2012 0.1933 29
2 14-06-2012 0.1933 412
2 15-06-2012 0.1741 321
So when I run my method, I want to return only the Numbers of the given parameter, in my case I will choose 0.1933.
I then want both rows where ID = 1 to be saved in an ObservableCollection<CustomClass>, and the single row where ID == 2 to be saved in another ObservableCollection<CustomClass>. Then, both of these ObservableCollections will be held in their own ObservableCollection! To illustrate :
ObservableCollection<ObservableCollection<CustomClass>>
ObservableCollection<CustomClass>
1 27-06-2012 0.1933 25
1 28-06-2012 0.1933 27
1 29-06-2012 0.1933 29
ObservableCollection<CustomClass>
2 14-06-2012 0.1933 412
How would I write a query in linq to sql that would do this ?
I'll just write a standard query syntax Linq expression to achieve this, you adapt it for your tables.
var rowsById = new ObservableCollection<ObservableCollection<row>>(
from r in _rows
where r.number == 1.2
group r by r.ID into rowIdGroup
select new ObservableCollection<row>(rowIdGroup));
If you need to convert data from the row into the CustomClass:
var rowsById = new ObservableCollection<ObservableCollection<CustomClass>>(
from r in _rows
where r.number == 1.2
group r by r.ID into rowIdGroup
select new ObservableCollection<CustomClass>(
rowIdGroup.Select(r => new CustomClass
{
ID = r.ID,
Number = r.number // add more
})));
Or if you prefer query syntax in all the expression:
var rowsById = new ObservableCollection<ObservableCollection<CustomClass>>(
from r in _rows
where r.number == 1.2
group r by r.ID into rowIdGroup
select new ObservableCollection<CustomClass>(
from gr in rowIdGroup select new CustomClass
{
ID = gr.ID,
Number = gr.number
}));

Categories