How to select columns after group by in entitiy frame - sql

I am trying to select multiple columns after groupby operation in EF.
Here is what I want to do:
this._context.dbtablename
.Select(u => new { u.name, u.age, u.grade })
.GroupBy(x => x.grade)
.Select(g => new { name = g.?, age = g.??, grade = u.key, Count = g.Count() })
Example:
name age grade
A 12 8
B 12 9
C 11 10
D 11 9
I want to have:
name age grade
A 12 8
B 12 9 ----> "name" is B or D, "age" is "12" or "11", does not matter.
C 11 10
Can I achieve it?

each grouped item has a key and collection so you can use first() or firstordefault() to get first item in each group
this._context.dbtablename
.Select(u => new { u.name, u.age, u.grade })
.GroupBy(a => a.grade)
.Select(a => new { name = a.First().name, age = a.First().age, grade = a.Key, count = a.Count() });
or min() or max()
.Select(a => new { name = a.Min(b => b.name), age = a.Min(b => b.age), grade = a.Key, count = a.Count() });

Following returns number of valid orders (where clause) in periods (YearMonth YYYYMM):
GM_ORDER.AsQueryable()
.Where(s => s.STATUS > -1)
.Select(s => new { DateOfOrder = s.CREATEDON.Date, s.ORDERID })
.GroupBy(g => g.DateOfOrder.Year*100 + g.DateOfOrder.Month )
.OrderByDescending(o=>o.Key)
.Select(g => new { Period = g.Key, NrOfOrders = g.Count()} )
Output is:
Period NrOfOrders
201705 13
201704 34
201703 42
201702 17
201701 17
201612 25
201611 34
201610 54
201609 135
201608 163
201607 110
201606 169
201605 100
201604 56
201603 19
201602 8
201601 6
Hope this helps.
Edited:
If you like to see more columns from the grouping following will help. To sort, you need to take it into a list variable and then sort the list variable in itself.
GM_ORDER.AsQueryable()
.Where(s => s.STATUS > -1)
.Select(s => new { DateOfOrder = s.CREATEDON.Date, s.ORDERID, s.STATUS })
.GroupBy(g => new { YYYYMM = g.DateOfOrder.Year * 100 + g.DateOfOrder.Month, g.STATUS })
.Select(g => new { Period = g.Key.YYYYMM, Status = g.Key.STATUS, NrOfOrders = g.Count() })
.ToList()

Related

How to translate what I do with the [Confirmed / Total] field in this query to lambda? with CAST

I'm trying to get all the users that have confirmed an Event and the following query shows how it should look
select us.ServiceId, s.Image, s.Title, s.CreatedTimestamp, (cast(count(us.Answer) as varchar(10))) +
'/' + (cast((select count(Id) from Users) as varchar(10))) [Confirmed / Total]
from Services s inner join UserServices us on s.Id = us.ServiceId
where us.ServiceId = '5cf37da7-e7ba-4652-8526-96b3ad19fd13'
group by us.ServiceId, s.Image, s.Title, s.CreatedTimestamp
The result:
but I can only get users who have been confirmed, I want to get users total too.
I did a lambda with the most fields, except the users total:
Services.Join(UserServices, s => s.Id, us => us.ServiceId, (s, us) => new { s,us })
.Where(w => (w.us.ServiceId == "5cf37da7-e7ba-4652-8526-96b3ad19fd13"))
.GroupBy(gb => new
{
ServiceId = gb.us.ServiceId,
Image = gb.s.Image,
Title = gb.s.Title,
CreatedTimestamp = gb.s.CreatedTimestamp,
ConfirmedTotal = gb.us.Answer
}, gb => new { us = gb.us, s = gb.s })
.Select(sl => new
{
ServiceId = sl.Key.ServiceId,
Image = sl.Key.Image,
Title = sl.Key.Title,
CreatedTimestamp = sl.Key.CreatedTimestamp,
ConfirmedTotal = sl.Count(x => x.us.Answer)
})
The result:
So, how to translate that or is there some way to do that?
I tried this and it worked:
Services.Join(UserServices, s => s.Id, us => us.ServiceId, (s, us) => new { s,us })
.Where(w => (w.s.ServiceTypeId == "efb6fd56-45be-4402-a960-ed93bcbeea79"))
.GroupBy(gb => new
{
ServiceTypeId = gb.us.ServiceId,
Image = gb.s.Image,
Title = gb.s.Title,
CreatedTimestamp = gb.s.CreatedTimestamp,
ConfirmedTotal = string.Concat(gb.us.Answer.ToString(), " / ", db.Users.Select(s => s.Id).Count().ToString())
})
.Select(s => new
{
ServiceId = s.Key.ServiceTypeId,
Image = s.Key.Image,
Title = s.Key.Title,
CreatedTimestamp = s.Key.CreatedTimestamp,
ConfirmedTotal = string.Concat(s.Count(x => x.us.Answer).ToString(), " / ", db.Users.Select(s2 => s2.Id).Count().ToString())
})

