Count active boxes in the rack from transaction logs - c#

I have 2 tables here
Rack
Id
RackName
1
Rack A
2
Rack B
RackTransaction
Id
RackId
Barcode
Event
DateTime
1
1
ABC1234
IN
2021-07-12
2
1
ABC1234
OUT
2021-07-20
3
1
ABC1235
IN
2021-07-21
4
1
ABC1236
IN
2021-07-21
5
1
ABC1236
OUT
2021-07-23
6
1
ABC1237
IN
2021-07-21
7
1
ABC1238
IN
2021-07-21
8
1
ABC1238
OUT
2021-07-23
Barcode ABC1235 and ABC1237 not check out yet. So the total count boxes inside the RACK A is 2.
So from given sample data, how I can generate using the linq?
var getTotal = await _context.RackBoxLogs.Where(c => c.RackId == rackId)
.GroupBy(c => new { c.Barcode,c.Event })
.Select(g => new { g.Key, MaxDate = g.Max(c => c.CreatedOn),Event = g.Key.Event })
.Where(c=> c.Event == "IN")
.CountAsync();
Even I already group by the barcode and filter the max date I still get the wrong result. Any idea?

This should work with EF 5, I think. Unfortunately EF 5 can't (yet) translate GroupBy().Select(g => g.Last()).
var getTotal = RackTransaction
.Where(rt => rt.RackId == rackId)
.Select(rt => rt.Barcode)
.Distinct()
.Select(b => RackTransaction.Where(rt => rt.Barcode == b).OrderBy(rt => rt.DateTime).Last())
.Where(rt => rt.Event == "IN")
.Count();

This query should get desired count:
var getTotal = await _context.RackBoxLogs
.Where(c => c.RackId == rackId)
.GroupBy(c => new { c.Barcode })
.Where(g => g.Sum(x => x.Event == "IN" ? 1 : 0) >
g.Sum(x => x.Event == "OUT" ? 1 : 0)
)
.CountAsync();

Related

where clause not working in group by LINQ c sharp

