Convert SQL Server query to Entity Framework query - sql

I have a SQL Server query like this:
select
month(fact_date) as month,
sum(case when beef_dairy_stat = 1 and param_id = 1 then 1 else 0 end) as cnt
from
user_behave_fact
where
YEAR(fact_date) = 2018
group by
month(fact_date)
order by
month
with a result of
month cnt
------------
1 10
2 20
Now I need to convert this query to its corresponding Entity Framework query.
This is my current attempt:
var sql_rez_ICC = new List<Tuple<int, int>>();
sql_rez_ICC = db.user_behave_fact
.Where(x => x.fact_date.Value.Year == selected_year)
.GroupBy(y => y.fact_date.Value.Month)
.Select(y =>new { month = y.Select(x=>x.fact_date.Value.Month), icc_count = y.Count(x => x.beef_dairy_stat == true && x.param_id == 1) })
.AsEnumerable()
.Select(y => new Tuple<int, int>(y.month, y.icc_count))
.ToList();
However on second .Select, I get an error on month which is
Cannot convert from System.Collection.Generic.IEnumrable to int

y.Select(x=>x.fact_date.Value.Month) returns an IEnumerable<int>. Use y.Key instead.

Related

I have a SQL query and I want to convert it to linq

I have a SQL query which I want to convert to Linq.
This is my SQL query:
SELECT
Calisanlar.CalisanId,
CovidYakalanmaTarih,
CovidBitisTarih
FROM
Calisanlar
INNER JOIN
Covids ON Calisanlar.CalisanId = Covids.CalisanId
WHERE
Calisanlar.CalisanId IN (SELECT TOP 10 CalisanId
FROM Hastaliklar
GROUP BY CalisanId
ORDER BY COUNT(*) DESC)
AND DATEDIFF(DAY, CovidYakalanmaTarih, GETDATE()) BETWEEN 0 AND 30
I wrote this C# code, but it doesn't work as expected because i didn't write "DATEDIFF(DAY, CovidYakalanmaTarih, GETDATE()) BETWEEN 0 AND 30" linq version:
var query = context.Hastaliklar
.GroupBy(x => x.CalisanId)
.OrderByDescending(grp => grp.Count())
.Select(grp => grp.Key)
.Take(10)
.ToList();
var result = from hastalik in context.Hastaliklar
join covid in context.Covids
on hastalik.CalisanId equals covid.CalisanId
where query.Contains(hastalik.CalisanId)
&& EF.Functions.DateDiffDay(covid.CovidYakalanmaTarih, covid.CovidBitisTarih)
select new SonBirAyCovidDto
{
CalisanId = covid.CalisanId,
CovidYakalanmaTarih = covid.CovidYakalanmaTarih,
CovidBitisTarih = covid.CovidBitisTarih
};
There is not direct translation to BETWEEN in EF Core, but you can make other condition. Also it is better to remove ToList() from first query, in this case you will have only one roundtrip to database.
var query = context.Hastaliklar
.GroupBy(x => x.CalisanId)
.OrderByDescending(grp => grp.Count())
.Select(grp => grp.Key)
.Take(10);
var result =
from hastalik in context.Hastaliklar
join covid in context.Covids
on hastalik.CalisanId equals covid.CalisanId
where query.Contains(hastalik.CalisanId)
&& covid.CovidYakalanmaTarih <= covid.CovidBitisTarih
&& EF.Functions.DateDiffDay(covid.CovidYakalanmaTarih, covid.CovidBitisTarih) <= 30
select new SonBirAyCovidDto
{
CalisanId = covid.CalisanId,
CovidYakalanmaTarih = covid.CovidYakalanmaTarih,
CovidBitisTarih = covid.CovidBitisTarih
};

Counting total of records by year

