multiple grouping, inner joning in Linq - linq

I am trying to translate this into Linq and cannot figure it out:
SELECT
CustomerOrder.ShipState, MONTH(OrderFulfillment.OrderDate) AS Mnth,
YEAR(OrderFulfillment.OrderDate) AS Yer,
SUM(OrderFulfillment.Tax) AS TotalTax
FROM
OrderFulfillment INNER JOIN
CustomerOrder ONOrderFulfillment.OrderID =CustomerOrder.OrderID
WHERE
(OrderFulfillment.Tax > 0)
GROUP BY
CustomerOrder.ShipState, MONTH(OrderFulfillment.OrderDate),
YEAR(OrderFulfillment.OrderDate)
ORDER BY
YEAR(OrderFulfillment.OrderDate) DESC, CustomerOrder.ShipState,
MONTH(OrderFulfillment.OrderDate) DESC
I have Linqpad and have gone through a bunch of the examples but cannot figure this out.

I think you want to do something like this:
from c in CustomerOrder
join o in OrderFulfillment on c.OrderId equals o.OrderId
where
o.Tax > 0
group o by
new { c.ShipState, Mnth = of.OrderDate.Month, Yer = of.OrderDate.Year }
into g
orderby
g.Key.Yer descending, g.ShipState, g.Key.Mnth descending
select
new { g.Key.ShipState, g.Key.Mnth, g.Key.Yer,
TotalTax = g.Sum(i => i.Tax) };
I haven't tried to compile it, but I think this is something along the lines of what you want.
The idea is that first you perform your join to link the customers and orders. Then apply your filter condition.
At that point, you want to get all the orders that have a particular group, so the group operator is applied.
Finally, order the results, then select out all info from the keys for each group, and sum up the tax in each of the group.

First of all, it would be nice to know what exactly you can't figure out. If you're completely lost and don't know where to begin then you need to google around for linq joining and grouping.
Here's something I did recently that may (possibly) point you in the right direction:
// This groups items by category and lists all category ids and names
from ct in Categories
join cst in Category_Subtypes
on ct.Category_Id equals cst.Category_Id
join st in Subtypes
on cst.Subtype_Id equals st.Subtype_Id
where
st.Type_Id == new Guid(id)
group ct by new { ct.Category_Id, ct.Display_Text } into ctg
select new
{
Id = ctg.Key.Category_Id,
Name = ctg.Key.Display_Text
}

Related

linq query grouping and joining getting incorrect sum

I have the following code which is grouping and summing some values.
The sum "TotalCost" value is correct, however, when i uncomment the lines the sum value is wrong (its less than it should be)
Im doing something wrong, but cant figure this out. any ideas?
from orderItem in Order_ProductItem
//join ho in Hardware_Items on orderItem.OuterColour equals ho.Index
//join hi in Hardware_Items on orderItem.InnerColour equals hi.Index
where orderItem.SalesOrderID == 3272 && (orderItem.IsDeleted==null || orderItem.IsDeleted.Value == false)
group new { orderItem/*, hi, ho*/} by orderItem.FrameNo into grp
select new OrderItemModel
{
FrameNo = grp.Key,
TotalCost = grp.Sum(x => x.orderItem.SellingPrice),
//InternalColor = grp.FirstOrDefault().hi.Name,
//ExternalColor = grp.FirstOrDefault().ho.Name,
Quantity = grp.FirstOrDefault().orderItem.Quantity,
}
Basic Schema
Order_ProductItem
FrameNo
OuterColour
InnerColour
SellingPrice
Hardware_Items
Index
Name
The Order_ProductItem has FrameNo which is listed multiple times in the table, so im trying to get it to group them, then sum the SellingPrice of each row that has the same FrameNo.
If i exclude the bit to obtain colour (internal and external) the sum is correct.
In that case how can i also include the inner and outer color names?
You probably need to use a left join, because the inner join is filtering out some of your data. Here is an example on how you would change your first join.
join ho in Hardware_Items on orderItem.OuterColour equals ho.Index into hog
from ho in hog.DefaultIfEmpty()

