how to group by multiple columns using linq [duplicate] - linq

This question already has answers here:
Group By Multiple Columns
(14 answers)
Closed 9 years ago.
I have a database table with a dataset that contains multiple rows of data as follows
ItemId Code StatusId
-------------------- ---------------------------------------------
62224 NC0860000 8
62225 NC0860000 8
62226 NC0860000 8
62227 NC0860200 5
62228 NC0860000 5
62229 NC0860000 5
62230 NC0860000 5
What I would like to accomplish is an output result as
NC0860000 8 3 (code, status, count)
NC0860000 5 3
I don't fully understand how grouping works in EF. I can get the key and a count of a single group using a query as:
var results = (from ssi in ctx.StageSubmitItems
join s in ctx.StageSubmissions on ssi.SubmissionId equals s.SubmissionId
where s.ContributorCode == contributorId
group ssi.SubmitItemId by ssi.AgencyCode into g
select new {AgencyCode = g.Key, Count = g.Count() }).ToList();
But I can't figure out how to group by code and then by StatusId and then produce a count of the total number of rows by status.
I'd appreciate any suggestions on where to look on how to accomplish this or what I am doing incorrectly in the query.

You can group by a new anon class as follows:
// I created a Foo class to show this working
var fooList = new List<Foo> {
new Foo { ItemId = 62224, Code = "NC0860000", StatusId = 8 },
new Foo { ItemId = 62225, Code = "NC0860000", StatusId = 8 },
new Foo { ItemId = 62226, Code = "NC0860000", StatusId = 8 },
new Foo { ItemId = 62227, Code = "NC0860200", StatusId = 5 },
new Foo { ItemId = 62228, Code = "NC0860000", StatusId = 5 },
new Foo { ItemId = 62229, Code = "NC0860000", StatusId = 5 },
new Foo { ItemId = 62230, Code = "NC0860000", StatusId = 5 },
};
var results = (from ssi in fooList
// here I choose each field I want to group by
group ssi by new { ssi.Code, ssi.StatusId } into g
select new { AgencyCode = g.Key.Code, Status = g.Key.StatusId, Count = g.Count() }
).ToList();
// LINQPad output command
results.Dump();
With the data provided, here is the output:
AgencyCode Status Count
NC0860000 8 3
NC0860200 5 1
NC0860000 5 3
I am guessing "NC0860200" is an error, but it is in your sample data so I included it.

Related

Group by and Count result in LinQ

