LINQ group by with multiple fields and aggregate function - c#

I'm trying to make a query in LINQ translating the following T-SQL query:
select b.crs,
d.epg,
d.m,
Count (a.sq_rea) as qt
from t_aaaa a with (nolock)
join t_bbbb b with (nolock) on a.crs = b.crs
join t_cccc c with (nolock) on a.spr = c.spr and c.rsp = 1
join v_dddd d with (nolock) on c.epg = d.epg
Where a.st = 5
group by b.crs, d.epg, d.m
However, I cannot use the aggregate function like this:
var llstData = (from a in lobjaaaaDao.list()
join b in lobjbbbbDao.list() on a.p equals b.p
join c in lobjcccc.listar() on a.u equals c.u
from d in lobjddddDao.list()
where a.w == d.w &&
a.st.Equals(5) &&
d.Indent == false
group a by new { b.xxxx, c.yyyy, c.zzzz } into grp
select new
{
grp.Key.xxxx,
grp.Key.yyyy,
grp.Key.zzzz,
total = a.kkkk.Count() // ERROR ON THIS LINE
}
).ToList();
I am getting this error:
The name a does not exist in th current context
How can I fix the error?

In the last select statement the only parameter from the query you are accessible to is grp; where each group is IGrouping; each group is represented by a key and an IEnumerable which is in your case : IEnumerable<a>. Having said that; you can replace the line total = a.kkkk.Count() with total = grp.SelectMany(v=> v.kkkk).Count() OR total = grp.Sum(a => a.kkkk.Count()) to resolve the issue.
This way total represents the summation of kkkk counts in each a in the group.

Related

How can we perform a select into another select using Linq c# left join, count , sum, where

How can I convert my sql code into Linq format :
How can we perform a select into another select using Linq c# :
My sql code :
SELECT DepartementProjects.Label, a.Number FROM
(SELECT DepartementProjects.Label ,count(1) as Number FROM DepartementProjects
inner join Absences on DepartementProjects.Id = Absences.DepartementProjectID
where Absences.Profil='SHT'
group by DepartementProjects.Label ) a right join DepartementProjects on DepartementProjects.Label = a.Label;
My attempt :
var AbsByDepartmentADM = from department in _dbContext.DepartementProjects
join abs in _dbContext.Absences on department.Id equals abs.DepartementProjectID
into groupedResult
from groupedResultRight in groupedResult.DefaultIfEmpty()
group groupedResultRight by department.Label into grouped
let NumberOfAbsence = grouped.Count(t => t.DepartementProjectID != null)
let WorkedHours = grouped.Sum(a => a.WorkedHours != null ? a.WorkedHours : 0)
select new
{
DepartmentId = grouped.Key,
NumberOfAbsence,
WorkedHours,
AbsencesHours = (8 * NumberOfAbsence - WorkedHours),
};
If you are trying to translate SQL, translate any subselects first, then the main select, and translate in LINQ phrase order. Also, your LINQ adds some values not in the SQL, so I didn't try to change the SQL to match:
var sub = from dept in _dbContext.DepartementProjects
join abs in _dbContext.Absences on dept.Id equals abs.DepartementProjectID into absj
from abs in absj
where abs.Profil == "SHT"
group abs by dept.Label into absg
select new { Label = absg.Key, Number = absg.Count() };
var ans = from dept in _dbContext.DepartementProjects
join a in sub on dept.Label equals a.Label into lnj
from ln in lnj.DefaultIfEmpty()
select new { dept.Label, ln.Number };

LINQ Count returning 1 instead of zero for an empty group

