I have a soldproduct table I want to draw the chart of the top 10 highest sold products.
trying it with following code but I don't know what is the exact problem while, it is logically right.
here is the error
System.ArgumentException: 'DbExpressionBinding requires an input expression with a collection ResultType. Parameter name: input'
DateTime start = startDate.Value;
DateTime end = EndDate.Value;
var TopTen = (from q in db.soldProduct
where (q.addDate >= start && q.addDate <= end)
orderby q.Barcode.Count() descending
select new
{
count = q.Barcode.Count(),
q.productName
}).Take(10);
foreach (var item in TopTen)
{
chartCustomer.Series["Customer"].Points.AddXY(item.productName, item.count);
}
ADDED :- I have in each row the item name and the quantity which might be one or more, I want to add that as well to the query but it is getting harder
model of the bill of soldProduct contains the following
public string barcode {get;set;}
public int productId{get;set;}
public string productName{get;set;}
public int quantity{get;set;}
public DateTime addDate{get;set;}
public double amount{get;set}
so the table if it has the following data
productId
barcode
productName
quantity
addDate
amount
1
111
milk
3
3/2/2020
15
1
111
milk
1
3/2/2020
5
2
222
bread
5
3/2/2020
20
3
333
cheese
1
3/2/2020
100
1
111
milk
3
3/2/2020
15
2
222
bread
3
3/2/2020
15
quantity of the of item sold the highest is bread with 8 occurrences it should come first then milk with 7 occurrences and then cheese.
Addition after comments: Apparently every SoldProduct has a property Amount. You don't want to count the number of SoldProducts, but the total Amount of all SoldProducts.
So if SoldProduct1 for product "Milk" has Amount 10 and SoldProduct[22] for product "Milk" has Amount 14, you want as result that of product "Milk" 24 items have been sold (= 10 + 14).
End addition after comment
So you have a table, SoldProducts. Every row in this table represents one Sale of a Product.
table SoldProducts has a.o. at least the following columns
AddDate: when was the sale
ProductName: the Name of the sold product,
Amount: the number of sold products in this sale.
I want ... the top 10 highest sold products
"highest sold products" probably doesn't have to do anything to do with the height of the sold products, but with the total Amount of products sold.
To calculate this, you need to make groups of SoldProducts with the same name. You'll get groups of the soldProducts with name: "Bread" and SoldProducts with name "Milk", etc.
Then you want to sum the total Amount of all soldProducts per group.
So if group "Bread" has 3 SoldProducts with Amounts 10, 7, 5, then you want as result: ["Bread", 22]. 22 is the total number of Breads sold.
You order the result of the grouping items by descending TotalAmount and take the first 10 items.
To group elements based on something common is done by one of the overloads of Enumerable.GroupBy. In this case, I take the overload with parameter resultSelector to count the number of elements in each group.
DateTime beginDate = ...
DateTime endDate = ...
var topTenSoldProductNames = dbContext.SoldProducts
.Where(soldProduct => beginDate <= soldProduct.AddDate
&& endDate >= soldProduct.AddDate)
// make groups with same ProductName
.GroupBy(soldProduct => soldProduct.ProductName,
// parameter resultSelector: take each ProductName,
// and all SoldProducts with this ProductName to make one new
(productName, soldProductsWithThisProductName) => new
{
Name = productName,
TotalAmount = soldProductsWithThisProductName
.Select(soldProduct => soldProduct.Amount)
.Sum(),
})
// order by descending TotalAmount, and take the first 10
.OrderByDescending(groupResult => groupResult.TotalAmount)
.Take(10);
Your query is wrong, you are returning count of chars. And without grouping this query is useless.
var groupingQuery =
from q in db.soldProduct
where (q.addDate >= start && q.addDate <= end)
group q by q.productName into g
select new
{
productName = g.Key,
count = g.Count(),
};
var TopTen = groupingQuery.OrderByDescending(x => x.count).Take(10);
Related
I have a structure like
ID Description Principal Interest Total
123 Paid 100 150 250
Balance 50 50 100
Total ? ? ?
124 Paid 100 150 250
Balance 50 50 100
Total ? ? ?
Class :
public class APIBillingHistory
{
public List<APIBillingHistoryDetails> BillingHistoryDetails;
}
public class APIBillingHistoryDetails
{
public string BillId;
public string Description;
public Decimal Principal;
public Decimal Interest;
public Decimal Total;
}
I would like to sum value for each column for each id. So in above example, Total for ID 123 for Principal would be 150, Interest 200 likewise. I checked this solution over here How to create Total column and Total row using LINQ but not able to get it.
Code:
responseObj = new APIBillingHistory
{
BillingHistoryDetails = billingHistory.BillingHistoryDetails
.GroupBy(detail => new { detail.BillId, detail.Description})
.Select(group => new APIBillingHistoryDetails
{
BillId = group.Key.BillId,
Description = group.Key.Description,
Principal = group.Sum(t => t.Principal),
Interest = group.Sum(t => t.Interest),
Total = group.Sum(t => t.Principal) + group.Sum(t => t.Interest)
}).Concat(new APIBillingHistoryDetails
{
Description = "Total",
/* Not sure what to write over here */
})
};
Edit:
To clarify what I am trying to achieve:
My source record list does not contain "Total" column & "Total" row. I would like to add it manually.
I Was able to figure out how to Add "Total" column which would contain Sum of values.
Principal & Interest will contain values in decimal format.
ID column is an integer. I would like to Display Total row for each ID
Values for Principal & Interest are being calculated by aggregating based on ID, After that calculation, only Total row should get displayed.
Any Suggestions?
You can't use Concat and reference previous data. You need to use SelectMany:
BillingHistoryDetails = billingHistory.BillingHistoryDetails
.GroupBy(detail => detail.BillId)
.SelectMany(bg => bg.Concat(new[] { new APIBillingHistoryDetails {
BillId = bg.First().BillId,
Description = "Total",
Principal = bg.Sum(b => b.Principal),
Interest = bg.Sum(b => b.Interest),
Total = bg.Sum(b => b.Total)
} }));
Assuming the current data
BillId Description Principal Interest
123 Paid 100 150
123 Balance 50 50
124 Paid 100 150
124 Balance 50 50
Then just group by the identity, creating the total object by summing up the grouped properties setting the description as "Total".
var totalsObj = new APIBillingHistory {
BillingHistoryDetails = billingHistory.BillingHistoryDetails
.GroupBy(detail => detail.BillId)
.Select(g => new APIBillingHistoryDetails {
BillId = g.Key,
Description = "Total",
Principal = g.Sum(detail => detail.Principal),
Interest = g.Sum(detail => detail.Interest),
Total = g.Sum(detail => detail.Principal) + g.Sum(detail => detail.Interest)
}).ToList()
};
and totalsObj.BillingHistoryDetails would have desired out put
After that calculation, only Total row should get displayed.
BillId Description Principal Interest Total
123 Total 150 200 350
124 Total 150 200 350
I have 2 related tables and they are
Schedule
SlotId
Description
Amount
and Slot
Id
Name
Example data:
Schedule
slotid description amount
--------------------------------
1 Morning charge 300
1 Late fee 300
1 Earlier bonus 200
1 Half day 150
2 Morning charge 300
2 Late fee 300
2 Earlier bonus 200
2 Half day 150
3 Morning charge 300
3 Late fee 300
3 Earlier bonus 200
3 Half day 150
Final result wanted as a SlotSchedules list, like this:
SlotId
SlotName
List<Schedules>
I need:
fetched list of Schedules
and then find distinct slots in it
and then iterate through each slot and build the model i needed as below
This is what I tried with LINQ:
List<Schedules> schedulesAll = (from n in dbContext.Schedules
select n).ToList();
var slotsdistinct = schedulesAll.Select(x => x.SlotId).Distinct().ToList();
foreach (var slot in slotsdistinct)
{
var scheduledforslot = schedulesAll.Where(x => x.SlotId == slot).Select(x => x).ToList();
foreach (Schedules _schedule in scheduledforslot)
{
//ListModel.Add(new DetailsModel { Name = _schedule.Description, Amount = (_schedule.Amount });
}
}
Any way to make it in single LINQ query?
Try this:
var slotsSchedules = dbContext.Slots.ToList().Select(slot => new {
SlotID = slot.Id,
Name = slot.Name,
SlotSchedules = dbContext.Schedules.ToList()
.Where(schedule = > schedule.SlotId == slot.Id).ToList()});
Here is an example Data Table:
ID Amount Date
--------------------------
1 3.000 2016/1/1
2 4.000 2016/1/1
1 6.000 2017/1/1
1 3.000 2018/1/1
3 2.000 2019/1/1
I need to count Dates which a specific Customers does not have a Shop in it.
for example ID 2 does not have a shop in 2017/1/1 and 2018/1/1, so the count will be 2. and the count for customer ID 3 will be 3 because He does not have a shop in 2016/1/1 and 2017/1/1 and 2018/1/1
I think I should use grouping but do not know how to count which I want for a specific ID!
orders.GroupBy(x => x.Date)......???
Assuming you have list of objects:
// number of all different dates
var datesCount = list.Select(i => i.Date).Distinct().Count();
int customerId = 2;
//number of dates with customer shopping
var customerDatesCount = list.Where(i => i.ID == customerId).Select(i => i.Date).Distinct().Count();
var nonShoppingDatesCount = datesCount - customerDatesCount;
You need two steps here.
Get all distinct order dates
var allDates = orders.Select(o => o.Date).Distinct();
Find those dates which customer don't have. Except operation will do that
var missingDates = allDates.Except(orders.Where(o => o.ID == 2).Select(o => o.Date));
If you need just number of missing dates, then use missingDates.Count() or (better) use solution by #Roma
I want to make an olympic medal ranking.
Right now I have a pivot table that has a CountryID, MatchID and Medal column.
The medal column stores the values 1 (gold), 2 (silver) and three (brass).
Countries with the most gold should be the heighest in the rank, followed by the most silver etc. Only thing is, when gold is equal then the amount of silver medals should be taken in account and ofcourse if that is also equal compare brass medals.
Right now I take the following (not successful) approach:
First I make 3 queries like this to get an overview of the amount of medals per country:
var resGold = context.olympics_landen_wedstrijd.Where(n => n.medal == 1).GroupBy(n => n.LandID).Select(g => new { g.Key, Count = g.Count(), Medal = 2 }).OrderByDescending(n => n.Count);
Then I combine resGold, resSilver and resBrass into one list. That list I query again to get a ranking where countries with the most gold are ranked higher.
var list = all.OrderBy(t => t.Medal == 1 ? 1 : (t.Medal == 2 ? 2 : t.Medal == 3 ? 3 : 4)).ToList();
The problem is that I end up with a list where countries are ranked more then once. When Germany and the USA both have 10 golden medals and they both also have silver medals then there is another record for both countries in the list.
How can I achieve to get a ranking according to olympic standards with my database setup?
The result I'm looking to create is:
[RANK 1] CountryID = 2, numberofGold = 10, numberofSilver = 3, numberOfBrass = 5
[RANK 2] CountryID = 3, numberofGold = 10, numberofSilver = 9, numberOfBrass = 9
[RANK 3] CountryID = 4, numberofGold = 9, numberofSilver = 10, numberOfBrass = 10
....
Thanks in advance!
You can compute score for every country based in Weighted Rank.
The ratio can be gold:silver:bronz = 5:3:1
you can sort country based on score Desc
Review
Olympic medal table
I have list like this-
Id Date
1 01/03/2011 14:15:23.320
1 01/03/2011 16:15:23.320
1 01/03/2011 18:15:23.320
1 01/04/2011 19:15:23.320
2 01/03/2011 14:15:23.320
2 01/03/2011 15:15:23.320
2 01/03/2011 18:15:23.320
2 01/05/2011 19:15:23.320
2 01/07/2011 20:15:23.320
My desired output is -
Id Date
1 01/03/2011
1 01/04/2011
2 01/03/2011
2 01/05/2011
2 01/07/2011
So how can I group by on the first list on id and take only the date part and achieve the results above in Linq ?
Try something like this:
var result = yourList.GroupBy(item =>
new {Id = item.Id, Date = item.Date.Date});
Basically, DateTime.Date strips the time information.
To loop through the result, you could do:
foreach(var grp in result)
{
Console.WriteLine("{0}: {1}", grp.Key.Id, grp.Key.Date);
}
It appears that you want to group on the date and id, so you want to pull those out into a structure that you can group on. It's when you create this key structure that you can format the date using the Date property to create the grouping correctly:
from item in list
group item by new { item.Id, Date = item.Date.Date } into g
select g
At that point, the keys in the grouping returned will give you the list you want.