How to convert this sql query into linq query - c#

My SQL query looks like this, But when I try to convert LINQ. I can't do that.
select case when Status = 0 then 'Pending'
when Status = 1 then 'Approved'
when Status = 2 then 'Denied' else '' end Status,
count(1) totalCount
from Client_BurnOuts group by Status
Here I have an enum that contains 3 values, Pending, Approved, and Denied. SQL output is well, But I can't convert it to SQL.

Suppose, your current value is 0 which means status would be pending so the corresponding linq would be as following:
var statusCaseLinq = new List<Status>()
{
new Status(){ StatusName = "Accepted",StatusId =2},
};
var caseToLinq =
(
from n in statusCaseLinq
where n != null
select new
{
CaseId = n,
CaseSatus =
(
n.StatusId == 0 ? "Pending" :
n.StatusId == 1 ? "Accepted" :
n.StatusId == 2 ? "Denied" : "Unknown"
)
}
);
var getCaseStstusFromId = caseToLinq.FirstOrDefault().CaseSatus;
Output:

You can convert a case statement to a switch expression.
from o in Client_BurnOuts
group o by o.Status into g
select new
{
Status = g.Key switch
{
0 => "Pending",
1 => "Approved",
2 => "Denied",
_ => ""
},
totalCount = g.Count()
};

Related

Linq syntax with group by and having clauses

I try to get a list from a datatable by a linq syntax with having clause.
But I don't get what I want.
Here's the SQL syntax :
SELECT ID_BEN,
GAR1,
FIRST(FIRST_NAME) FIRST_NAME,
FIRST(LAST_NAME) LAST_NAME,
FIRST(ADR1) ADR1,
FIRST(ADR2) ADR2,
FIRST(ZIP_CODE) ZIP_CODE,
FIRST(CITY) CITY,
SUM(AMOUNT) SUM_AMOUNT,
SUM(CASE WHEN STATUS_TAB <> 'OK' THEN 1 ELSE 0 END) NUM_STATUS_TAB
FROM T_AMOUNT
WHERE STATUS_ENR = 'OK' AND STATE_ENR = '1'
GROUP BY ID_BEN, GAR1
HAVING SUM(CASE WHEN STATUS_TAB <> 'OK' THEN 1 ELSE 0 END) = 0
Here is my linq syntax :
var oLstReglementGrp = objDataSet.T_AMOUNT
.AsEnumerable()
.Select(sel => new
{
ID_BEN = sel.ID_BEN,
GAR1 = sel.GAR1,
LI_NOM = sel.First().FIRST_NAME,
LI_ADR1 = sel.First().LAST_NAME,
LI_ADR2 = sel.First().ADR1,
LI_ADR3 = sel.First().ADR2,
LI_ADR4 = sel.First().ZIP_CODE,
CD_PST = sel.First().CITY
})
.Where(x => x.STATUS_ENR == "OK"
&& x.STATE_ENR == "1")
.GroupBy(row => new { ID_BEN = (long?)row.ID_BEN, GAR1 = row.GAR1 },
(g, r) => new
{
NUM_STATUS_TAB = r.Sum(s => s.STATUS_TAB != "OK" ? 1 : 0),
SUM_AMOUNT = r.Sum(s => (decimal?)s.AMOUNT)
})
.Where(p => p.NUM_STATUS_TAB == 0)
.ToList();
Here are the SQL results :
FIRST_NAME LAST_NAME ADR1 ZIP_CODE CITY SUM_AMOUNT NUM_STATUS_TAB
Jack Palance 3 bd One 1234 New York 12000 0
John Wayne 4 ave 2 4567 Los Angeles 5500 0
Jimmy Page 5 street 2 2345 Chicago 450 0
And in my list from the linq :
SUM_AMOUNT NUM_STATUS_TAB
12000 0
5500 0
450 0
Do you have an idea ?
When writing LinQ you should no try to translate to SQL query like you would read it.
LinQ syntax is closer to SQL Execution order. In this way Linq is more "Logical".
SQL execution order is the following:
FROM and JOINs
WHERE
GROUP BY
HAVING
SELECT
objDataSet
// 1. FROM and JOINs
.T_AMOUNT
//2. WHERE
.Where(x => x.STATUS_ENR == "OK" && x.STATE_ENR == "1")
//3. GROUP BY
.GroupBy(row => new { ID_BEN = (long?)row.ID_BEN, GAR1 = row.GAR1 })
//5. SELECT
.Select(sel => new
{
ID_BEN = sel.Key.ID_BEN,
GAR1 = sel.Key.GAR1,
LI_NOM = sel.First().FIRST_NAME,
LI_ADR1 = sel.First().LAST_NAME,
LI_ADR2 = sel.First().ADR1,
LI_ADR3 = sel.First().ADR2,
LI_ADR4 = sel.First().ZIP_CODE,
CD_PST = sel.First().CITY,
NUM_STATUS_TAB = sel.Sum(s => s.STATUS_TAB != "OK" ? 1 : 0),
SUM_AMOUNT = sel.Sum(s => (decimal?)s.AMOUNT)
})
//4. HAVING
.Where(p => p.NUM_STATUS_TAB == 0)
.ToList();
Step 4 and 5 have been swap because we are filtering on a field that is not present in the groupby, so we need the select in order to have it avaidable.
At Step 3. GROUP BY, notice the overload used. Order by has 9 overload, MS Docs.
I will advice on using the simple one till you get familiar with it

