Get additional attributes from group key - c#

I have another problem with LINQ, So what I'm trying to do is create a list of best salesman. My table of sold_items, looks like this
[ID]
[Name]
[Price]
[Sold_date]
[Salesman_ID]
and the table of Salesmans
[ID]
[Login]
[First_name]
[Surname]
I want to sum all the prices, that each individual salesman sold and also have an option to group it by date for example, the best of this month, or this week
var query1 = from s in context.Archive
//join us in context.Users
//on s.Salesman.ID equals us.ID
group s by s.Salesman.ID
into g
orderby g.Sum(o => o.Price) descending
select new
{
Salesman_ID = g.Key,
Sale = g.Sum(o => o.Price),
};
that works fine, but I only get salesman_ID, how to add User First_name and Surname from Salesmans table?

You could do something like this:
var query1 =
from s in context.Archive
group s by s.Salesman into g
orderby g.Sum(o => o.Price) descending
select new
{
Salesman_ID = g.Key.ID,
Salesman_First_name = g.Key.First_name,
Salesman_Surname = g.Key.Surname,
Sale = g.Sum(o => o.Price),
};
And to limit it my a specific date, use something like this:
var query1 =
from s in context.Archive
where s.Sold_date >= minDate && s.Sold_date <= maxDate
group s by s.Salesman into g
orderby g.Sum(o => o.Price) descending
select new
{
Salesman_ID = g.Key.ID,
Salesman_First_name = g.Key.First_name,
Salesman_Surname = g.Key.Surname,
Sale = g.Sum(o => o.Price),
};

You can group by multiple columns (all the columns you want to retrieve)
var query1 = from s in context.Archive
//join us in context.Users
//on s.Salesman.ID equals us.ID
group s by new // group by multiple columns
{
s.Salesman.Id,
s.first_name,
s.surname,
} into g
orderby g.Sum(o => o.Price) descending
select new
{
Salesman_ID = g.Key,
FirstName = g.first_name,
Surname = g.surname,
Sale = g.Sum(o => o.Price),
};

Change the current Line to this.
select new { Salesman_ID = g.Key, Salesman_First_Name = g.Key.First_name };

Related

Matrix output in ASP.NET MVC LINQ

I have 3 simple tables
tblQual (ID, QualName)
tblPerson (ID, PersonName)
tblPersonQual (ID, PersonID, QualID, ExpiryDate)
I would like to display a matrix with PersonName down the left, QualName at the top and ExpiryDate in the middle. How do I go about doing this?
I've tried this but no joy.
var QualMatrix = from c in db.tblPersonQual
join q in db.tblQual on c.QualID equals q.ID
join p in db.tblPerson on c.PersonID equals p.ID
group c by c.ID into g
select new
{
rowKey = g.Key,
rowData = g.Select(c => new { Qual = q.QualName, Expiry = c.Expiry })
};
In terms of output view something similar to this
As my understanding, you want to display a matrix with QualName, ExpiryDate and QualName. We can use the same query by just modifying group by clause.
var QualMatrix = from c in db.tblPersonQual
join q in db.tblQual on c.QualID equals q.ID
join p in db.tblPerson on c.PersonID equals p.ID
group new { q.QualName,p.PersonName} by new { c.ID,c.ExpiryDate } into g
select new
{
QualName=g.Select(e=>e.QualName).FirstOrDefault(),
ExpirtyDate=g.Key.Expiry,
PersonName=g.Select(e=>e.PersonName).FirstOrDefault(),
};
Hopefully, This will fulfil your requirement.

LINQ Query with GroupBy, MAX and Count

What could be the LINQ query for this SQL?
SELECT PartId, BSId,
COUNT(PartId), MAX(EffectiveDateUtc)
FROM PartCostConfig (NOLOCK)
GROUP BY PartId, BSId
HAVING COUNT(PartId) > 1
I am actually grouping by two columns and trying to retrieve max EffectiveDateUtc for each part.
This is what I could write. Stuck up on pulling the top record based on the date.
Also not sure, if this is a optimal one.
//Get all the parts which have more than ONE active record with the pat
//effective date and for the same BSId
var filters = (from p in configs
?.GroupBy(w => new
{
w.PartId,
w.BSId
})
?.Select(g => new
{
PartId = g.Key.PartId,
BSId = g.Key.BSId,
Count = g.Count()
})
?.Where(y => y.Count > 1)
select p)
?.Distinct()?.ToList();
var filteredData = (from p in configs
join f in filters on p.PartId equals f.PartId
select new Config
{
Id = p.Id,
PartId = p.PartId,
BSId = p.BSId,
//EffectiveDateUtc = MAX(??)
}).OrderByDescending(x => x.EffectiveDateUtc).GroupBy(g => new { g.PartId, g.BSId }).ToList();
NOTE: I need the top record (based on date) for each part. Was trying to see if I can avoid for loop.
The equivalent query would be:
var query =
from p in db.PartCostConfig
group p by new { p.PartId, p.BSId } into g
let count = g.Count()
where count > 1
select new
{
g.Key.PartId,
g.Key.BSId,
Count = count,
EffectiveDate = g.Max(x => x.EffectiveDateUtc),
};
If I understand well, you are trying to achieve something like this:
var query=configs.GroupBy(w => new{ w.PartId, w.BSId})
.Where(g=>g.Count()>1)
.Select(g=>new
{
g.Key.PartId,
g.Key.BSId,
Count = g.Count(),
EffectiveDate = g.Max(x => x.EffectiveDateUtc)
});

