C# Group with conditional - c#

how can i grouping a data with conditional if bill < 10 ?
i have table:
meetingId | bill
------------------
a | 6
b | 7
c | 1
a | 5
a | 3
b | 4
g | 2
expected results :
a = 6+5+3 = 14 limit is 10 --> 10 and 4
b = 7+4 = 11 so limit is 10 --> 10 and 1
c and g not over the limit.
meetingId | bill
------------------
a | 10
a | 4
b | 10
b | 1
c | 1
g | 2
i tried in SQL why but i stuck with if condition
my SQL :
SELECT NO_ORDRE
,ORDRE.CODE_CLIENT As CodeCl
,[CODE_DEST]
,ORDRE.RS_NOM As OrdreRS
,ORDRE.ADRESSE As OrdreAdr
,ORDRE.CP As OrdreCP
,ORDRE.VILLE As OrdreVille
,ENLEV_CREMB
,ENLEV_DECL
,MODAL_MODE
,[PAYS]
,[INSEE]
,[SIRET]
,ORDRE.TEL As OrdreTel
,ORDRE.FAX As OrdreFax
,[EMAIL]
,[NBR_COLIS]
,[POID]
,[OBS]
,[DATE_CREE]
,[DATE_MODIF]
,[REF_EXPED]
,[AUTRE_REF]
,[AGENCE]
,[TRANSPORTEUR]
,NOM
,CAPITAL
,LIBELLE
,T_LOGO.IMG As FaImg
,T_LOGO.ADRESSE As FaAdr
,T_LOGO.CP As FaCp
,T_LOGO.VILLE As FaVille
,T_LOGO.TEL As FaTel
,T_LOGO.FAX As FaFax
,FAWEB_CLIENT.RS_NOM As CliRsNom
,FAWEB_CLIENT.ADRESSE As CliAdr
,FAWEB_CLIENT.CP As CliCp
,FAWEB_CLIENT.VILLE As CliVille
FROM [ORDRE]
LEFT JOIN T_LOGO ON ORDRE.TRANSPORTEUR = T_LOGO.NOID
LEFT JOIN FAWEB_CLIENT ON ORDRE.CODE_CLIENT = FAWEB_CLIENT.CODE_CLIENT
WHERE (STATUT_ORDRE = 2) AND (TRANSPORTEUR IN (SELECT ParsedString From dbo.ParseStringList(#Trans)))
and then i use in C#
List<Pers_Ordre> oListOrdre = new List<Pers_Ordre>();
while (readerOne.Read())
{
Pers_Ordre oPerOrdr = new Pers_Ordre();
Pers_Ordre test = (from t in oListOrdre where t.DestId == readerOne["CODE_DEST"].ToString() select t).FirstOrDefault();
oPerOrdr.OrdreId = Convert.ToInt32(readerOne["NO_ORDRE"]);
oPerOrdr.DestId = readerOne["CODE_DEST"].ToString();
if (test == null)
{
oListOrdre.Add(oPerOrdr);
}
else
{
int NbrColis = (from t in oListOrdre where t.DestId == readerOne["CODE_DEST"].ToString() select t.NbrColis).FirstOrDefault();
if (NbrColis < 5)
{
test.NbrColis += NbrColis;
}
}
}
it not work what i expected.
Thanks for your help!

(Not really an answer, but this doesn't fit in a comment.)
Here's a LINQ-to-Objects query that groups items by meetingId and creates new items such that there is one item with bill less than 10 and as many items as needed with bill equalling 10 to keep the sum:
Is this what you're looking for?
Code:
var list = new List<Tuple<char, int>>
{
Tuple.Create('a', 6),
Tuple.Create('b', 7),
Tuple.Create('c', 1),
Tuple.Create('a', 5),
Tuple.Create('a', 3),
Tuple.Create('b', 4),
Tuple.Create('g', 2),
};
var result = list
.GroupBy(x => x.Item1)
.Select(g => new
{
Key = g.Key,
Sum = g.Sum(x => x.Item2)
})
.Select(p => new
{
Key = p.Key,
Items = Enumerable.Repeat(10, p.Sum / 10)
.Concat(Enumerable.Repeat(p.Sum % 10, 1))
})
.SelectMany(p => p.Items.Select(i => Tuple.Create(p.Key, i)))
.ToList();

This SQL query will return the wanted results:
SELECT meetingId, SUM(bill) as bill_total
FROM table
GROUP BY meetingId
HAVING SUM(bill) < 10

You should not do this at the client side because it can get pretty intensive, a simple GROUP BY with a HAVING clause should give you the expected results:
Sample data:
The query you need:
SELECT
MeetingID,
SUM(bill) AS Total
FROM
Table_1
GROUP BY
MeetingID
HAVING
SUM(bill) < 10
The results of the query:

table.GroupBy(p => p.meetingId).Where(p => p.Sum(q => q.bill) < 10)
.Select(p => new
{
meetingId= p.Key,
bill= p.Sum(q => q.bill)
});

Related

How to get dictinct userid with order by close using Linq

I have table called info, and its data something like this:
FKUserID
CompletedTime
Type
1
2021-03-10 12:56:00.423
5
245
2021-03-10 12:46:46.977
5
1
2021-03-10 12:44:53.683
5
1
2021-03-10 12:40:54.733
5
1
2021-03-10 12:35:26.307
5
245
2021-03-10 11:11:33.887
5
245
2021-03-10 10:18:11.403
5
I need to get distinct userID data, and also with the maximum completed time of theirs CompletedTime column
expected output is:
FKUserID
CompletedTime
Type
1
2021-03-10 12:56:00.423
5
245
2021-03-10 12:46:46.977
5
I need to do this using Linq query
How can I do this, I did it using SQl, need it using Linq
SELECT FKUserID , MAX(CompletedTime)
from Info
where cast(CompletedTime as date) = '2021-03-10'
and Status = 5
GROUP BY FKUserID;
You can use the following query. The following query implements your SQL query.
var query = context.Info.GroupBy(a => a.FKUserID)
.Join(context.Info,
left => left.Key,
right => right.FKUserID,
(left, right) => new { left, right })
.Where(a => a.right.CompletedTime.ToShortDateString() == "2021-03-10" && a.right.Status == 5)
.Select(a => new
{
FKUserID = a.left.Key,
CompletedTime = a.left.Max(x => x.CompletedTime)
}).ToList();
Something like this
var d = new DateTime(2021, 3, 10);
var d2 = d.AddDays(1);
dbContext.Infos
.Where(i => i.Status == 5 && i.CompletedTime >= d && i.CompletedTime < d2)
.GroupBy(i => i.FkUserId)
.Select(g => new {
FkUserId = g.Key,
CompletedTime = g.Max(g2 => g2.CompletedTime)
}
);

how to group data in Linq with date

Im using Linq and having 2 tables which store the record as following
OrderMasterTable
Order_ID |Place_Date |ExpectedDelivery_Date |IsDelivered
==========|=============|=======================|============
1 |1993-02-19 | 1993-02-20 00:01:00 | True
2 |1993-02-20 | 1993-02-20 00:01:00 | True
3 |1993-02-21 | 1993-02-22 00:01:00 | True
4 |1993-02-22 | 1993-02-23 00:01:00 | False
OrderAssignTable
Order_ID |Delivered_By |Delivery_Date
==========|=============|=======================
1 |User123 | 1993-02-20 00:01:00
2 |UserXyz | 1993-02-20 00:01:01
3 |User345 | 1993-02-24 00:01:00
I want to group output data by delivered date in such a way that it appears in a following way:
Date: 1993-02-20,
OnTime: 1,
Delayed:1
Date: 1993-02-22,
OnTime :1,
Delayed: 0
* OnTime if deliveryDateTime is <= ExpectedTime
* Date is deliveryDate
pls,help me out
you can try this.
var query = from assign in OrderAssignTable
join master in OrderMasterTable on assign.Order_ID equals master.Order_ID
where master.IsDelivered == true
group new { assign, master } by assign.Delivery_Date.Date into g
select new
{
Date = g.Key,
OnTime = g.Count(i => i.assign.Delivery_Date <= i.master.ExpectedDelivery_Date),
Delayed = g.Count(i => i.assign.Delivery_Date > i.master.ExpectedDelivery_Date)
};
That should do:
var result = Orders
.Join(Assigns, o => o.OrderId, a => a.OrderId, (o, a) => new {Order = o, Assign = a})
.GroupBy(o => o.Order.ExpectedDeliveryDate.Date)
.Select(g => new
{
Date = g.Key,
OnTime = g.Count(o => o.Assign.DeliveryDate <= o.Order.ExpectedDeliveryDate),
Delayed = g.Count(o => o.Assign.DeliveryDate > o.Order.ExpectedDeliveryDate)
})
.ToArray();

How to get data between two columns in datatable?

If i have two data tables like this :
1-penaltyrule
ser from-min to-min pen
1 1 55 1
2 56 90 2
3 91 null 3
2- penaltyEmp
ser emp tot-min
1 782 2
2 672 67
3 677 92
4 56 7
I want to get the pen for each user with LINQ
i mean where tot-min BETWEEN from-min AND to-min SELECT
pen
I want data table with the following result :
emp pen
782 1
672 2
677 3
56 1
You can use this query:
var penaltyEmps = penaltyEmp.AsEnumerable()
.Select(r => new { ser = r.Field<int>("ser"), emp=r.Field<int>("emp"), tot_min=r.Field<int>("tot-min"), row = r });
var penaltyrules = penaltyrule.AsEnumerable()
.Select(r => new { ser = r.Field<int>("ser"), from_min=r.Field<int>("from-min"), to_min=r.Field<int>("to-min"), row = r });
DataTable tblResult = penaltyEmps
.Select(x => new
{
penaltyEmp = x,
matchingRules = penaltyrules.Where(x2 => x.tot_min >= x2.from_min && x.tot_min <= x2.to_min)
})
.Where(x => x.matchingRules.Any())
.Select(x => x.penaltyEmp.row)
.CopyToDataTable();
Something like this should work in LINQ for you: (Don't forget to include the System.Linq namespace).
var results = from emp in context.penaltyEmp
join rule in context.penaltyRule on emp.ser equals rule.ser
where emp.tot-min > rule.from-min && emp.tot-min < rule.to-min
select new { emp = emp.emp, pen = rule.pen };
you can use this if you are using EF
var data=(from a in db.penaltyEmp
select new{
emp= a.emp,
pen= db.penaltyrule.Where(d=>d.from-min>a.tot-min && d.to-min==null?true:(d.to-min>a.tot-min)).Select(d=>d.pen).firstOrDefault()
});

How to find the min dates from the list of items?

I have a table structure like this
id | itemId | date |
1 | a1 | 6/14/2015
2 | a1 | 3/14/2015
3 | a1 | 2/14/2015
4 | b1 | 6/14/2015
5 | c1 | 6/14/2015
From this table structure I am trying to get all the distinct items that has min date. for e.g. I am trying to get id = 3,4 and 5.
I have tried following code but I couldn't
var items = (from i in _db.Items
//where min(i.date) // doesn't seem right
group i by i.itemID
into d select new
{
iId = d.Key,
}).Distinct();
Given your sample data, I would do this:
var query =
from i in _db.Items
group i by i.itemId into gis
let lookup = gis.ToLookup(x => x.date, x => x.id)
from x in lookup[gis.Min(y => y.date)]
select x;
var items = from i in _db.Items
group i.date by i.itemID
into d select new {
iId = d.Key, iDate = d.Min()
};

Roll up totals of an ObservableCollection<MyType> with a Linq expression

I have a Silverlight delegate which gets an ObservableCollection in the EventArgs Result. The DTO myType has fields Order, StartDate, Status, PlannedAmount, ActualAmount, and few others. The query on the WCF service side gets several rows per Order, varying only by PlannedAmount and ActualAmount.
Order # | StartDate | PlannedAmount| ActualAmount | Order Comments ....
Order A | March 15 | 20.00 | 0.00 | Comment 1 ...
Order A | March 15 | 30.00 | 0.00 | Comment 1 ...
Order A | March 15 | 10.00 | 0.00 | Comment 1 ...
Order A | March 15 | 0.00 | 30.00 | Comment 1 ...
Order B | March 25 | 10.00 | 0 | Comment 2 ...
Order B | March 25 | 0.00 | 5.00 | Comment 2 ...
I would like to show only one row per Order and sum all the PlannedAmount and ActualAmount values. I prefer to change this in the presentation layer as I don't know what other consumers of the WCF Operation require. So I want to roll it up to...
Order # | StartDate | PlannedAmount| ActualAmount | Order Comments ....
Order A | March 15 | 60.00 | 30.00 | Comment 1 ...
Order B | March 25 | 10.00 | 5.00 | Comment 2 ...
And then make this an ObservableCollection of the same type that I had before.
I have tried this but I cannot seem to get anything but the Key and the Sum values.
var Orders =
from wo in OrdersPerOperation
group wo by wo.OrderNo
into g
select new
{
OrderNo = g.Key,
Planned = g.Sum(wo => wo.Planned),
Actual = g.Sum(wo => wo.Actual),
OrderComments = g.Select(wo => wo.Equipment),
StartDate = g.Select(wo => wo.StartDate),
Status = g.Select(wo => wo.Status),
OrderType = g.Select(wo => wo.OrderType) //,...
};
Edit
Getting just the key and two sums is straight-forward:
var Orders =
from wo in OrdersPerOperation
group wo by wo.OrderNo
into g
select new
{
OrderNo = g.Key,
Planned = g.Sum(wo => wo.Planned),
Actual = g.Sum(wo => wo.Actual)
}
The challenge is getting all of the other fields, which are repetitive to also show in the result.
EDIT
I made this guess that this might work like a self-referencing SQL query. I believe I am on the right track with this, in that each element has data in the correct format. I still cannot set the results to the ItemsSource of the Silverlight grid, which I could bind, before all of this Linq confusion. The IDE warns me that FirstOrDefault is a possible NullReferenceException.
var workOrders = from wo in workOrdersPerOperation
group wo by wo.OrderNo
into g
select new
{
OrderNo = g.Key,
Planned = g.Sum(wo => wo.Planned),
Actual = g.Sum(wo => wo.Actual),
g.FirstOrDefault(wo => wo.OrderNo == g.Key).Location,
g.FirstOrDefault(wo => wo.OrderNo == g.Key).Equipment,
g.FirstOrDefault(wo => wo.OrderNo == g.Key).StartDate,
g.FirstOrDefault(wo => wo.OrderNo == g.Key).Status,
g.FirstOrDefault(wo => wo.OrderNo == g.Key).OrderType,
g.FirstOrDefault(wo => wo.OrderNo == g.Key).AccType,
g.FirstOrDefault(wo => wo.OrderNo == g.Key).WorkCenter,
g.FirstOrDefault(wo => wo.OrderNo == g.Key).Description,
g.FirstOrDefault(wo => wo.OrderNo == g.Key).Priority
};
Can anyone get me past this step? I still need to bind it to the control.
You want g.SelectMany(wo => wo.Equipment) instead.
I'm pretty sure that this
Location = g.FirstOrDefault(wo => wo.OrderNo == g.Key).Location,
Will produce the same result as this
Location = g.FirstOrDefault().Location,
Additionally, you only need to use FirstOrDefault if your collection might be empty. However, the group would not exist if there were no items in it. This allows you to simplify it down to this.
Location = g.First().Location,
You can make the final solution
var orders = from wo in ordersPerOperation
group wo by wo.OrderNo
into g
select new MyType
{
OrderNo = g.Key,
Planned = g.Sum(wo => wo.Planned),
Actual = g.Sum(wo => wo.Actual),
Location = g.First().Location,
Equipment = g.First().Equipment,
StartDate = g.First().StartDate,
Status = g.First().Status,
OrderType = g.First().OrderType,
AccType = g.First().AccType,
WorkCenter = g.First().WorkCenter,
Description = g.First().Description,
Priority = g.First().Priority
};
Try:
OrderComments = g.Select(wo => wo.Equipment).ToList()
I found that I could select into a collection of new instances of MyClass with initializers.
var orders = from wo in ordersPerOperation
group wo by wo.OrderNo
into g
select new MyType()
{
OrderNo = g.Key,
Planned = g.Sum(wo => wo.Planned),
Actual = g.Sum(wo => wo.Actual),
Location = g.FirstOrDefault(wo => wo.OrderNo == g.Key).Location,
Equipment = g.FirstOrDefault(wo => wo.OrderNo == g.Key).Equipment,
StartDate = g.FirstOrDefault(wo => wo.OrderNo == g.Key).StartDate,
Status = g.FirstOrDefault(wo => wo.OrderNo == g.Key).Status,
OrderType = g.FirstOrDefault(wo => wo.OrderNo == g.Key).OrderType,
AccType = g.FirstOrDefault(wo => wo.OrderNo == g.Key).AccType,
WorkCenter = g.FirstOrDefault(wo => wo.OrderNo == g.Key).WorkCenter,
Description = g.FirstOrDefault(wo => wo.OrderNo == g.Key).Description,
Priority = g.FirstOrDefault(wo => wo.OrderNo == g.Key).Priority
};
This is not an ObservableCollection, but it turns out that I don't need it be after all.

Categories

Resources