SQL with max(date) to LINQ

I have tried to make the following sql in linq with no luck can some help mw with this?
select * from customer c
where companynumber = 1
and status <> 0
and lastdate = (select max(lastdate) from customer where customernumber = c.customernumber)
Gives 22 records
My best try was this:
_ctx.Customers
.Where(r => r.CompanyNumber == companyNumber && r.CustomerNumber != null && r.Status != 0)
.GroupBy(c => c.CustomerNumber)
.Select(g => new
{
name = g.Key,
count = g.Count(),
date = g.Max(x => x.LastEdited)
})
.OrderBy(c => c.name);
Gives 22.000+ records
But not the result as the above SQL
UPDATE:
The following LINQ does the trick ;o)
from a in _ctx.Customers
where a.CustomerNumber != null && a.CompanyNumber == companyNumber
group a by new { a.CustomerNumber } into g
select g.OrderByDescending(a => a.LastEdited).FirstOrDefault() into c
where c.Status == 1
select c
I had to move the where c.Status == 1 into my first select statment

How can I convert a SQL script into Linq

I do have a sql script that I can't translate into linq. May one of you can help me out to get the right direction.
My big problems are the count and the group by:
SELECT
wfs.ServerId,
COUNT(wfss.Name) AS Records,
wfs.DiskId
FROM WorkflowStep wfs
INNER JOIN WorkflowStepStatus wfss ON wfs.WorkflowStepStatusId = wfss.Id
WHERE wfs.WorkflowId = (
SELECT
Id
FROM Workflow wf
WHERE wf.Name = 'Collecting data virutal'
)
AND wfs.StepNumber IN (1, 2, 3)
AND wfss.Name = 'Processed'
GROUP BY wfs.ServerId,
wfss.Name,
wfs.DiskId
this should work
var result = wfs.Join(wfss,
t => t.WorkflowStepStatusId,
u => u.ID,
(t, u) => new {
t.ServerID,
t.WorkflowId,
t.StepNumber,
u.Name,
t.DiskID
})
.Where(t => t.WorkflowId == wf.FirstOrDefault(u => u.Name == "Collecting data virutal").ID &&
t.Name == "Processed" &&
new List<int> { 1, 2, 3 }.ToArray().Contains(t.StepNumber))
.GroupBy(t => new { t.ServerID, t.Name, t.DiskID })
.Select(t => new {
t.Key.ServerID,
Records = t.Key.Name.Count(),
t.Key.DiskID
})
.ToList();

C# + LINQ - inner join

