I'm translating a query and here's the original:
select top 5 t.usrID, u.FirstName, u.LastName, t.cnt as sCount
from (
select usrID, COUNT(rID) as cnt
from sessions as s where s.sDate > DATEADD(yy, -1, getdate())
group by usrID
) as t
inner join users as u on t.usrID = u.usrID
order by t.cnt desc
Here's what I have so far:
var topUser = (from p in _context.Sessions
where p.SDate > DateTime.Now.AddYears(-1)
join c in _context.Users on p.UsrId equals c.UsrId into j1
from j2 in j1.DefaultIfEmpty()
// group j2 by p.UsrId into grouped
select new
{
p.UsrId,
j2.FirstName,
j2.LastName,
cnt = p.RId
})
//.OrderBy(d => d.cnt)
//.GroupBy(o => o.UsrId)
.Take(5);
I'm having trouble figuring out how to include count() and group by clauses. When I include groupBy my other columns disappear. Thank you.
This is the answer to your answer - not to your original query. I would put it as comment, but without formatting it's hard to explain
Assuming User object has collection of Session your first statement can be drastically simplified:
var topUsers = _context.Sessions
.Where(s => s.SDate > DateTime.Now.AddYears(-1))
.Select(s => new
{
s.UsrId,
cnt = s.User.Sessions.Count(u => u.UsrId == s.UsrId)
})
.OrderByDescending(s => s.cnt)
.Take(5);
You can shape the results to get a ViewModel that also has FirstName and LastName. It all boils down to defining a model with one-to-many relationship
var topUser = (from p in _context.Sessions
where p.SDate > DateTime.Now.AddYears(-1)
join c in _context.Users on p.UsrId equals c.UsrId into j1
from j2 in j1.DefaultIfEmpty()
group j2 by p.UsrId into g
select new
{
UsrId = g.Key,
FirstName = g.Select(x => x.FirstName).FirstOrDefault(),
LastName = g.Select(x => x.LastName).FirstOrDefault(),
sCount = g.Count()
})
.OrderByDescending(d => d.sCount)
.Take(5);
Alright so it's not the most efficient but it works:
var topUsers = _context.Sessions
.Where(s => s.SDate > DateTime.Now.AddYears(-1))
.GroupBy(s => s.UsrId)
.Select(ws => new { ws.Key, cnt = ws.Count() })
.OrderByDescending(s => s.cnt)
.Take(5);
var topNamedUsers = topUsers.Join(_context.Users, ws => ws.Key, ud => ud.UsrId, (ws, ud) => new { ws.Key, ud.FirstName, ud.LastName, ws.cnt });
Related
This is my first post and I hope you can help me. I didn't find an answer so here I'm:
I created this query in SQL and it works.
string consultaSQL =
#"SELECT a.GastosEstudio - ISNULL(SUM(b.GastosEstudioR),0) AS restagastos, a.Articulo - ISNULL(SUM(b.ArticuloR),0) AS restaarticulo, a.Honorarios - ISNULL(SUM(b.HonorariosR),0) AS restahonorarios, a.IVAHonorarios - ISNULL(SUM(b.IVAHonorariosR),0) AS restaivahonorarios FROM deudores a LEFT JOIN recibos b ON a.DNI=b.DNI WHERE a.DNI = #DNI GROUP BY a.GastosEstudio, a.Articulo, a.Honorarios, a.IVAHonorarios";
Now I need to do the same but in LINQ. Basically: I have two tables (deudores and recibos). In deudores I have the debt with the different concepts (columns):
gastos, articulo, honorarios, ivahonorarios
In the table recibos I insert the receipts with the same columns.
The SQL query sums the receipts and subtracts the debt. The closest I get in LINQ was this:
var query = (from d in bd.deudores
join r in bd.recibos on d.DNI equals r.DNI
where d.DNI == DNI
group d by d.DNI into g
select new
{
DNI = g.Key,
articulo = g.Max(x => x.Articulo) - g.Sum(x => x.ArticuloR),
gastos = g.Max(x => x.GastosEstudio) - g.Sum(x => x.GastosEstudioR),
honorarios = g.Max(x => x.Honorarios) - g.Sum(x => x.HonorariosR),
ivah = g.Max(x => x.IVAHonorarios) - g.Sum(x => x.IVAHonorariosR),
});
The problem with this query is that if there is no receipt does not show any information (should show the initial debt)
I try with DefaultIfEmpty but didn't work:
var query = (from d in bd.deudores
join r in bd.recibos on d.DNI equals r.DNI into Pagos
from p in Pagos.DefaultIfEmpty()
where d.DNI == DNI
group d by d.DNI into g
select new
{
DNI = g.Key,
articulo = g.Max(x => x.Articulo) - g.SelectMany(x => x.recibos).Count() >= 1
? g.SelectMany(x => x.recibos).Sum(y => y.ArticuloR)
: 0,
gastos = g.Max(x => x.GastosEstudio) - g.SelectMany(x => x.recibos).Count() >= 1
? g.SelectMany(x => x.recibos).Sum(y => y.GastosEstudioR)
: 0,
honorarios = g.Max(x => x.Honorarios) - g.SelectMany(x => x.recibos).Count() >= 1
? g.SelectMany(x => x.recibos).Sum(y => y.HonorariosR)
: 0,
ivah = g.Max(x => x.IVAHonorarios) - g.SelectMany(x => x.recibos).Count() >= 1
? g.SelectMany(x => x.recibos).Sum(y => y.IVAHonorariosR)
: 0
});
The problem with this query is that it does not subtract it.
Any suggestion?
Thank you!
You want the equivalent of an outer join, so you correctly turn to a GroupJoin, or join ... into. But the query part ...
from d in bd.deudores
join r in bd.recibos on d.DNI equals r.DNI into Pagos
from p in Pagos.DefaultIfEmpty()
where d.DNI == DNI
group d by d.DNI into g
... does more than you want. In fluent LINQ syntax its structure is equivalent to
bd.deudores.GroupJoin(bd.recibos, ...)
.SelectMany(...)
.GroupBy(...)
The point is that the first GroupJoin creates a collection of deudores, each having a group of their recibos, that may be empty. Then the SelectMany flattens it into pairs of one deudores and one recibos or null. Subsequently, the GroupBy creates groups with null elements.
The first GroupJoin is all you need:
from d in bd.deudores
join r in bd.recibos on d.DNI equals r.DNI into g
select new
{
DNI = d.DNI,
articulo = d.Articulo - g.Select(x => x.ArticuloR).DefaultIfEmpty().Sum(),
gastos = d.GastosEstudio - g.Select(x => x.GastosEstudioR).DefaultIfEmpty().Sum(),
honorarios = d.Honorarios - g.Select(x => x.HonorariosR).DefaultIfEmpty().Sum(),
ivah = d.IVAHonorarios - g.Select(x => x.IVAHonorariosR).DefaultIfEmpty().Sum()
});
By adding DefaultIfEmpty() it is ensured that Sum will return 0 when there are no elements.
#Gert Arnold: The relationship between the two tables is a column name DNI. In the table deudores is PK and in the table recibos is FK. Last night i tried this code and it works:
var query = (from d in bd.deudores
join r in bd.recibos
on d.DNI equals r.DNI into g
where d.DNI == DNI
select new
{
articulo = d.Articulo - g.Sum(x => x.ArticuloR) ?? d.Articulo,
gastos = d.GastosEstudio - g.Sum(x => x.GastosEstudioR) ?? d.GastosEstudio,
honorarios = d.Honorarios - g.Sum(x => x.HonorariosR) ?? d.Honorarios,
ivah = d.IVAHonorarios - g.Sum(x => x.IVAHonorariosR) ?? d.IVAHonorarios
});
Is it the best way to do it ?. If you want to give me your opinion will be welcome.
Regards!
I've been puzzling over this problem all morning and can't figure out how to do it in C#.
My SQL query as follows:
select a.CourseID,
a.UserID
from audit a
inner join results r on a.UserID = r.UserID
inner join Course c on a.CourseID = c.CourseID
where c.CourseType = 9 and a.Guid = 'A123F123D123AS123123'
and a.Result = 'Passed' and r.Class = 'Maths'
group by a.CourseID, a.UserID
order by a.UserID
returns exactly what I want, but I can't seem to translate it into linq format. (the format being used here is what is required in my job at the moment so please advise on this format)
So far I have the following:
var audits = auditRepository.Get(a => a.Course.CourseType == 9 && a.GUID == this.Company.GUID && a.Result == "Passed", null, null,
a => a.Course, a => a.User)
.Join(resultsRepository.Get(r => r.GUID == this.Company.GUID && r.Class == class),
a => a.UserID,
r => r.UserID,
(a, r) => new Audit
{
User = a.User,
Course = a.Course,
Result = a.Result,
Timestamp = a.Timestamp,
AuditID = a.AuditID,
UserID = a.UserID
}
)
.OrderByDescending(o => o.Timestamp)
.GroupBy(u => new { u.User, u.Course })
.Select(grp => grp.ToList())
.ToList();
However this returns duplicates.
Any advice is appreciated, thanks
H
Instead of
.Select(grp => grp.ToList())
Select only the first element from each group to exclude duplicates:
.Select(grp => grp.First())
If you need a count also:
.Select(t => new{grp = t.First(),cnt = t.Count()} )
Fix:
.Select(t => new { grp = t.First(), cnt = t.Select(s => s.AuditID).Distinct().Count() })
I have a SQL Query
select Firma.Name as companyName,
Taetigkeit.Taetigkeit as skillName,
SUM(Zeit) as time
from Zeiterfassung
inner join Firma On ZEiterfassung.FirmenID = Firma.ID
inner join Taetigkeit on Zeiterfassung.TaetigkeitID = Taetigkeit.ID
group by Taetigkeit, Firma.Name
order by Firma.Name
And want to "translate" it to linq. Here is what I tried:
var query = db.Zeiterfassung
.Where(x => x.Firma.ID == x.FirmenID && x.TaetigkeitID == x.Taetigkeit.ID)
.GroupBy(x => x.Taetigkeit.Taetigkeit1)
.Select(x => new Evaluation() { skillName = x.Key, time = x.Sum(y => y.Zeit), //skillName = x.Sum(x => x.Zeit), })
.OrderBy(x => x.skillName);
I dont know who to solve this with joins and the group by because all the time when i do a groupBy i cant access the other members.
From data you provided, I think query should look like
from z in db.Zeiterfassung
join f in db.Firma on z.FirmenID equals f.ID
join t in db.Taetigkeit on z.TaetigkeitID equals t.ID
select new { f.Name, t.Taetigkeit, z.Zeit) into x
group x by new { x.Taetigkeit, f.Name } into g
select new {
CompanyName = g.Key.Name,
SkillName = g.Key.Taetigkeit,
Time = g.Sum(i => i.Zeit)
}
Or with navigation properties:
db.Zeiterfassung
.Select(z => new { z.Zeit, z.Taetigkeit.Taetigkeit1, z.Firma.Name })
.GroupBy(x => new { x.Taetigkeit1, x.Name })
.Select(g => new Evaluation {
companyName = g.Key.Name,
skillName = g.Key.Taetigkeit1,
time = g.Sum(y => y.Zeit)
});
I decided to try my hand at LINQ and so far its been a miserable failure. I need to convert the following SQL query to LINQ:
SELECT
MAX(A.NEXTPAYMENTDATE) as NextPaymentDate
, SUM(B.PurchasePrice) - SUM(A.Amount) AS BALANCE
, c.FirstName
, c.LastName
, b.[year]
, b.make
, b.model
FROM Payments A
JOIN Vehicles B ON A.VehicleId = B.Id
JOIN Customers C ON b.CustomerId = c.Id
GROUP BY VehicleId, c.FirstName, c.LastName, b.[year], b.make, b.model
HAVING SUM(B.PurchasePrice) - SUM(A.Amount) > 0
This is what I have so far. It seems to work to a certain extent, but I don't know how to progress from here.
var groupedpayments =
from payments in db.Payments
group payments by new { payments.VehicleId }
into paymentGroup
let maxDate = paymentGroup.Max(x => x.NextPaymentDate)
let paid = paymentGroup.Sum(x => x.Amount)
select
new { Payments = paymentGroup.Where(x => x.NextPaymentDate == maxDate)};
I think that is what you need.
var query =
Payments.Join(Vehicles, p => p.VehicleId, v => v.Id, (p, v) => new {p, v})
.Join(Customers, d => d.v.CustomerId, c => c.Id, (d, c) => new {d, c})
.GroupBy(r =>
new {
r.d.p.VehicleId,
r.d.v.year,
r.d.v.make,
r.d.v.model,
r.c.FirstName,
r.c.LastName
},
(g, data) =>
new {
FirstName = g.FirstName,
LastName = g.LastName,
Year = g.year,
Make = g.make,
Model = g.model,
NextPaymentDate = data.Max(dd => dd.d.p.NEXTPAYMENTDATE),
Balance = data.Sum(dd => dd.d.v.PurchasePrice)
- data.Sum(dd => dd.d.p.Amount)})
.Where(r => r.Balance > 0);
I'm trying to convert this linq query to lambda
var query = (from a in context.Table_A
join u in context.Table_B on a.scored equals u.userid
join u2 in context.Table_B on a.scorer equals u2.userid
from cs in a.Table_C //(Table_A is related to Table_C)
where (a.date>= startdate && a.date < enddate)
select new MSViewModel
{
scored= u.User.name,
scorer= u2.User.name,
subject_name = cs.Subject.name,
score = cs.score,
categoryid = cs.id,
})
.AsEnumerable()
.GroupBy(t => t.scored)
.ToList();
so far this is what i have. I'm kinda lost what to do next.
var tobi = db.Table_A.Join(db.Table_B,a=>a.scored,u=>u.userid,
(a,u) => new {scored=u.User.name });
db.Table_A.Join(db.Table_B,a1=>a1.scorer,u2=>u2.userid,
(a,u2)=> new {scorer= u2.User.name});
Firstly, I'd agree with Arran's comment: the query expression is going to be much simpler to deal with. I'm absolutely on board with using the lambda form where it makes sense, but joins are generally much simpler in query expressions.
Having said that, you basically need to imitate transparent identifiers. The code below is untested, but looks vaguely plausible to me.
var query = context.Table_A
.Join(context.Table_B, a => a.scored, u => u.userid,
(a, u) => new { a, u })
.Join(context.Table_B, p => p.a.scorer, u2 => u2.userid,
(p, u2) => new { p, u2 })
.SelectMany(q => q.p.a.TableC, (q, cs) => new { q, cs })
.Where(r => r.q.p.a.date >= startdate && r.q.p.a.date < enddate)
.Select(q => new MSViewModel {
scored= r.q.p.u.User.name,
scorer= r.q.u2.User.name,
subject_name = r.cs.Subject.name,
score = r.cs.score,
categoryid = r.cs.id,
})
.AsEnumerable()
.GroupBy(t => t.scored)
.ToList();
Basically p and q and r are the transparent identifiers here. You've got three of them because you've got two joins and a subsequent from clause.
To expand on my comment, If you have Resharper:
Resharper showing option to convert LINQ to Lambada
After the conversion:
Try this one:
var query = (_context.Table_A.Join(_context.Table_B, a => a.scored, u =>
u.userid,
(a, u) => new {a, u}).Join(_context.Table_B,
#t => #t.a.scorer,
u2 => u2.userid,
(#t, u2) => new {#t, u2}).
SelectMany(#t => _context.Table_A, (#t, cs) => new MSViewModel()
{
scored = #t.#t.u.User.name,
scorer= #t.u2.User.name,
subject_name = #t.cs.Subject.name,
score = #t.cs.score,
categoryid = #t.cs.id,
})).AsEnumerable()
.ToList();