Linq and grouping with three tables

I've come up with the following LINQ, but I can't help thinking that I should be able to do this in one query instead of two. Can anyone help?
The idea is to inner join three tables and group by one.
var q1 = from er in ExportRules
join per in PlaceExportRules on er.ExportRulesID equals per.ExportRulesID
select new
{
PlaceID = per.PlaceID,
Description = er.Description,
Tag = er.TagName,
ExportName = per.ExportName,
ExportAddress = per.ExportAddress
};
var q2 = from p in Places
join rules in q1 on p.PlaceID equals rules.PlaceID into joined2
where joined2.Any()
orderby p.PlaceName
select new {Place = new {p.PlaceID, p.PlaceName}, joined2};
Well, you can just bracket things:
var query = from p in Places
join rules from
(from er in ExportRules
join per in PlaceExportRules
on er.ExportRulesID equals per.ExportRulesID
...)
on p.PlaceId equals rules.PlaceId into joined2
where joined2.Any()
orderby p.PlaceName
select new {Place = new {p.PlaceID, p.PlaceName}, joined2};
However, I'd personally probably leave it as two queries. It's clearer, and won't affect the performance - it's not like the first statement in your code would actually execute the query.

LINQ Left join on my than one field? I have the SQL working but can't convert it to a linq query

I wonder if anyone can help
I have a simple SQL Query which was this.
SELECT * FROM ITEM INNER JOIN CODES ON ITEM.ITEMID = CODES.ITEMID AND
ITEM.CATID = CODES.CATID
This works great, so i created the following query in LINQ
from i in Item join c in codes
on new { i.itemid, i.catid } equals new { c.itemid, c.catid }
Works great, but they i realized that i actually needed an LEFT JOIN in place of the INNER JOIN. So the sql, which now works great!, is :- (notice left join)
SELECT * FROM ITEM LEFT JOIN CODES ON ITEM.ITEMID = CODES.ITEMID AND
ITEM.CATID = CODES.CATID
So now everything seems to work and i get back the data i require using SQL i can't figure out how to do a left join in LINQ and especially how to do a left join on more than 1 field - in my case itemid and catid
I wonder if anyone can lend a hand, i am stuck :-)
I think this is the direction you need to head down:
from i in Item
join c in codes on new { i.itemid, i.catid } equals new { c.itemid, c.catid }
into grouped
from g in grouped.DefaultIfEmpty()
select new
{
ItemId = c.itemid,
CatItemId = g != null ? g.itemid : "Empty"
};
You should look: http://codingsense.wordpress.com/2009/03/08/left-join-right-join-using-linq/
The key is -->
into JoinedEmpDept
from dept in JoinedEmpDept.DefaultIfEmpty()

LINQ count in group from join

I have a LINQ statement I am trying to get right, so maybe going about this all wrong. My objective is to query a table and join in another table to get counts.
Places
ID, Display
ProfilePlaces
ID, PlaceID, Talk, Hear
Basically Places have ProfilePlaces in a one to many relationship. I want to get the number SUM of ProfilePlaces that have Talkand Hear. Talkand Hear are bit fields.
The following gives me a unique list of Places, so I need to add in the Talkand Hear counts.
var counts = from p in db.Places
join pp in db.ProfilePlaces on p.ID equals pp.PlaceID
group new { Place = p } by p.Display;
I thought something like this, but not having any luck
var counts = from p in db.Places
join pp in db.ProfilePlaces on p.ID equals pp.PlaceID
group new { Place = p,
Talk = pp.Count(t => t.Talk == true),
Hear = pp.Count(t => t.Hear == true)
} by p.Display;
Thanks for any help.
You want to do a GROUP JOIN to get the counts for each Place.
var counts2 = from p in places
join pp in profilePlaces on p.ID equals pp.PlaceID into g
select new
{
Place = p,
CountMeet = g.Count(a => a.Meet),
CountTalk = g.Count(a => a.Talk)
};
Here's the documentation on the different joins from MSDN:
http://msdn.microsoft.com/en-us/library/bb311040.aspx