Convert SQL(Row_Number) Query into Linq in MVC?

How to convert below SQL Query to Linq expression in C#(MVC)?
with cte
as
(
select *,rank() over(partition by LineClass order by LineClassId) as rownum
from MT_LineClass where ProjectId =1
)
select * from cte where rownum=1
var res = from tbl in MT_LineClass
group tbl.lineclassid by tbl.lineclass into g
select new { LineClass = g.Key, LineClassIds = g.ToList() };
You can use other than ToList operations to get the id (eq First, Max etc)
var lst = (from t in context.MT_LineClass
where t.ProjectId == projId
group t by t.LineClass into g
select new Mt_Lineclass
{
lineId = g.Select(t => t.LineClassId).FirstOrDefault(),
Lineclass = g.Select(t => t.LineClass).FirstOrDefault()
}).ToList();

SQL to LINQ convertion

I need help producing the required C# code to implement the following SQL query. I am unsure if this is even possible?
select p.Name, r.Id, r.Status, r.Created, r.DepartmentId
from (select r.*, row_number() over (partition by personid order by created desc) as seqnum
from checkin r
where r.departmentid = '7AF20674-AEC1-4D4C-B1EA-88B1D7E8F3DB' and cast(created as date) = '2013-02-11'
) r join
person p
on r.personid = p.id
where seqnum = 1
order by p.name desc
Before i used to only have one registration per day per person, so the following was possible. Now i can have several registrations per person per day, thats why SQL has been updated.
var query = from b in context.Persons
join c in context.CheckIns
on b.Id equals c.PersonId into JoinedPersCheck
from c in JoinedPersCheck.Where(i => i.Date.Equals(date)).DefaultIfEmpty()
where b.DepartmentId.Equals(departmentId)
orderby b.Name
select new Model.PersonCheckIn
{
CheckIn = MapToCheckInModel(c),
Person = MapToModel(b),
};
return query;
Try this:
var query = context.CheckIns
.Where(p => p.DepartmentId == departmentId && p.Created.Date == date)
.GroupBy(r => r.PersonId)
.Select(g => g.OrderByDescending(p => p.Created).First())
.Join(context.Persons, c => c.PersonId, p => p.Id,
(c,p) => new { p.Name, c.Id, c.Status, c.Created, c.DepartmentId})
.OrderByDescending(f => f.Name);

How can I filter results of one LINQ query based on another?

Given the following:
DP_DatabaseTableAdapters.EmployeeTableAdapter employeetableAdapter = new DP_DatabaseTableAdapters.EmployeeTableAdapter();
DP_Database.EmployeeDataTable employeeTable = employeetableAdapter.GetData();
var leadEmployees = from e in employeeTable
where e.IsLead == true
select e;
DP_DatabaseTableAdapters.LaborTicketTableAdapter tableAdapter = new DP_DatabaseTableAdapters.LaborTicketTableAdapter();
DP_Database.LaborTicketDataTable table = tableAdapter.GetDataByDate(date.ToString("MM/dd/yyyy"));
var totHours = from l in table
join e in leadEmployees on l.EmployeeID equals e.EmployeeID
group l by l.EmployeeID into g
orderby g.Key
select new
{
EmployeeID = g.Key,
HoursWorked = g.Sum(s => s.HoursWorked)
};
Total hours correctly filters the results based on the leadEmployee's list of people who have the IsLead bit set to true.
I would like to know how to do this with a where clause, I have attempd to use leadEmployees.Contanis but it wants a whole EmployeeRow...
How can I add what looks to be part of an IN clause to a where filter to replace the join?
var totHours = from l in table
where ??????
group l by l.EmployeeID into g
orderby g.Key
select new
{
EmployeeID = g.Key,
HoursWorked = g.Sum(s => s.HoursWorked)
};
The contains will only want a whole EmployeeRow if you are selecting whole employee roles. You can either:
leadEmployees.Select(e => e.id).contains
OR
leadEmployees.Count(e => e.id == l.id) > 0
Both will work. (Excuse slightly rushed lack of consideration for syntax accuracies).
This should work:
var leadEmployees = from e in employeeTable
where e.IsLead == true
select e.EmployeeID;
var totHours = from l in table
where leadEmployees.Contains(l.EmployeeID)
group l by l.EmployeeID into g
orderby g.Key
select new
{
EmployeeID = g.Key,
HoursWorked = g.Sum(s => s.HoursWorked)
};

Categories

Resources