Table: one
Column (PK): employee_ssn
Column: employee_active bit
Table: two
Column (pk): date
Column (FK): employee_ssn
Column: total_income
Column: total_expenses
Working Linq code to sum total_income and total_expenses for the year, per employee:
var SumOfSections = db.two
.Select(x => x)
.Where(x => x.employee_ssn.Equals(xxxxxxxxx))
.Where(x => x.Date.Year.Equals(year))
.GroupBy(x => x.Date)
.Select(g => new
{
Total_Income = g.Sum(x => x.total_expenses),
Total_Expenses= g.Sum(x => x.total_income)
})
.ToArray();
I need to incorporate INNER JOIN to the above to only include active employees. Working SQL:
select two.total_income,total_expenses
from two
INNER JOIN one
ON one.SSN = two.SSN
WHERE one.Active = 1 AND two.Date='1/1/2014' AND two.SSN='xxxxxxxxx';
How can I modify my linq code to what my sql code is doing?
var SumOfSections = (from t in db.two
join o in db.one on t.employee_ssn equald o.employee_ssn
where t.employee_ssn = "xxxxxxxxx" && o.employee_active == true
group t by t.date into g
select new {
Total_Income = g.Sum(x => x.total_expenses),
Total_Expenses= g.Sum(x => x.total_income)
}).ToArray();
I used query syntax because it seems to be more readable.
You can also continue with the notation you are using:
var SumOfSections = db.two.Join(db.one, o=>o.employee_ssn, t=>t.employee_ssn, (o,t)=>new {One = o, Two = t)
.Select(x => x)
.Where(x => x.Two.employee_ssn.Equals(""))
.Where(x => x.Two.date.Year.Equals(1234))
.Where(x=> x.One.employee_active == true)
.GroupBy(x => x.Two.date)
.Select(g => new
{
Total_Income = g.Sum(x => x.Two.total_expenses),
Total_Expenses = g.Sum(x => x.Two.total_income)
})
.ToArray();

How to use the group join result to join another tables using LINQ?

I am not able to use the result of group join and then further applying the join with other tables.
My SQL query is :
SELECT *
FROM
[dummy_database].[dbo].[MA] M
INNER JOIN
SN.dbo.A A ON A.ApplicantMAId = M.MAId
INNER JOIN
SN.dbo.SP SP ON SP.PropertyMAId = M.MAId
INNER JOIN
SN.dbo.MCC CC ON CC.MAId = m.MAId
INNER JOIN
SN.dbo.MLSTN T ON T.MAT_ID = M.MAId
INNER JOIN
(SELECT
MAX(MAT_DATE) AS MaxDate,
MAT_ID
FROM
[SN].[dbo].[MLSTN]
GROUP BY
MAT_ID) Q ON Q.MAT_ID = M.MAId
and what I have done so far is:
var q = (from ml in context.MLSTN
group ml by ml.MAT_ID into g
let maxdate = g.Max(date => date.MAT_DATE)
select new
{
MortgId = g.Key,
TrackingDate = g.FirstOrDefault(val => val.MAT_DATE == maxdate).MAT_DATE
}
);
but now this result is not at all further used by me to create a join with other tables. I want to ask how to join further? Any clue?
You need something like this:
var groups = context.MLSTN
.GroupBy(x => x.MAT_ID)
.Select(g => new
{
MAT_ID = g.Key,
MaxDate = g.Max(date => date.MT_DATE)
});
var result = context.MA
.Join(context.A,
m => m.MA_ID,
a => a.MA_ID,
(m, a) => new
{
MA = m,
A = a
})
.Join(context.SP,
x => x.MA.MAId,
sp => sp.PropertyMAId,
(x, sp) => new
{
MA = x.MA ,
A = x.A,
SP = sp
})
.Join(context.MCC,
x => x.MA.MAId,
cc => cc.MAId,
(x, cc) => new
{
MA = x.MA ,
A = x.A,
SP = x.SP,
MCC = cc
})
.Join(context.MLSTN,
x => x.MA.MAId,
t => t.MAT_ID,
(x, t) => new
{
MA = x.MA ,
A = x.A,
SP = x.SP,
MCC = x.MCC,
MLSTN = t
})
.Join(groups,
x => x.MA.MAId,
g => g.MAId,
(x, g) => new
{
MA = x.MA ,
A = x.A,
SP = x.SP,
MCC = x.MCC,
MLSTN = t,
MLSG = g
});