Counting total of records by year - sql

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)

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
};

Unable to translate LINQ Query

I am having an issue with the following LINQ query:
var baselineDate = DateTime.Now.AddDays(-365);
var salesPerformance = _context.SalesOrder.Where(p => p.OrderDate >= baselineDate).Where(p => p.CustomerId == customerId)
.GroupBy(p => p.OrderDate.Month)
.Select(g => new CustomerSalesPerformance
{
Month = g.Key,
Sales = g.Sum(i => i.SalesOrderItems.Sum(i => i.Qty * i.UnitPrice))
});
return await salesPerformance.ToListAsync();
I am aiming to produce a report with sales per customer for the last year:
Jan: £13,500
Feb: £0.00
Mar: £56,000
etc
I am unable to see anything in this query which would not translate (such as a DateTime function).
The error message:
{"The LINQ expression 'GroupByShaperExpression:\r\nKeySelector: DATEPART(month, s.OrderDate), \r\nElementSelector:EntityShaperExpression: \r\n EntityType: SalesOrder\r\n ValueBufferExpression: \r\n ProjectionBindingExpression: EmptyProjectionMember\r\n IsNullable: False\r\n\r\n .Sum(i => i.SalesOrderItems\r\n .Sum(i => (Nullable)i.Qty * i.UnitPrice))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information."}
My models:
SalesOrder
SalesOrderId (PK, int)
CustomerId (FK, int)
OrderDate (DateTime)
SalesOrderItem
SalesOrderItemId (PK, int)
Qty (int)
UnitPrice (decimal)
SalesOrderId (FK, int)
My DTO Model:
CustomerSalesPerformance
Month (int)
Sales (decimal?)
After GroupBy, you cannot use navigation properties. So just rewrite query to do that before.
var salesPerformance =
from so in _context.SalesOrder
where so.OrderDate >= baselineDate && so.CustomerId == customerId)
from sio in so.SalesOrderItems
group sio by so.OrderDate.Month into g
select new CustomerSalesPerformance
{
Month = g.Key,
Sales = g.Sum(i => ii.Qty * i.UnitPrice)
});

Convert SQL Server query to Entity Framework query

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.

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.

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);