Convert T-SQL statement into LINQ expression

i am quite new to linq and actually fighting to convert the following t-sql statement into an linq to sql or linq to entities expression:
SELECT TOP 1
vm.EventID,
vmm.VotingMatrixID,
PersonAcceptedCount = SUM( CAST( vmm.IsAccepted AS INT) )
FROM VotingMatrixMember vmm
JOIN VotingMatrix vm
ON vmm.VotingMatrixID = vm.ID
WHERE vm.EventID = 'abbe3077-24de-45d8-ac04-13dba97c1567'
AND vm.Deleted = 0
AND vmm.Deleted = 0
GROUP BY vm.EventID, vmm.VotingMatrixID
ORDER BY PersonAcceptedCount DESC
Try this, can not test
var firstItem = (
from vmm in db.VotingMatrixMember
join vm in db.VotingMatrix on vmm.VotingMatrixID equals vm.ID
where vm.EventID = "abbe3077-24de-45d8-ac04-13dba97c1567"
&& vm.Deleted = 0
&& vmm.Deleted = 0
group new {vm, vmm} by new {vm.EventID, vmm.VotingMatrixID} into gr
select new
{
EventID = gr.Key.EventID,
VotingMatrixID = gr.Key.VotingMatrixID,
PersonAcceptedCount = gr.Sum(x => Convert.ToInt32(x.IsAccepted))
}
into groupedItem
orderby groupedItem.PersonAcceptedCount descending
select groupedItem
).FirstOrDefault();
var query =
from vm in dataContext.VotingMatrices
where vm.EventId == eventId
where vm.Deleted == 0
from vmm in vm.VotingMatrixMembers
where vmm.Deleted == 0
group vmm by new { vm.EventId, vmm.VotingMatrixId } into g
select new
{
g.Key.EventId,
g.Key.VotingMatrixId,
PersonAcceptedCount: g.Select(x => Convert.ToInt32(x.IsAccepted)).Sum()
} into resultRow
order by resultRow.PersonAcceptedCount descending
select resultRow;
var row = query.FirstOrDefault();

Get parameters outside of Grouping Linq