Stuck on a subquery that is grouping, in Linq`

I have some Linq code and it's working fine. It's a query that has a subquery in the Where clause. This subquery is doing a groupby. Works great.
The problem is that I don't know how to grab one of the results from the subquery out of the subquery into the parent.
Frst, here's the code. After that, I'll expplain what piece of data i'm wanting to extract.
var results = (from a in db.tblProducts
where (from r in db.tblReviews
where r.IdUserModified == 1
group r by
new
{
r.tblAddress.IdProductCode_Alpha,
r.tblAddress.IdProductCode_Beta,
r.tblAddress.IdProductCode_Gamma
}
into productGroup
orderby productGroup.Count() descending
select
new
{
productGroup.Key.IdProductCode_Alpha,
productGroup.Key.IdProductCode_Beta,
productGroup.Key.IdProductCode_Gamma,
ReviewCount = productGroup.Count()
}).Take(3)
.Any(
r =>
r.IdProductCode_Alpha== a.IdProductCode_Alpha&&
r.IdProductCode_Beta== a.IdProductCode_Beta&&
r.IdProductCode_Gamma== a.IdProductCode_Gamma)
where a.ProductFirstName == ""
select new {a.IdProduct, a.FullName}).ToList();
Ok. I've changed some field and tables names to protect the innocent. :)
See this last line :-
select new {a.IdProduct, a.FullName}).ToList();
I wish to include in that the ReviewCount (from the subquery). I'm jus not sure how.
To help understand the problem, this is what the data looks like.
Sub Query
IdProductCode_Alpha = 1, IdProductCode_Beta = 2, IdProductCode_Gamma = 3, ReviewCount = 10
... row 2 ...
... row 3 ...
Parent Query
IdProduct = 69, FullName = 'Jon Skeet's Wonder Balm'
So the subquery grabs the actual data i need. The parent query determines the correct product, based on the subquery filters.
EDIT 1: Schema
tblProducts
IdProductCode
FullName
ProductFirstName
tblReviews (each product has zero to many reviews)
IdProduct
IdProductCode_Alpha (can be null)
IdProductCode_Beta (can be null)
IdProductCode_Gamma (can be null)
IdPerson
So i'm trying to find the top 3 products a person has done reviews on.
The linq works perfectly... except i just don't know how to include the COUNT in the parent query (ie. pull that result from the subquery).
Cheers :)
Got it myself. Take note of the double from at the start of the query, then the Any() being replaced by a Where() clause.
var results = (from a in db.tblProducts
from g in (
from r in db.tblReviews
where r.IdUserModified == 1
group r by
new
{
r.tblAddress.IdProductCode_Alpha,
r.tblAddress.IdProductCode_Beta,
r.tblAddress.IdProductCode_Gamma
}
into productGroup
orderby productGroup.Count() descending
select
new
{
productGroup.Key.IdProductCode_Alpha,
productGroup.Key.IdProductCode_Beta,
productGroup.Key.IdProductCode_Gamma,
ReviewCount = productGroup.Count()
})
.Take(3)
Where(g.IdProductCode_Alpha== a.IdProductCode_Alpha&&
g.IdProductCode_Beta== a.IdProductCode_Beta&&
g.IdProductCode_Gamma== a.IdProductCode_Gamma)
where a.ProductFirstName == ""
select new {a.IdProduct, a.FullName, g.ReviewCount}).ToList();
While I don't understand LINQ completely, but wouldn't the JOIN work?
I know my answer doesn't help but it looks like you need a JOIN with the inner table(?).
I agree with shahkalpesh, both about the schema and the join.
You should be able to refactor...
r => r.IdProductCode_Alpha == a.IdProductCode_Alpha &&
r.IdProductCode_Beta == a.IdProductCode_Beta &&
r.IdProductCode_Gamma == a.IdProductCode_Gamma
into an inner join with tblProducts.

Resources