I have a table "register_operation with fields"
[Key]
int id_registru_casa ,
DateTime data ,
int id_cont_sintetic ,
decimal suma ,
string tip
tip can take only 2 value :"receipts" and "payments"
"Groupby" work with no problem
but when I add "where" clause not working
(it doesn't show me any records)
(although there are recordings in database with day 19, month 9 and tip=receipts)
var centralizator_rc = db.register_operation
.Where(i => (i.data.Day == 19) && (i.data.Month == 9) && (tip=="receipts"))
.GroupBy(i => i.id_cont_sintetic)
.Select(g => new {
id_cont_sintetic = g.Key,
total_receipts = g.Sum(i=>i.suma),
}).ToList();
Thanks!
SOLVED!
I change code like this:
var centralizator_rc = db.registru_casa
.Where(crc=>(crc.data.Month==8) && (crc.data.Day==16) && (crc.tip=="receipts"))
.GroupBy(crc=> new
{
crc.id_cont_sintetic,
crc.data.Month,
crc.data.Day,
crc.tip
})
.Select(g => new {
data = ziuaOK,
id_cont_sintetic = g.Key.id_cont_sintetic,
total_incasare = g.Sum(i => i.suma),
}).ToList();

LINQ Query Multiple Group and count of latest record - Oracle DB

I tried to divided Linq queries into 3 (total, success, fail) but so far "Total" Linq query is working fine. Please help me to get "Success", "Fail" columns (it has mulitple statuses and we have to check the last column of each transaction and destination)
Note: you need to group by ProcessTime, TransactionId, Destination and check last column whether it is success or Fail then apply count (we are using oracle as backend)
LINQ for Total count
var query = (from filetrans in context.FILE_TRANSACTION
join route in context.FILE_ROUTE on filetrans.FILE_TRANID equals route.FILE_TRANID
where
filetrans.PROCESS_STRT_TIME >= fromDateFilter && filetrans.PROCESS_STRT_TIME <= toDateFilter
select new { PROCESS_STRT_TIME = DbFunctions.TruncateTime((DateTime)filetrans.PROCESS_STRT_TIME), filetrans.FILE_TRANID, route.DESTINATION }).
GroupBy(p => new { p.PROCESS_STRT_TIME, p.FILE_TRANID, p.DESTINATION });
var result = query.GroupBy(x => x.Key.PROCESS_STRT_TIME).Select(x => new { x.Key, Count = x.Count() }).ToDictionary(a => a.Key, a => a.Count);
Check this solution. If it gives wrong result, then I need more details.
var fileTransQuery =
from filetrans in context.AFRS_FILE_TRANSACTION
where accountIds.Contains(filetrans.ACNT_ID) &&
filetrans.PROCESS_STRT_TIME >= fromDateFilter && filetrans.PROCESS_STRT_TIME <= toDateFilter
select filetrans;
var routesQuery =
from filetrans in fileTransQuery
join route in context.AFRS_FILE_ROUTE on filetrans.FILE_TRANID equals route.FILE_TRANID
select route;
var lastRouteQuery =
from d in routesQuery.GroupBy(route => new { route.FILE_TRANID, route.DESTINATION })
.Select(g => new
{
g.Key.FILE_TRANID,
g.Key.DESTINATION,
ROUTE_ID = g.Max(x => x.ROUTE_ID)
})
from route in routesQuery
.Where(route => d.FILE_TRANID == route.FILE_TRANID && d.DESTINATION == route.DESTINATION && d.ROUTE_ID == route.ROUTE_ID)
select route;
var recordsQuery =
from filetrans in fileTransQuery
join route in lastRouteQuery on filetrans.FILE_TRANID equals route.FILE_TRANID
select new { filetrans.PROCESS_STRT_TIME, route.CRNT_ROUTE_FILE_STATUS_ID };
var result = recordsQuery
.GroupBy(p => DbFunctions.TruncateTime((DateTime)p.PROCESS_STRT_TIME))
.Select(g => new TrendData
{
TotalCount = g.Sum(x => x.CRNT_ROUTE_FILE_STATUS_ID != 7 && x.CRNT_ROUTE_FILE_STATUS_ID != 8 ? 1 : 0)
SucccessCount = g.Sum(x => x.CRNT_ROUTE_FILE_STATUS_ID == 7 ? 1 : 0),
FailCount = g.Sum(x => failureStatus.Contains(x.CRNT_ROUTE_FILE_STATUS_ID) ? 1 : 0),
Date = g.Min(x => x.PROCESS_STRT_TIME)
})
.OrderBy(x => x.Date)
.ToList();

LINQ Nested query with appropriate quantifiers and restrictions

I have two tables A & B as below:
Table A
W X Y
1 7 5
2 0 7
3 1 7
4 4 4
5 4 7
Table B
Q Z C D
1 1 7 5
2 1 0 7
3 1 1 7
4 1 4 4
I want to get those values of W for whom X & Y combination exactly matches those combination of C & D in Table B for whom Z = 1.
I have tried following query:
var query = A.Where(u =>
B.Where(a => a.Z == 1)
.Select(a => a.C)
.Contains(u.X))
.Where(u =>
B.Where(a => a.Z == 1)
.Select(a => a.D)
.Contains(u.Y))
.Select(a => new { WIds = a.W });
so in above cases, query result should give: W = {1,2,3,4} however I am getting extra value of 5 as well. W = {1,2,3,4,5}. I think it is not considering the combination as a whole. Can anyone help me what am I doing wrong in this query?
You can simply do it using Any:-
var result = A.Where(x =>
B.Any(p => p.Z == 1 && p.C == x.X && p.D == x.Y)
)
.Select(x => x.W);
Fiddle
The problem is that you are just checking whether the current X matches any C and the current Y matches any D, instead of matching them as a group. You could do this with a simpler query:
var query = A
.Where(a => B.Any(b => b.Z == 1 && b.C == a.X && b.D == a.Y))
.Select(a => new { WIds = a.W });
Can you try this ?
var query = A.Where(a =>
B.Any(b => b.Z == 1 && a.X == b.C && a.Y == b.D))
.Select(a => new { WIds = a.W });

GroupBy and Sum with two Different period time - Linq

I need to get sum of my products amount in different period of times in just one row.
for example:
ID Date Amount
-------------------------
1 2017/01/01 10
1 2017/01/01 12
1 2017/04/03 5
2 2017/01/02 10
I need to get sum for spring season and summer season of each product, so we have this for product 1:
ID SumSpring SumSummer
-----------------------------
1 22 5
I have used this code:
var pDetails = ordersTotal.Select(g => new
{
g.ProductID,
DateType = (((String.Compare(g.BuyDate, "2017/01/01") >= 0 && String.Compare(g.BuyDate, "2017/03/30") <= 0)) ? "Spring" : "Summer"),
g.Amount
}).GroupBy(x => new { id = x.ProductID, type = x.DateType }).Select(x => new
{
ProductID = x.Key.id,
SumSpring = (x.Where(z => z.DateType == "Spring").Count() == 0 ? 0 : x.Where(z => z.DateType == "Spring").Sum(z => z.Amount)),
SumSummer = (x.Where(z => z.DateType == "Summer").Count() == 0 ? 0 : x.Where(z => z.DateType == "Summer").Sum(z => z.Amount)),
});
but it returns several rows for each product which is not what I expected and I do not know why!
This is the output for one product:
ID SumSpring SumSummer
-----------------------------
1 22 0
1 0 5
two rows for one product, but it should be one!
You can get the quarter of a year in this way:
int quarter = (month + 2) / 3;
But don't include it in the GroupBy, you only want to group by ProductID
var pDetails = ordersTotal.Select(x => new
{
x.ProductID,
x.Amount,
Quarter = (x.BuyDate.Month + 2) / 3
})
.Where(x => x.Quarter == 1 || x.Quarter == 2) // it seems you only want these
.GroupBy(x => x.ProductID)
.Select(g => new
{
ProductID = g.Key,
SumSpring = g.Where(x => x.Quarter == 1)
.Select(x => x.Amount)
.DefaultIfEmpty(0)
.Sum(),
SumSummer = g.Where(x => x.Quarter == 2)
.Select(x => x.Amount)
.DefaultIfEmpty(0)
.Sum()
});
Note that this query doesn't care about the year. But it seems you don't care about it anyway.
Try following. the major issue is that you are grouping by Amount :
var pDetails = ordersTotal.Select(g => new
{
ProductID = g.ProductID,
DateType = ((g.BuyDate >= DateTime.Parse("1/1/17")) && (g.BuyDate <= DateTime.Parse("3/30.17"))) ? "Spring" : "Summer",
Amount = g.Amount
}).GroupBy(x => new { id = x.ProductID}).Select(x => new
{
ProductID = x.Key.id,
SumSpring = x.Where(z => z.DateType == "Spring").Sum(z => z.Amount),
SumSummer = x.Where(z => z.DateType == "Summer").Sum(z => z.Amount),
}).ToList();

Sum values in datatable using linq based on conditions

I'm having a datatable like mentioned below.
ID Percentage
1 50
1 30
2 0
2 100
Result:
ID Percentage
1 80
2 100
I tried this and it doesn't work
var n = dt.AsEnumerable()
.Where(r => (int)r["ID"] != "0" || (int)r["ID"] != "100")
.Sum(r => (int)r["Percentage"]);
I'm new to linq and pls provide some suggestions.
Now I need to sum the percentage for each ID and the percentage for each ID should be 0 or 100 percentage.
If any one of the ID in table doesn't have 0 or 100 I need to alert. Pls suggest me how I can do this in linq and I think its the best way.
var result = from row in dt.AsEnumerable()
group row by row["ID"]
into g
select new
{
ID = g.Key,
Sum = g.Sum(x => int.Parse(x["Percentage"].ToString()))
};
var errorItems = result.Where(x => x.Sum != 100 && x.Sum != 0);
if (errorItems.Any())
{
var ids = errorItems.Select(x => x.ID);
string msg = string.Format("ID(s): [{0}] don't meet condition.", string.Join(",", ids));
MessageBox.Show(msg);
}
You are not trying get the sum of "Percentage" for the whole table so directly doing a sum on it wont give you the desired result.
You're trying to find the sum of the percentage for each ID value so you need to group it by ID.
That's what GroupBy(g => g.Field<int>("ID")) does. Then you take the group(g), and for each group, you sum the "Percentage" Column of the members i.e.. .Select(g => g.Sum(p => p.Field<int>("Percentage")))
Here is the complete code.
dt.AsEnumerable().Where(r => r.Field<int>("ID") == 0 || r.Field<int>("ID") == 100).GroupBy(g => g.Field<int>("ID")).Select(g => g.Sum(p => p.Field<int>("Percentage")));
to put an alert message you can use Any instead of the where to check for the presence of the values
if(dt.AsEnumerable().Any(r => r.Field<int>("ID") != 0 && r.Field<int>("ID") != 100)
{
Console.WriteLine("Alert");
}
I guess that you want a new DataTable with the same columns as the first but with grouped percentage by ID? Then have a look at GroupBy and Sum:
var groupQuery = dt.AsEnumerable()
.Select(r => new { ID = r.Field<int>("ID"), Percentage = r.Field<int>("Percentage") })
.Where(x => x.ID != 0 && x.ID != 100)
.GroupBy(x => x.ID);
DataTable groupingTable = dt.Clone(); // empty, same columns
foreach(var grp in groupQuery)
groupingTable.Rows.Add(grp.Key, grp.Sum(x => x.Percentage));
This presumes that the type of the columns is actually int. If they are strings the best way is to change it to int, if you can't do that you have to use int.Parse.
For example:
ID = int.Parse(r.Field<int>("ID"))`
Update: Although it's not clear what you want if i reread your qustion, especially:
If any one of the ID in table doesn't have 0 or 100 I need to alert
You could use this to get all ID-groups without 0 or 100 percentage:
var without0Or100Perc = dt.AsEnumerable()
.Select(r => new { ID = r.Field<int>("ID"), Percentage = r.Field<int>("Percentage") })
.GroupBy(x => x.ID)
.Where(g => !g.Any(x => x.Percentage == 0 || x.Percentage == 100));
Now you can use Any, FirstOrDefault or a foreach loop to consume this query, so one of following approches:
bool anyWithout0Or100Perc = without0Or100Perc.Any();
var firstWithout0Or100Perc = without0Or100Perc.FirstOrDefault();
anyWithout0Or100Perc = firstWithout0Or100Perc != null;
foreach (var grp in without0Or100Perc)
{
Console.WriteLine("ID: {0} Percentages:{1}",
grp.Key,
String.Join(",", grp.Select(x => x.Percentage)));
}

Categories