I want to count the amount of records by year, for each year. These records contain a datecreated field. But the count should include the previous years as well. So counting the years of 2013 should, include those lower years as well, but not yet of 2014 and higher.
Explanation preferably in linq.
(sql is totally fine though)
I tried doing this by grouping by year, and then count for each year. Now only the previous years should be added, for each year.
I know this can be done with a lot where statements and selecting the results, but there should be a better way.
In SQL you need SUM OVER but it is not supported by Linq. You can download yearly data and calculate the cumulative sums in memory.
var fromYear = 2010;
var toYear = 2019;
var yearlyData = Receipts.Where(x => x.DateCreated.Year >= fromYear & x.DateCreated.Year <= toYear)
.GroupBy(x => x.DateCreated.Year)
.Select(x => new { Year = x.Key, Count = x.Count() })
.ToList();
var result = Enumerable.Range(fromYear, toYear - fromYear)
.Select(year => new
{
Year = year,
CumulativeCount = yearlyData.Where(y => y.Year <= year).Sum(y => y.Count)
});
Also you can use an outer variable:
var fromYear = 2010;
var toYear = 2019;
var yearlyData = Receipts.Where(x => x.DateCreated.Year >= fromYear & x.DateCreated.Year <= toYear)
.GroupBy(x => x.DateCreated.Year)
.Select(x => new { Year = x.Key, Count = x.Count() })
.OrderBy(x => x.Year)
.ToList()
;
var sum = 0;
var result = yearlyData.Select(x => new {x.Year, CumulativeSum = sum += x.Count});
select sum(case when year(datecreated) <= 2013 then 1 else 0 end) as until_2013,
sum(case when year(datecreated) <= 2014 then 1 else 0 end) as until_2014,
sum(case when year(datecreated) <= 2015 then 1 else 0 end) as until_2015
from your_table
Here's your query.
select count(1), year(created_date) from tableA
where year(created_date) < 2014
group by year(created_date)

SQL to Linq group by count