I need to get some Field's out of the Group using linq for example, this is my code:
(from PaymentTypes in PaymentTypes_DataTable.AsEnumerable()
join CashTransactions in CashTransactions_DataTable.AsEnumerable()
on PaymentTypes.Field<Int32>("cashpaymenttype_id")
equals CashTransactions.Field<Int32>("cashpaymenttype_id")
into JoinedCashTransactions
from CashTransactions in JoinedCashTransactions.DefaultIfEmpty()
group CashTransactions by PaymentTypes.Field<Int32>("cashpaymenttype_id")
into GroupPaymentTypes
select new
{
cashpaymenttype_id = 0, // Get PaymentTypeID
cashpaymenttype_name = "", // Get PaymentTypeName
cashtransaction_amount = GroupPaymentTypes.Sum(a =>
a != null
? (a.Field<Int32>("cashtransactionstatus_id") == 1 ||
a.Field<Int32>("cashtransactionstatus_id") == 3 ? 1 : -1) *
a.Field<Double>("cashtransaction_amount")
: 0.00),
}).Aggregate(PaymentTypesTransactions_DataTable, (dt, result) => {
dt.Rows.Add(result.cashpaymenttype_id, result.cashpaymenttype_name,
result.cashtransaction_amount); return dt; });
This linq works but i need to get the fields cashpaymenttype_id and cashpaymenttype_name they are within PaymentTypes
Assuming PaymentTypeID - PaymentTypeName is 1-to-1, you could change your group by to this:
group CashTransactions by new
{
PaymentTypeId = PaymentTypes.Field<Int32>("cashpaymenttype_id"),
PaymentTypeName = PaymentTypes.Field<String>("cashpaymenttype_name")
}
into GroupPaymentTypes
The your select will look like this:
select new
{
cashpaymenttype_id = GroupPaymentTypes.Key.PaymentTypeId,
cashpaymenttype_name = GroupPaymentTypes.Key.PaymentTypeName,
...
}

Convert T-SQL to LINQ using the WHERE IN clause with a Nested Subquery

