How to get dictinct userid with order by close using Linq - c#

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)
}
);

Related

How to rank elements when it has duplicates

I am trying to figure out a way to rank items in a list that has duplicated values.
For example:
QTECDE
RANK
40
1
30
2
24
3
18
4
4
5
4
5
3
6
But my code always skips a number when I have a duplicated rank. This what I get:
QTECDE
RANK
40
1
30
2
24
3
18
4
4
5
4
5
3
7 (7 insted of 6)
Here's my code:
var rankedList = oList.OrderByDescending(p => p.QTECDE)
.Select((p, i) => new { Order = 1 + i, lst = p })
.GroupBy(p => new { p.lst.QTECDE })
.SelectMany(g => g.Select(p => new
{
RANK = g.Min(x => x.Order),
NO_ART = p.lst.NO_ART,
QTECDE = p.lst.QTECDE,
LIB_INDEX_FR_SUP = p.lst.LIB_NIVEAU_SUP_FR,
LIB_IMAGE = p.LIB_IMAGE,
}));
Any solutions?
You just need the index of the group not the items:
var rankedList = oList
.OrderByDescending(p => p.QTECDE)
.GroupBy(p => new { p.QTECDE })
.SelectMany((g, groupIndex) => g
.Select(p => new
{
RANK = groupIndex + 1,
NO_ART = p.NO_ART,
QTECDE = p.QTECDE,
LIB_INDEX_FR_SUP = p.LIB_NIVEAU_SUP_FR,
LIB_IMAGE = p.LIB_IMAGE,
}));
You're determining the rank/order on your source items. You want to apply the (item, index) to your SelectMany() instead of your Select().

Sum multiple column in LINQ

How can I reproduce this query using linq?
SELECT
SUM(SecondsSinceLastEvent) as AccessTime,
SUM (case when DownloadType = 0 then 1 end) FileDownloadCount,
SUM (case when DownloadType = 1 then 1 end) KortextDownloadCount,
SUM (case when Action = 'print' then 1 end) PrintCountFROM EReaderLogs WHERE PublishedContent_Id = XXX
In LINQ to Entities you need to first use GroupBy before using multiple aggregate functions. To sum all the elements in a column you can group by some static key so then a single group would be a whole table:
var query = context.EReaderLogs
.Where(e => e.PublishedContent_Id == someValue)
.GroupBy(a => 1, (k, g) =>
{
AccessTime = g.Sum(e => e.SecondsSinceLastEvent),
FileDownloadCount = g.Sum(e => e.DownloadType == 0 ? 1 : 0),
KortextDownloadCount = g.Sum(e => e.DownloadType == 1 ? 1 : 0),
PrintCount = g.Sum(e => e.Action == "print" ? 1 : 0)
});

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()
});

Group by and MIN() in LINQ

Trying to convert the below SQL query to LINQ, but I'm stuck at grouping by ClientCompany.
SELECT TOP 300 ClientCompany,
CASE WHEN MIN(FeatureID) = 12 THEN 1 ELSE 0 END as Sort
FROM Ad
LEFT JOIN AdFeature
ON Ad.ID = AdFeature.AdID
WHERE (AdFeature.FeatureID = 13 OR AdFeature.FeatureID = 12)
AND SiteID = 2
GROUP BY ClientCompany
ORDER BY Sort DESC
My attempt to convert this to LINQ:
(from a in Ads
join af in AdFeatures
on new {
join1 = a.ID,
join3 = 2
} equals new {
join1 = af.AdID,
join3 = af.SiteID
}
let sort = (
af.FeatureID == 12 ? 1 : 0
)
orderby sort descending
where af.FeatureID == 13 || af.FeatureID == 12
select new { a.ClientCompany, sort } ).Take(300)
How would I use MIN(FeatureID) and GROUP BY ClientCompany in LINQ, so that I only get a single row per ClientCompany back?
EDIT
This worked! Based on Daniel Hilgarth's answer. Is there anything that can go horribly wrong with this solution?
Ads.Join(AdFeatures, x => x.ID, x => x.AdID,
(a, af) => new { Ad = a, AdFeature = af })
.Where(x => x.AdFeature.FeatureID == 12 || x.AdFeature.FeatureID == 13)
.Where(x => x.AdFeature.SiteID == 2)
.GroupBy(x => x.Ad.ClientCompany)
.Select(g => new { ClientCompany = g.Key, Sort = g.Min(x => x.AdFeature.FeatureID) == 12 ? 1 : 0 })
.OrderByDescending(x => x.Sort)
.Take(300)
Try this:
Ads.Join(AdFeatures, x => x.FeatureID, x => x.FeatureID,
(a, af) => new { Ad = a, AdFeature = af })
.Where(x => x.AdFeature.FeatureID == 12 || x.AdFeature.FeatureID == 13)
.Where(x => x.AdFeature.SiteID == 2)
.GroupBy(x => x.Ad.ClientCompany)
.Select(g => new { ClientCompany = g.Key,
Sort = g.Min(x => x.AdFeature.FeatureID) == 12 ? 1 : 0 });
Please note, I changed the left outer join into an inner join, because your original query accesses AdFeature unconditionally, making it effectively an inner join .
hi I would write it like that
context.Ads.Where(ad => ad.AdFeatures.Any(feature => (feature.FeatureID == 13 || feature.FeatureID == 12) && feature.SiteID == 2))
.GroupBy(ad => ad.ClientCompany)
.Select(ads => new
{
cc = ads.Key, sort = ads.SelectMany(ad => ad.AdFeatures)
.Select(feature => feature.FeatureID)
.Min() == 12
})
.OrderBy(arg => arg.sort).Take(300);
Try this:
(from a in ads
join af in AdFeatures on a.ID equals af.AdID into g
from x in g.DefaultIfEmpty()
where x.FeatureID == 13 || x.FeatureID == 12
where x.SiteID == 2
orderby a.Sort descending
group a by a.ClientCompany into g2
from x2 in g2
let sort = g2.Select(T => T.FeatureID).Min() == 12 ? 1 : 0
select new { a.ClientCompany, Sort = sort }).Take(300);
Why do you need grouping anyway?

C# Group with conditional

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)
});

Categories

Resources