Linq to SQL order by aggregate - linq-to-sql

I have a very simple grouping and aggregation problem in LINQ to SQL that I just can't figure out, and it is driving me mad.
I've simplified things into this example:
class Customer {
public Guid Id;
public String Name;
}
class Order {
public Guid Customer_Id;
public double Amount;
}
How do I get a list of customers ordered by the number of orders they have? And on the total amount they have purchased for?

return dataContext.Customers.OrderBy(cust => cust.Orders.Count)
.ThenBy(cust => cust.Orders.Sum(order => order.Amount))
.ToList();

var qry1 = from c in db.Customers
join o in db.Orders on c.Id equals o.Customer_Id into orders
orderby orders.Count()
select c;
var qry2 = from c in db.Customers
join o in db.Orders on c.Id equals o.Customer_Id into orders
orderby orders.Sum(o => o.Amount)
select c;

By number of orders:
var customers = (from c in db.Customers
select new
{
c.Name,
OrderCount = c.Orders.Count()
}).OrderBy(x => x. OrderCount);
By total amount purchased:
var customers = (from c in db.Customers
select new
{
c.Name,
Amount = (from order in c.Orders
select order.Amount).Sum()
}).OrderBy(x => x.Amount);

Related

LINQ: Count Users in 3 way join

I'm having trouble with LINQ to SQL, which I think should not be too difficult.
In SQL I have a BusinessUnits, that get's divided in OrgUnits, and Users belong to an Org Unit.
I want to print the BusinessUnitID with the number of Users in each.
In SQL, it will probably look like this:
SELECT BusinessUnitID, Count(u.UserID)
FROM BusinessUnitsOrgUnits bu
INNER JOIN OrgUnits org on bu.OrgUnitID= org.OrgUnitID
INNER JOIN Users u on org.OrgUnitID = u.OrgUnitID
GROUP BY BusinessUnitID
But in LINQ I got this, but struggling to get the count correct.
var UsersPerBU = from bu in BusinessUnitsOrgUnits
join org in OrgUnits on bu.OrgUnitID equals org.OrgUnitID
join u in Users on org.OrgUnitID equals u.OrgUnitID
group bu by bu.BusinessUnitID into g
select new
{
BusinessUnitID = g.Key,
UserCount = Users.Count (us => us.OrgUnit.OrgUnitID == bu.OrgUnitID)
//here it complains that bu does not exist.
};
var UsersPerBU = from bu in BusinessUnitsOrgUnits
join org in OrgUnits on bu.OrgUnitID equals org.OrgUnitID
join u in Users on org.OrgUnitID equals u.OrgUnitID
group bu by bu.BusinessUnitID into g
select new
{
BusinessUnitID = g.Key,
UserCount = g.Count()
};
Maybe this
var UsersPerBU = (from bu in BusinessUnitsOrgUnits
join org in OrgUnits on bu.OrgUnitID equals org.OrgUnitID
join u in Users on org.OrgUnitID equals u.OrgUnitID
group bu by bu.BusinessUnitID into g
select new { bu = g})
.Select(x =>
new
{
BusinessUnitID = x,
UserCount = x.bu.Select(y => y.OrgUnitID).Distinct().Count()
//here it complains that bu does not exist
}
);

SQL Query in Linq with HAVING SUM

I have a small database example with three tables: Cities, Country and Geo_Languages (Languages spoken in the countries). Now I want to get the most spoken languages of all cities in the world with a population of at least one million people.
Here is the SQL-Query:
SELECT SUM(c.population) AS totalPop, g.name_en
FROM cities c, country cy, geo_languages g
WHERE c.country_code = cy.id AND
cy.id = g.code2l
GROUP BY g.name_en
HAVING SUM(c.population) > 1000000
ORDER BY totalPop DESC;
Here the Linq-Query so far:
Var query =
from c in db.City
join country in db.Country on c.country_code equals country.id
join languages in db.geo_languages on country.id equals
languages.code2l
group languages by languages.name_en
select new{
totalPop = c.Sum (c => c.population)
};
I just don't know how to convert the HAVING SUM and the ORDER BY into Linq.
I'm thankful for any help.
Try that one:
var query =
from c in db.City
join country in db.Country on c.country_code equals country.id
join languages in db.geo_languages on country.id equals
languages.code2l
group c by languages.name_en into g
where g.Sum(x => x.population) > 1000000
select new {
totalPop = g.Sum(x => x.population)
};

LINQ to SQL with multiple joins, group by and count

