I want to replicate this query in LINQ to SQL but am too unfamiliar with how to do it.
SELECT A.Recruiter, SUM(O.SaleAmount * I.Commission) --This sum from fields in two different tables is what I don't know how to replicate
FROM Orders AS O
INNER JOIN Affiliate A ON O.AffiliateID = A.AffiliateID
INNER JOIN Items AS I ON O.ItemID = I.ItemID
GROUP BY A.Recruiter
I've got this far:
from order in ctx.Orders
join item in ctx.Items on order.ItemI == item.ItemID
join affiliate in ctx.Affiliates on order.AffiliateID == affiliate.AffiliateID
group order //can I only group one table here?
by affiliate.Recruiter into mygroup
select new { Recruiter = mygroup.Key, Commission = mygroup.Sum(record => record.SaleAmount * ?????) };
group new {order, item} by affiliate.Recruiter into mygroup
select new {
Recruiter = mygroup.Key,
Commission = mygroup
.Sum(x => x.order.SaleAmount * x.item.Commission)
};
And an alternative way of writing the query:
from aff in ctx.Affiliates
where aff.orders.Any(order => order.Items.Any())
select new {
Recruiter = aff.Recruiter,
Commission = (
from order in aff.orders
from item in order.Items
select item.Commission * order.SaleAmount
).Sum()
};
try linqpad, just Google, amazing tool!
Related
I have these tables which have 1:n and then 1:n relationship with each other:
How can I sum up the amount of Expenses for one specific household?
This is my SQL for that:
SELECT households.Id as HouseholdId,
households.Name HouseholdName,
SUM(expenses.Amount) as SumExpenses
FROM [Households] households
INNER JOIN Accounts accounts
ON households.Id = accounts.HouseholdId
INNER JOIn Expenses expenses
ON expenses.AccountId = accounts.Id
WHERE households.Id = '2AFAB095-39D6-4637-1FC1-08DAC249FA0A'
GROUP BY households.Id, households.Name;
This is what I have done so far:
var results = await (
from household in Context.Households
join account in Context.Accounts
on household.Id equals account.HouseholdId
join expense in Context.Expenses
on account.Id equals expense.AccountId
group new { household }
by new { household.Id, household.Name, AccountName = account.Name, Amount = expense.Amount}
into g
select new
{
HouseholdId = g.Key.Id,
HouseholdName = g.Key.Name,
AccountName = g.Key.AccountName,
//What to do here to get the sum?
}).ToListAsync();
LNQ grouping has the same behaviour as in the SQL. If you add additional grouping keys - you will fail. Important part is what to group.
Also I have removed other artifacts which are not present in your original SQL. You have test that adding additional grouping keys will not change result.
var householdId = ...;
var query =
from household in Context.Households
join account in Context.Accounts
on household.Id equals account.HouseholdId
join expense in Context.Expenses
on account.Id equals expense.AccountId
where household.Id == householdId
group expense
by new { household.Id, household.Name }
into g
select new
{
HouseholdId = g.Key.Id,
HouseholdName = g.Key.Name,
SumExpenses = g.Sum(x => x.Amount)
};
I am trying to find out best 5 company names which makes the max profit for the company.
Here is what I have written so far:
var result = from c in db.Customers
join o in db.Orders
on c.CustomerID equals o.CustomerID
join od in db.Order_Details
on o.OrderID equals od.OrderID
select new
{
CompanyName = c.CompanyName,
Profit = (float)od.UnitPrice * (float)od.Quantity * (1 - od.Discount)
};
However, it doesn't contain not the group by and the best 5 company part which I'm actually looking for. I tried to do with
group c by c.CompanyName into CompanyName
but it doesn't work, and I couldn't find out that top 5 company query.
I think you would need to group your result with company name and sum the profit, then take the highest 5 by order by desc and take.
Something like the below (even though the sentence may not be exactly correct)
var grouped =from p in query
group p by p.CompanyName into g
select new
{
CompanyName = g.Key,
TotalProfit = g.sum(x=>x.Profit)
};
var Top5=grouped.orderbyDesc(x=>TotalProfit).take(5);
var totalCompanies = db.Order_Details.GroupBy(x => x.Order.Customer.CompanyName).OrderByDescending(x=>x.Sum(y=> (float)y.Quantity * (float)y.UnitPrice * 1 - (y.Discount))).Take(5).ToList();
List<string> bestCompanies = new List<string>();
foreach (var item in totalCompanies)
{
bestCompanies.Add(item.Key);
};
Here is the similar solution for the question.
I am trying to move from simple SQL to EF.
But there are some complex queries(joins) that it seems to hard to generate the linq for.
At first I tried to use sqltolinq tool to generate the linq but it gives error as some of the things are not supported in the query.
here is the linq:
var entryPoint = (from ep in dbContext.tbl_EntryPoint
join e in dbContext.tbl_Entry on ep.EID equals e.EID
join t in dbContext.tbl_Title on e.TID equals t.TID
where e.OwnerID == user.UID
select new {
UID = e.OwnerID,
TID = e.TID,
Title = t.Title,
EID = e.EID
});
The table entry has many entries that I would like to group and get the latest for each group. But then I would need to select into a view model object which will be bind to gridview.
I dont know where I can implement the logic to group by and get the latest from each and be able to get values from join table into viewModel object.
somewhere I need to add
group entry by new
{
entry.aID,
entry.bCode,
entry.Date,
entry.FCode
}
into groups
select groups.OrderByDescending(p => p.ID).First()
in the above linq to retrieve latest from each group.
You can insert group by right after the joins:
var query =
from ep in dbContext.tbl_EntryPoint
join e in dbContext.tbl_Entry on ep.EID equals e.EID
join t in dbContext.tbl_Title on e.TID equals t.TID
where e.OwnerID == user.UID
group new { ep, e, t } by new { e.aID, e.bCode, e.Date, e.FCode } into g
let r = g.OrderByDescending(x => x.e.ID).FirstOrDefault()
select new
{
UID = r.e.OwnerID,
TID = r.e.TID,
Title = r.t.Title,
EID = r.e.EID
};
The trick here is to include what you need after the grouping between group and by.
However, the above will be translated to CROSS APPLY with all joins included twice. If the grouping key contains fields from just one table, it could be better to perform the grouping/selecting the last grouping element first, and then join the result with the rest:
var query =
from e in (from e in dbContext.tbl_Entry
where e.OwnerID == user.UID
group e by new { e.aID, e.bCode, e.Date, e.FCode } into g
select g.OrderByDescending(e => e.ID).FirstOrDefault())
join ep in dbContext.tbl_EntryPoint on e.EID equals ep.EID
join t in dbContext.tbl_Title on e.TID equals t.TID
select new
{
UID = e.OwnerID,
TID = e.TID,
Title = t.Title,
EID = e.EID
};
Please anyone can help me to write this sql query into Linq. i have tried..
this is my sql query
select o.OrderID,o.Nature,o.Date,od.TotalPrice,os.OrderStatus,lo.FirstName,lo.EmailAddress,lo.PhoneNumber
from [dbo].[Order] o
inner join [dbo].[tbl_OrderDetails] od on od.OrderID = o.OrderID
inner join [dbo].[tbl_OrderHistory] oh on oh.OrderID = o.OrderID
inner join [dbo].[tbl_Login] lo on o.UserID = lo.UserID
inner join dbo.tbl_OrderStatus os on oh.OrderStatusID= os.OrderStatusID
group by o.OrderID,o.Nature,od.TotalPrice,o.Date,os.OrderStatus,lo.FirstName,lo.EmailAddress,lo.PhoneNumber
and this is my try
public override orderDetailModel orderDetails(int id)
{
var results = from o in obj.Orders
join od in obj.tbl_OrderDetails on o.OrderID equals od.OrderID
join oh in obj.tbl_OrderHistory on o.OrderID equals oh.OrderID
join l in obj.tbl_Login on o.UserID equals l.UserID
join os in obj.tbl_OrderStatus on oh.OrderStatusID equals os.OrderStatusID
where (od.OrderID == id)
group o by new { o.Nature, o.OrderID } into
select new orderDetailModel
{
OrderID = o.OrderID,
OrderStatus = os.OrderStatus,
Date = o.Date,
DeliveryNature = o.Nature,
EmailAddress = l.EmailAddress,
FirstName = l.FirstName,
PhoneNumber = l.PhoneNumber,
TotalPrice = od.TotalPrice
};
//group o by new {o.OrderID};
orderDetailModel data = (orderDetailModel)results.FirstOrDefault();
return data;
}
but this is wrong query its not working fine please help me
You need to correct the group by clause, like you have in the SQL query like this:-
group new { o, l } by new { o.OrderID,o.Nature,od.TotalPrice,o.Date,os.OrderStatus,
l.FirstName, l.EmailAddress,l.PhoneNumber } into g
select new orderDetailModel
{
OrderID = g.Key.OrderID,
OrderStatus = g.Key.OrderStatus,
Date = g.Key.Date,
..and so on
};
Since you need the grouping on two tables Order & tbl_Login you will have to first project them as anonymous type group new { o, l } then specify all the groupings and finally while projecting use Key to get the respective items.
I guess that actually, also the SQL query is not correct.
I would simply use a SELECT DISTINCT ... instead of Grouping all the columns.
Anyway, first thing to do:
Check if databases is designed correctly. As far as i can see, if you're joining the table with their Ids, i don't understand why you need to group all the data. If you have duplicates, maybe the error is in the Database design.
If you can't change your Database, or you are happy with it, then use the following LINQ approach:
var distinctKeys = allOrderDetails.Select(o => new { o.OrderID, o.Nature, o.TotalPrice, o.Date,o.OrderStatus,o.FirstName, o.EmailAddress,o.PhoneNumber }).Distinct();
var joined = from e in allOrderDetails
join d in distinctKeys
on new { o.OrderID, o.Nature,o.TotalPrice, o.Date,o.OrderStatus, o.FirstName, o.EmailAddress, o.PhoneNumber } equals d select e;
joined.ToList(); // gives you the distinct/grouped list
So I'm trying to do a linq statement to group two db tables and select the top 25 based on how many reviews each category has. So my sql statement is
SELECT TOP 25 BusinessCategories.Category, COUNT(*) as count
FROM Reviews
JOIN BusinessCategories
ON BusinessCategories.BusinessID=Reviews.BusinessID
GROUP BY BusinessCategories.Category
ORDER BY count desc
Which works perfectly. So now to try to do this in my web api I'm having troubles. This is what I have:
var top = (from review in Db.Reviews
from category in Db.BusinessCategories
where review.BusinessID == category.BusinessID
group review by category into reviewgroups
select new TopBusinessCategory
{
BusinessCategory = reviewgroups.Key,
Count = reviewgroups.Count()
}
).OrderByDescending(x => x.Count).Distinct().Take(25);
This gives me some of the same results, but it looks like when I call the api in the browser all the counts are the same...so I'm doing something wrong.
Try this may be it works for you
var top = (from review in Db.Reviews
join category in Db.BusinessCategories
on review.BusinessID equals category.BusinessID
group review by category into reviewgroups
select new TopBusinessCategory
{
BusinessCategory = reviewgroups.Key,
Count = reviewgroups.Key.categoryId.Count() //CategoryId should be any
//property of Category or you
//can use any property of category
}).OrderByDescending(x => x.Count).Distinct().Take(25);
Solve the problem by using this
[HttpGet]
[Queryable()]
public IQueryable<TopBusinessCategory> GetTopBusinessCategories()
{
var top = (from p in Db.BusinessCategories
join c in Db.Reviews on p.BusinessID equals c.BusinessID into j1
from j2 in j1.DefaultIfEmpty()
group j2 by p.Category into grouped
select new TopBusinessCategory
{
BusinessCategory = grouped.Key,
Count = grouped.Count(t => t.BusinessID != null)
}).OrderByDescending(x => x.Count).Take(25);
return top.AsQueryable();
}