I've got this SQL query:
SELECT oy.ownerId, oy.Year, COUNT(doc.Id) as docCount FROM aavabruf.owneryears oy
left join vastdocuments doc
on oy.ownerId = doc.Ownerid and oy.Year = doc.Year
group by oy.ownerid, oy.year
order by docCount
It shows docCount as ZERO for the OwnerId, Year pairs that have no document match in the vastdocuments table.
I tried to do the same with LINQ using the suggested left outer join solution:
from oy in OwnerYears
join doc in VaStDocuments on new {oy.OwnerId, oy.Year} equals new {doc.OwnerId , doc.Year} into docS
from docIfNull in docS.DefaultIfEmpty()
group oy by new {oy.OwnerId, oy.Year} into g
orderby g.Count() ascending
select new { OwnerId = g.Key.OwnerId, Year = g.Key.Year, docCount = g.Count()}
However, for the OwnerId, Year groups that are not present in the VastDocuments table I get docCount as ONE, not ZERO. If I remove the
from docIfNull in docS.DefaultIfEmpty()
line the "empty" groups will not be shown at all.
How can i get the Count as zero just as it is in the SQL query? I tried the following:
Count = docIfNull == null ? 0 : g.Count()
however in this case I get an error:
The name 'docIfNull' does not exist in the current context
The simplest approach is to count non-null values:
g.Count(x => x != null)
I'd suggest moving the ordering after the select so that you can avoid repeating yourself:
select new { g.Key.OwnerId, g.Key.Year, DocCount = g.Count(x => x != null) } into result
orderby result.DocCount
select result
However, I note that currently you're not using docIfNull at all at the moment... so I suspect your join isn't really doing what you want it to. Perhaps you should be using
group docIfNull by new { oy.OwnerId, oy.Year } into g
?
SQL COUNT function ignores the NULL values, while LINQ Count function w/o predicate counts everything, including nulls.
You can get the same result in LINQ by using the predicate version of Count like this (note the group docIfNull so the g elements will be of the same type as docIfNull):
from oy in OwnerYears
join doc in VaStDocuments on new { oy.OwnerId, oy.Year } equals new { doc.OwnerId, doc.Year } into docS
from docIfNull in docS.DefaultIfEmpty()
group docIfNull by new { oy.OwnerId, oy.Year } into g
let docCount = g.Count(doc => doc != null)
orderby docCount ascending
select new { OwnerId = g.Key.OwnerId, Year = g.Key.Year, docCount = docCount }
(the let clause is just to reuse the expression in orderby and select).
However in LINQ you have another option - in case the (OwnerId, Year) combination inside OwnerYears is unique as it seems, instead of left outer join pattern followed by group by and Count filtering nulls you could use simple group join operator with regular Count call:
from oy in OwnerYears
join doc in VaStDocuments on new { oy.OwnerId, oy.Year } equals new { doc.OwnerId, doc.Year } into docs
let docCount = docs.Count()
orderby docCount ascending
select new { OwnerId = oy.OwnerId, Year = oy.Year, docCount = docCount }

LINQ to Entities grouping

I have written the following SQL-query that illustrates what I'm trying to achieve:
SELECT
K.id,
SUM(BP.pris)
FROM Kunde K
JOIN Booking BO ON K.id = BO.Kunde_id
JOIN Bane_Booking BB ON BO.id = BB.Booking_id
JOIN Banepris BP ON BO.starttid = BP.time
WHERE BO.gratis = 0
GROUP BY K.id;
Basically it's retrieving the total amount spend by customers. Now I'm trying to convert this query into LINQ, as I'm using LINQ to Entities in my application. This is what I have so far:
from kunde in context.Kunde
join booking in context.Booking on kunde equals booking.Kunde
join banepris in context.Banepris on booking.starttid equals banepris.time
from baneBooking in booking.Bane
select new { Kunde = kunde, Booking = booking, BaneBooking = baneBooking, Banepris = banepris };
I would like however to be able to group these in the same LINQ-query so I dont have to group them manually afterwards. How would i go about achieving this?
I need to get the "kunde"-object and the sum of "banepris.pris".
Without your database, I can't test this, but this should be close:
from K in context.Kunde
join BO in context.Booking on K.id equals BO.Kunde_id
join BP in context.Banepris on BO.starttid equals BP.time
where BO.gratis == 0
group new { Kunde = K, Pris = BP.pris } by K.id into g
select new { ID=g.Key, Kunde = g.First().Kunde, Sum = g.Sum(k=>k.Pris)}

Adding Count Column to LINQ query Based on Joined Table