I have 3 tables, Cust, Order and Item with the following relevant fields:
Cust - CustID, CustName
Order - OrderID, CustID
Item - ItemID, OrderID
I want to find the total number of orders and items for each customer.
Here is an SQL statement that generates what I want, a list of customers with the total number of orders for each customer and the total number of items ordered.
SELECT
Cust.CustID, Cust.CustName,
count(DISTINCT Order.OrderID) AS numOrders,
count(DISTINCT Item.ItemID ) AS numItems
FROM Cust
LEFT JOIN Order ON Order.CustID = Cust.CustID
LEFT JOIN Item ON Item.OrderID = Order.OrderID
GROUP BY Cust.CustID, Cust.CustName
ORDER BY numItems
My first attempt at converting this to LINQ was to just count items and came up with this:
var qry = from Cust in tblCust
join Order in tblOrder on Cust.CustID equals Order.CustID
join Item in tblItem on Order.OrderID equals Item.OrderID
group Cust by new {CustID = Cust.CustID, CustName = Cust.CustName} into grp
orderby grp.Count()
select new
{
ID = grp.Key.CustID,
Name = grp.Key.CustName,
Cnt = grp.Count()
};
With this code I get the exception:
Value cannot be null. Parameter name: inner
Am I on the right track? What would I have to do to get both counts?
For Left Joins - I suggest using a from with a where and a DefaultIfEmpty
You need to group using an anonymous type in order to group multiple parameters
Value cannot be null. Parameter name: inner
Are any of joining properties nullable?
var qry =
from Cust in tblCust
from Order in tblOrder.Where(x => Cust.CustID == x.CustID)
.DefaultIfEmpty()
from Item in tblItem.Where(x => Order.OrderID == x.OrderID)
.DefaultIfEmpty()
group new { Cust, Order.OrderId, Item.ItemId } by new { Cust.CustID, Cust.CustName } into grp
let numItems = grp.Select(x => x.ItemId).Distinct().Count()
orderby numItems
select new
{
ID = grp.Key.CustID,
Name = grp.Key.CustName,
numOrders = grp.Select(x => x.OrderId).Distinct().Count(),
numItems,
};

how would i use GroupBy in this linq statement?

Morning i would like to include a group by in this linq statement, Some records i have being brought back have multiple entries so i need to group them by the productAsin. so i dont have duplicates in my table.
var query = from a in dc.aProducts
join t in dc.tProducts on a.sku equals t.sku
join lp in dc.LowestPrices on a.asin equals lp.productAsin
orderby t.title
select new GetLowestPrices
{
productAsin = lp.productAsin,
sku = t.sku,
title = t.title,
tweprice = Convert.ToString(t.twePrice),
lowprice = Convert.ToString(lp.price),
amzprice = Convert.ToString(lp.tweAmzPrice),
lastupdated = Convert.ToDateTime(lp.priceDate)
};
return query.ToList();
many thanks in advance.
Use GroupBy Extension method:
var query = from a in dc.aProducts
join t in dc.tProducts on a.sku equals t.sku
join lp in dc.LowestPrices on a.asin equals lp.productAsin
orderby t.title
select new GetLowestPrices
{
productAsin = lp.productAsin,
sku = t.sku,
title = t.title,
tweprice = Convert.ToString(t.twePrice),
lowprice = Convert.ToString(lp.price),
amzprice = Convert.ToString(lp.tweAmzPrice),
lastupdated = Convert.ToDateTime(lp.priceDate)
};
var groupedData = query.GroupBy(d => d.productAsin);
return groupedData;
After that you can access that group values and put some aggregate function on them as below:
var groupedData = query.GroupBy(d => d.productAsin).Select( data => new {
productAsin = data.Key,
LowPriceSum = data.Sum(s => Convert.ToInt32(s.price))
}).ToList();
Ref:
group clause (C# Reference)
How to Use LINQ GroupBy

Full outer join - Linq To SQL

I'm trying to use Linq to SQL to do a full outer join. I had this working for a basic example, but it didn't work when each side of the full outer join were generated from another inner join. Below's the code. I realise that this could probably be put into less queries - but I'd rather split them out to make them as readable as possible. Performance isn't an issue in this case.
var productIds = db.OrderItemsIncoming.Select(i => i.ProductID)
.Union(db.OrderItemsOutgoing.Select(o => o.ProductID))
.Distinct();
var ordersIn = from o in db.OrdersIncoming
join i in db.OrderItemsIncoming on o.OrderNumber equals i.OrderNumber
select new { o, i };
var ordersOut = from o in db.OrdersOutgoing
join i in db.OrderItemsOutgoing on o.OrderNumber equals i.OrderNumber
select new { o, i };
var fullOuterJoinResults = from i in ordersIn
join o in ordersOut on i.i.ProductID equals o.i.ProductID into t
from o in t.DefaultIfEmpty()
where i == null ^ o == null
select new { i, o };
In my test, the ordersIn results is empty, and the ordersOut results has one row in it. So I want the final fullOuterJoinResults to have a row, but it's empty.
Literally a second after I post, I notice an error where I'm not using the productID results anywhere!!! :-/ I'll edit this post with my fix once I've got it working ...
[edit]
Okay, this seems to work:
var ordersIn = from o in db.OrdersIncoming
join i in db.OrderItemsIncoming on o.OrderNumber equals i.OrderNumber
select new { o, i };
var ordersOut = from o in db.OrdersOutgoing
join i in db.OrderItemsOutgoing on o.OrderNumber equals i.OrderNumber
select new { o, i };
var productIds = db.OrderItemsIncoming.Select(i => i.ProductID)
.Union(db.OrderItemsOutgoing.Select(o => o.ProductID))
.Distinct();
var fullOuterJoinResults = from pid in productIDs
join i in ordersIn on pid equals i.i.ProductID into t1
from i in t1.DefaultIfEmpty()
join o in ordersOut on pid equals o.i.ProductID into t2
from o in t2.DefaultIfEmpty()
where i == null ^ o == null
select new { i, o };