I have a single column in a table to count specific rows. The sql query is as below:
SELECT
CASE
WHEN trail LIKE 'ClassA%' THEN 'ClassA'
WHEN trail LIKE 'ClassB%' THEN 'ClassB'
WHEN trail LIKE 'SemA%' THEN 'SemesterA'
WHEN trail LIKE 'SemB%' THEN 'SemesterB'
END AS Logs
, COUNT(*) AS Count
FROM Logs where s_date >= 'from date from UI' and e_date <= 'to date from ui'
GROUP BY
CASE
WHEN trail LIKE 'ClassA%' THEN 'ClassA'
WHEN trail LIKE 'ClassB%' THEN 'ClassB'
WHEN trail LIKE 'SemA%' THEN 'SemesterA'
WHEN trail LIKE 'SemB%' THEN 'SemesterB'
END
The above query result in sql fine as
ClassA 20
ClassB 5
SemesterA 2
SemesterB 50
Now, I need to change this sql to Linq with a date filter (from date, to date).
Please suggest change in query to simplyfy it.
Thanks
Tried:-
var data = _db.Logs.Where(p => p.trail.StartsWith("ClassA") && (p.SDate.Date >= CDate.Date && p.SDate.Date <= FDate.Date)).GroupBy(p => p.trail.StartsWith("ClassA")).Select(s =>
new
{
source = "Class - A total",
percentage = s.Count()
}).Union(_db.Logs.Where(p => p.trail.StartsWith("ClassB") && (p.SDate.Date >= CDate.Date && p.SDate.Date <= FDate.Date)).GroupBy(p => p.trail.StartsWith("ClassB")).Select(s =>
new
{
source = "Class - B total",
percentage = s.Count()
}).Union(_db.Logs.Where(p => p.trail.StartsWith("SemesterA") && (p.SDate.Date >= CDate.Date && p.SDate.Date <= FDate.Date)).GroupBy(p => p.trail.StartsWith("SemesterA")).Select(s =>
new
{
source = "Semester - A total",
percentage = s.Count()
}).Union(_db.Logs.Where(p => p.trail.StartsWith("SemesterB") && (p.SDate.Date >= CDate.Date && p.SDate.Date <= FDate.Date)).GroupBy(p => p.trail.StartsWith("SemesterB")).Select(s =>
new
{
source = "Semester - B total",
percentage = s.Count()
})))).ToList();
Try storing all the interesting starting keys in an enumerable of some sort and then using the built in group by method overload which outputs a result mapped from the key,group pairs (c.f. https://msdn.microsoft.com/en-us/library/vstudio/bb549393(v=vs.100).aspx)
string[] startingKeys = new string[] {"ClassA","ClassB","SemsterA","SemesterB"};
var data =_db.Logs.Where(p=>(p.SDate.Date >= CDate.Date && p.SDate.Date <= FDate.Date)&&startingKeys.Any(k=>p.Logs.StartsWith(k))).GroupBy(p=>startingKeys.Where(k=>p.Logs.StartsWith(k)).First(),(key,items)=>new {source=key,count = items.Count()})
One advantage of this method is you can change the starting keys at runtime if you feel like it.

Linq union all equivalent of sql code

I have the following queries:
var majorClients = maj in dbContext.MajorClients
where (maj.startdate > startDate)
where (maj.status == "Active")
Select new Client{EntityPK = maj.mjPrimaryKey,Name = maj.name, Type = "Maj"};
var minorClients = min in dbContext.MinorClients
where (min.startdate > startDate)
where (min.status == "Active" || min.status== "Inactive")
Select new Client{EntityPK = min.mnPrimaryKey,Name = min.name, Type = "Min"};
There are clients that could appear in both major and minor tables. I would like to return a list of all occurrences of clients in both tables, however if there are matching clients by name, then I would only want to return the matching record from the majorClients table.
I have written a sql query to return the results:
SELECT mjPrimaryKey AS EntityPK,name,'Maj' AS TYPE
FROM majorClients
WHERE status = 'Active' AND startDate > #startDate
UNION ALL
SELECT mnPrimaryKey,name,'Min' FROM minorClients
WHERE status IN ('Active','Inactive') AND startDate > #startDate
WHERE name NOT IN (SELECT name FROM majorClients WHERE status = 'Active' AND startDate > #startDate)
How would I represent this query in linq?
Try this linq. To exclude duplicates from minorClients, I've used Contains method. To union all objects - Union method:
var majorClients = from maj in dbContext.MajorClients
where maj.startdate > startDate
&& maj.status == "Active"
select new Client
{
EntityPK = maj.mjPrimaryKey,
Name = maj.name,
Type = "Maj"
};
var minorClients = from min in dbContext.MinorClients
where min.startdate > startDate
&& min.status == "Active" || min.status== "Inactive"
&& !(from maj in dbContext.MajorClients
where maj.startdate > startDate
&& maj.status == "Active"
select maj.name).Contains(min.Name)
select new Client
{
EntityPK = min.mnPrimaryKey,
Name = min.name,
Type = "Min"
};
var allClients = majorClients.Union(minorClients);

How to convert T-SQL into LINQ

I have following code in a T-SQL query and I need to convert (rewrite) it into LINQ. Can somebody help me? Thanks
SELECT (select max(X.PocetDniPoPlatnosti)
from
(
select
(select top 1 datediff(day,datumplatnosti,getdate()) from planrealizace p
where p.cinnostsopidsop = cinnostsop.idsop and datumplatnosti <= getdate() and p.provest = 1 and p.datumprovedeni is null
order by p.datumplatnosti desc) as PocetDniPoPlatnosti
from cinnostsop
where cinnostSOP.LegislativneVyznamna = 1 and (CinnostSOP.ObjektId = 131476)) X) as PoPlatnosti
this should work, but I could not try it as I do not have any programming tools at home, so feel free to let me know if this doesn't work, and we can improve it together
var max = (from cp in cinnostsop.Where(c => c.LegislativneVyznamna = 1 && c.ObjektId = 131476)
join p in (
planrealizace.
Where(pz => pz.datumplatnosti <= DateTime.Now &&
pz.provest = 1 and pz.datumprovedeni is null).
GroupBy(pz => pz.cinnostsopidsop, pz => pz).
Select(g =>
new {
id = g.Key,
firstdate = (g.OrderByDescending(
pz => pz.datumplatnosti).
First().datumplatnosti - DateTime.Now
).Totaldays
})
) on cp.idsop equals p.id
select p.firstdate).Max(d => d);