How would the following T-SQL query be written in LINQ using the WHERE IN clause and a subquery:
SELECT a.IncidentID,
a.OccurWhen,
a.OccurWhere,
a.Description
FROM buIncidentDetail a
WHERE a.IncidentID IN (SELECT IncidentID
FROM buPerson
WHERE IsDeleted = 0
AND (NameFirst LIKE '%%'
OR NameLast LIKE '%%')
)
OR a.IncidentID IN (SELECT IncidentID
FROM buInjury
WHERE IsDeleted = 0
AND (TimeLossEstimateTerms LIKE '%%'
OR ResultOtherDesc LIKE '%%')
)
Before marking this as a possible duplicate, all the other examples I found were using an array, i.e. – (“1”, “2”, “3”). I’m looking for one that specifically demonstrates the use of a subquery.
You turn the queries inside out and start with the inner queries first, and then applying the result of those to the outer query.
int? incidentID;
var person = buPerson.Where(
p => p.IsDeleted == 0
&& (!string.NullOrWhitespace(p.NameFirst)
|| !string.NullOrWhitespace(p.NameLast)).FirstOrDefault();
if ( person != null )
incidentID = person.IncidentID;
else {
var incident = buInjury.Where(
i => i.IsDeleted == 0
&& (!string.NullOrWhitespace(i.TimeLossEstimateTerms)
|| !string.NullOrWhitespace(i.ResultOtherDesc)).FirstOrDefault();
if ( incident != null )
incidentID = incident.IncidentID;
}
if ( incidentID.HasValue() )
{
var detail = buIncident
.FirstOrDefault(j=>j.IncidentID.Value)
.Select(j => new { k => new {
ID = k.IncidentID,
When = g.OccurWhen,
Where = g.OccurWhere,
Description = g.Description };
if ( detail != null )
Console.WriteLine( "{0}, {1}, {2}, {3}",
detail.IncidentID,
detail.OccurWhen,
detail.OccurWhere,
detail.Description);
}
else
Console.WriteLine("No incident found");

Converting SQL Rank() to LINQ, or alternative

I have the below SQL statement that works as desired/expected. However I would like to translate it into a LINQ statement(Lambda??) so that it will fit with the rest of my DAL. However I cannot see to figure out how to simulate Rank() in LINQ.
The reason I posted it here, which is maybe in error, is to see if anyone has an alternative to the Rank() statement so that I can get this switched over. Alternatively, if there is a way to represent Rank() in LINQ that would be appreciated also.
USE CMO
SELECT vp.[PersonID] AS [PersonId]
,ce.[EnrollmentID]
,vp.[FirstName]
,vp.[LastName]
,ce.[EnrollmentDate]
,ce.[DisenrollmentDate]
,wh.WorkerCategory
FROM [dbo].[vwPersonInfo] AS vp
INNER JOIN
(
[dbo].[tblCMOEnrollment] AS ce
LEFT OUTER JOIN
(
SELECT *
,RANK()OVER(PARTITION BY EnrollmentID ORDER BY CASE WHEN EndDate IS NULL THEN 1 ELSE 2 END, EndDate DESC, StartDate DESC) AS whrank
FROM [dbo].[tblWorkerHistory]
WHERE WorkerCategory = 2
) AS wh
ON ce.[EnrollmentID] = wh.[EnrollmentID] AND wh.whrank = 1
)
ON vp.[PersonID] = ce.[ClientID]
WHERE (vp.LastName NOT IN ('Client','Orientation','Real','Training','Matrix','Second','Not'))
AND (
(wh.[EndDate] <= GETDATE())
OR wh.WorkerCategory IS NULL
)
AND (
(ce.[DisenrollmentDate] IS NULL)
OR (ce.[DisenrollmentDate] >= GetDate())
)
Here's a sample that shows how I would simulate Rank() in Linq:
var items = new[]
{
new { Name = "1", Value = 2 },
new { Name = "2", Value = 2 },
new { Name = "3", Value = 1 },
new { Name = "4", Value = 1 },
new { Name = "5", Value = 3 },
new { Name = "6", Value = 3 },
new { Name = "7", Value = 4 },
};
var q = from s in items
orderby s.Value descending
select new
{
Name = s.Name,
Value = s.Value,
Rank = (from o in items
where o.Value > s.Value
select o).Count() + 1
};
foreach(var item in q)
{
Console.WriteLine($"Name: {item.Name} Value: {item.Value} Rank: {item.Rank}");
}
OUTPUT
Name: 7 Value: 4 Rank: 1
Name: 5 Value: 3 Rank: 2
Name: 6 Value: 3 Rank: 2
Name: 1 Value: 2 Rank: 4
Name: 2 Value: 2 Rank: 4
Name: 3 Value: 1 Rank: 6
Name: 4 Value: 1 Rank: 6
LINQ has rank funcionality built in, but not in the query syntax. When using the method syntax most linq functions come in two versions - the normal one and one with a rank supplied.
A simple example selecting only every other student and then adding the index in the resulting sequence to the result:
var q = class.student.OrderBy(s => s.studentId).Where((s, i) => i % 2 == 0)
.Select((s,i) => new
{
Name = s.Name,
Rank = i
}
If you want to simulate rank then you can use following linq query.
var q = (from s in class.student
select new
{
Name = s.Name,
Rank = (from o in class.student
where o.Mark > s.Mark && o.studentId == s.studentId
select o.Mark).Distinct().Count() + 1
}).ToList();
you can use order by like:
var q = (from s in class.student
orderby s.studentId
select new
{
Name = s.Name,
Rank = (from o in class.student
where o.Mark > s.Mark && o.studentId == s.studentId
select o.Mark).Distinct().Count() + 1
}).ToList();
but order by does not matter in this query.
Based on answer from #Totero but with a lamda implementation.
Higher score = higher rank.
var rankedData = data.Select(s => new{
Ranking = data.Count(x => x.Value > s.Value)+1,
Name = s.Key,
Score = s.Value});
For this input:
{ 100, 100, 98, 97, 97, 97, 91, 50 }
You will get this output:
Score : Rank
100 : 1
100 : 1
98 : 3
97 : 4
97 : 4
97 : 4
91 : 6
50 : 7

Categories