So I have a SQL view that I've created that provides me what I need. Essentially it's a job position billeting system that shows how many positions have been authorized vs filled (or assigned).
SELECT Companies.Name AS Company, Grades.Name AS Grade, Series.Name
AS Series, Positions.Authorized, COUNT(People.PersonId) AS Assigned
FROM Companies INNER JOIN
Positions ON Companies.Id = Positions.CompanyId INNER JOIN
Series ON Positions.SeriesId = Series.Id INNER JOIN
Grades ON Positions.GradeId = Grades.Id INNER JOIN
People ON Positions.CompanyId = People.CompanyId AND
Positions.SeriesId = People.SeriesId AND Positions.GradeId = People.GradeId
GROUP BY Companies.Name, Grades.Name, Series.Name, Positions.Authorized
Now what I'd like to be able to do is recreate this in a LINQ query. I've almost got it where I need it; however, I can't figure out how to add the counted column at the end that's based on the People table.
Here's my current LINQ query:
var query = from a in db.Companies
join b in db.Positions on a.Id equals b.CompanyId
join c in db.Series on b.SeriesId equals c.Id
join d in db.Grades on b.GradeId equals d.Id
join e in db.People on new { b.CompanyId, b.SeriesId, b.GradeId } equals new { e.CompanyId, e.SeriesId, e.GradeId }
group a by new { CompanyName = a.Name, GradeName = d.Name, SeriesName = c.Name, b.Authorized, e.PersonId } into f
select new { Company = f.Key.CompanyName, Grade = f.Key.GradeName, Series = f.Key.SeriesName, f.Key.Authorized, Assigned = /* needs to be Count(People.PersonId) based on last join */ )};
Thanks in advance for any help you can provide!
Figured it out. The reason why it was posting multiple rows and not doing a proper count on the same row was because in my "group by" I added in "e.PersonId" when it should have simply been removed. I also had to add a few things to make it work on the front-end razor views since it's an anonymous type (this doesn't have anything to do with the original question, but thought I'd give reason to the changes). So the person who removed their answer, you were partially right, but the reason it wasn't working was because of the additional fieldin the group by:
dynamic query = (from a in db.Companies
join b in db.Positions on a.Id equals b.CompanyId
join c in db.Series on b.SeriesId equals c.Id
join d in db.Grades on b.GradeId equals d.Id
join e in db.People on new { b.CompanyId, b.SeriesId, b.GradeId } equals new { e.CompanyId, e.SeriesId, e.GradeId }
group a by new { CompanyName = a.Name, GradeName = d.Name, SeriesName = c.Name, b.Authorized } into f
select new { Company = f.Key.CompanyName, Grade = f.Key.GradeName, Series = f.Key.SeriesName, Authorized = f.Key.Authorized, Assigned = f.Count()}).AsEnumerable().Select(r => r.ToExpando());
And what it looks like on the page:

Convert SQL into linq to sql - group by two columns and request count of a third column

This is how the query looks in SQL:
select count(SnpId_this), DrugId, VariantId from tbl_custom_SNPs_All
join tbl_custom_SNP_Variants on VariantId = SnpsVariantId_this
join tbl_custom_SNP_Drugs_Apelon_NUIs on DrugId = SnpsDrugId_this
group by DrugId, VariantId
Here is my attempt using linq-to-sql:
var drugVariantGroups =
(from a in adminDB.tbl_custom_SNPs_Alls
join v in adminDB.tbl_custom_SNP_Variants
on a.VariantId equals v.SnpsVariantId_this
join d in adminDB.tbl_custom_SNP_Drugs_Apelon_NUIs
on a.DrugId equals d.SnpsDrugId_this
group a by new { a.VariantId, a.DrugId } into dv
select new
{
dv.Key.VariantId,
dv.Key.DrugId,
Entries = dv.Sum()
}).ToList();
looks like dv does not have a definition for sum. How do I access SnpId_this to count it?
Just use Count. You may need to filter any entries where SnpId_this is null if that is a possibility and to precisely match the T-SQL.
Entries = dv.Where(t => t.SnpId_this != null).Count()
You want Count not Sum:
var drugVariantGroups =
(from a in adminDB.tbl_custom_SNPs_Alls
join v in adminDB.tbl_custom_SNP_Variants
on a.VariantId equals v.SnpsVariantId_this
join d in adminDB.tbl_custom_SNP_Drugs_Apelon_NUIs
on a.DrugId equals d.SnpsDrugId_this
group a by new { a.VariantId, a.DrugId } into dv
select new
{
dv.Key.VariantId,
dv.Key.DrugId,
Entries = dv.Count()
}).ToList();
If you want sum you should provide the field to use in Sum function like:
dv.Sum(c=>c.Amount)

Categories

Resources