I have 1 very basic table which I need to query in order to get the amount (count) of rooms in each building code using a LinQ query.
So far i have this:
var myQuery =
from s in Locations
group s.Room by s.BldgCode into t
select t.Count();
myQuery.Dump();
with this output
Query (3 items)
2
4
7
How can I include the Building code details so I have an output like this:
BldgCode NoRooms (3 items)
A 2
B 4
C 7
foreach(var line in data.GroupBy(info => info.Room )
.Select(group => new {
BldgCode = group.Key,
NoRooms = group.Count()
})
{
Console.WriteLine("{0} {1}", line.BldgCode , line.NoRooms );
}

How to .GroupBy multiple columns LINQ/Projection?

How can I group by multiple columns using linq projection?
Something like this:
var q = db.Areas.GroupBy(x => x.AreaCatId, x.AreaCatName, x.AreaId, x.AreaName);
Resulting in a flat result set such as:
AreaCatId, AreaCatName, AreaId, AreaName
0 US 1 FL
0 US 2 NY
1 Canada 3 BC
You can GroupBy an anonymous type:
var q = db.Areas.GroupBy(
x => new
{
CatId = x.AreaCatId,
CatName = x.AreaCatName,
Id = x.AreaId,
Name = x.AreaName
});

Linq extract a count() value from a data object

I have divAssignments that has potential multiple rows by rNI, an official id, according to a compound key of Indictment and booking numbers.
rNI Booking Indictment
12345 954445 10 12345
12345 954445 10 12346
12345 954445 10 12347
So ID has a count of 3 for a single booking number for this rni.
I get lost attempting to generate a count and a group by booking Number:
var moreThen = from dA in divAssignments
select new { dA.rNI, IndictmentCount = dA.indictmentNumber.Count() };
Most of the examples are dealing with static int[] and don't seem to work in my case.
How do I get a group and then a count? If I could put in a having that would be fantastic.
from a t-sql POV I'd use this:
Select rni, bookingNumber, count(*) IndictmentCount
from divAssignments
group by rni, bookingNumber
having count(*) > 0
TIA
How about something like this:
var query = from item in divAssignments
group item by item.rNI into grouping
select new
{
Id = grouping.Key,
Count = grouping.Count()
}
If you're interested in grouping by both the rNI and the booking number, I would change it to this:
var query = from item in divAssignements
group item by new { item.rNI, a.Booking } into grouping
select new
{
Id = grouping.Key,
Count = grouping.Count
};
OR
var query = from item in divAssignments
group item by item into grouping
select new
{
Id = grouping.Key,
Count = grouping.Count()
}
and implement IEquatable on the divAssignment object to support equality comparison. The other option if you'd like is to write an IEqualityComparer instance to do the composite key comparison. Your query could then look like:
var query =
divAssignments
.GroupBy(i => i, new MyCustomEqualityComparer())
.Select(i => new { Key = i.Key, Count = i.Count());
var query =
from dA in divAssignments
group dA by new { dA.rNI, dA.bookingNumber };
foreach(var grp in query)
{
Console.WriteLine("rNI={0}, bookingNumber={1} => Count={2}", grp.Key.rNI, grp.Key.bookingNumber, grp.Count());
}
If you use a Grouping operator in Linq you will get what you need. The code:
var count = from a in divAssignments
group a by new { a.rNI, a.Booking } into b
select b;
will return a collection of IGrouping objects. This will give you the Key (in my example this will be an anonymous type with an rNI and a Booking property) and a collection of the divAssignments that match the key.
Using Method syntax (much easier to read in my opinion):
First group the records, then select a new result for each group that contains the count.
var groups = divAssignments.GroupBy(d => new { d.rNI, d.Booking });
groups.Select(g=> new { g.Key.rNI, g.Key.Booking, IndictmentCount = g.Count() });

LINQ Join With Multiple Where Clause

I am struggling once again so any help would be gratefully received.
I have the following LINQ that pulls back a list of data:
public static List<tblWeight> GetWeights(string memberid, string locationid, string buyer, string subcategory, string product)
{
MyEntity getweights = new MyEntity ();
var r = (from p in getweights.tblWeights
where p.MemberId == memberid &&
p.LocationId == locationid
select p);
if (buyer != "Not Specified")
r = r.Where(p => p.UnitUserField1 == buyer);
if (subcategory != "Not Specified")
r = r.Where(p => p.UnitUserField2 == subcategory);
if (product != "Not Specified")
r = r.Where(p => p.IDDesc == product);
return r.ToList();
}
Lovely!
What I would like to do now is based upon this result set and the unit IDs (IDDesc), I then go to tblPurchase, pull back a few columns from tblPurchases and group the columns.
So for example, we have tblWeight looking like so:
MemberID LocationID Buyer SubCategory IDDesc
1 1 Cat1 Sub1 ab
1 1 Cat1 Sub1 abc
1 1 Cat1 Sub2 abcd
The user makes a search for Sub1 in subcategory and the above LINQ does the trick and pulls back the first two rows from above. Fine.
What I need the LINQ to do now is to go to tblPurchases:
MemberID LocationID IDDesc SupplierID SupplierStatus
1 1 ab Sup1 Live
1 1 abc Sup1 Live
1 1 abcd Sup2 Dead
And then pull back the following result so it is joined on MemberID, LocationID and IDDesc but just selects tblPurchases.
Sup1 Live (or all columns in tblPurchases, just grouped/distinct)
I have tried to add in a join and on but no matter how many different variations, I still come across the red squiggle of doom!!!
If anyone can help, beer/kiss is on offer again.
The following LINQ query should do what you want:
var result = from w in tblWeight
where w.SubCategory == "Sub1"
join p in tblPurchases on
new { w.MemberID, w.LocationID, w.IDDesc } equals
new { p.MemberID, p.LocationID, p.IDDesc }
group p by new { p.SupplierID, p.SupplierStatus } into pg
select pg.Key;
The variable result is a list containing tuples of SupplierID and SupplierStatus.
If you also want to put the conditional parts in there, it gets a little more complicated. Here's how to do it:
var weights = from w in tblWeight
select w;
weights = weights.Where(w => w.SubCategory == "Sub1");
// You can add additional where clauses here.
// Now join with tblPurchases and group by SupplierID and SupplierStatus.
var result =
weights.Join(tblPurchases,
w => new { w.MemberID, w.LocationID, w.IDDesc },
p => new { p.MemberID, p.LocationID, p.IDDesc },
(w, p) => p)
.GroupBy(p => new { p.SupplierID, p.SupplierStatus },
(k, ps) => new
{
k.SupplierID,
k.SupplierStatus,
TotalQty = ps.Sum(p => p.PurchaseQty)
});

LINQ | How do I get SUM without grouping?

Crazy question...however, I want the sum of all the rows in a table for a column (without using the group by clause)
Example:
Table = Survey
Columns = Answer1, Answer2, Answer3
1 1 1
4 3 5
3 3 2
I want the sums for each column.
Final results should look like:
Answer1Sum Answer2Sum Answer2Sum
8 7 8
This doesn't work:
from survey in SurveyAnswers
select new
{
Answer1Sum = survey.Sum(),
Answer2Sum = survey.Sum(),
Answer3Sum = survey.Sum()
}
Would this work:
var answer1Sum = SurveyAnswers.Sum( survey => survey.Answer1 );
var answer2Sum = SurveyAnswers.Sum( survey => survey.Answer2 );
var answer3Sum = SurveyAnswers.Sum( survey => survey.Answer3 );
A VB.NET soltuion to this answer for anyone that needs it is as follows:
Dim Answer1Sum = SurveyAnswers.Sum(Function(survey) survey.Answer1)
Dim Answer2Sum = SurveyAnswers.Sum(Function(survey) survey.Answer2)
Dim Answer3Sum = SurveyAnswers.Sum(Function(survey) survey.Answer3)
SurveyAnswers.Sum(r => r.Answer1);

Resources