I'm really struggling with LINQ. I've written my query out in SQL (in effect it's a pivot), and trying to write an equivalent statement in LINQ. Any pointers forward would be much appreciated. See below for code:
SELECT b.URL,
SUM(CASE WHEN (a.ExtFlag = 0) THEN 1 ELSE 0 END) AS IntLinks,
SUM(CASE WHEN (a.ResponseCode >= 400 AND a.ExtFlag = 0) THEN 1 ELSE 0 END) AS IntBroken,
SUM(CASE WHEN (a.ExtFlag = 1) THEN 1 ELSE 0 END) AS ExtLinks,
SUM(CASE WHEN (a.ResponseCode >= 400 AND a.ExtFlag = 1) THEN 1 ELSE 0 END) AS ExtBroken
FROM Link a
INNER JOIN Host b
ON a.HostID = b.ID
GROUP BY b.URL
ORDER BY b.URL
Many Thanks.
I think this should do what you want - it's at least worth a try:
var query = from link in db.Links
join host in db.Hosts on link.HostID equals host.ID
group link by host.Url into links
select new
{
Url = links.Url,
IntLinks = links.Count(link => link.ExtFlag == 0),
IntBroken = links.Count(link => link.ExtFlag == 0 &&
link.ResponseCode >= 400),
ExtLinks = links.Count(link => link.ExtFlag == 1),
ExtBroken = links.Count(link => link.ExtFlag == 1 &&
link.ResponseCode >= 400),
};
This is how to do it:
from a in db.Links
group a by a.Host.Url into g
select new
{
Url = g.Key,
IntLinks = (
from x in g
select x.ExtFlag == 0 ? 1 : 0)
.Sum()
};
You can use the ?: operator for your CASE.
Related
I tried to convert sql query to linq but couldn't get it correctly. Can someone help me to convert below to linq please?
SELECT stockdiary.datenew, locations.ID AS LOCATIONID, locations.NAME AS LOCATIONNAME,
products.REFERENCE, products.NAME,
products.CATEGORY, categories.NAME AS CATEGORYNAME,
products.SUPPLIER,
SUM(CASE WHEN stockdiary.UNITS <0 THEN stockdiary.UNITS ELSE 0 END) AS UNITSOUT,
SUM(CASE WHEN stockdiary.UNITS <0 THEN stockdiary.UNITS * stockdiary.PRICE ELSE 0 END) AS TOTALOUT,
SUM(CASE WHEN stockdiary.UNITS >=0 THEN stockdiary.UNITS ELSE 0 END) AS UNITSIN,
SUM(CASE WHEN stockdiary.UNITS >=0 THEN stockdiary.UNITS * stockdiary.PRICE ELSE 0 END) AS TOTALIN,
SUM(stockdiary.UNITS) AS UNITSDIFF,
SUM(stockdiary.UNITS * stockdiary.PRICE) AS TOTALDIFF
FROM stockdiary JOIN locations ON stockdiary.LOCATION = locations.ID,
products LEFT OUTER JOIN categories ON products.CATEGORY = categories.ID
WHERE products.ID = stockdiary.PRODUCT
GROUP BY locations.ID, locations.NAME, products.REFERENCE, products.NAME, products.CATEGORY, categories.NAME
ORDER BY locations.ID, categories.NAME, products.NAME
======
below is my linq query which gives me wrong result.
(from sd in Stockdiaries
join loc in Locations on sd.Location equals loc.Id
join prod in Products on sd.Product equals prod.Id
join cat in Categories on prod.Category equals cat.Id
select new
{
Location = loc.Name,
Category = cat.Name,
Reference = prod.Reference,
Product = prod.Name,
UnitsOut = sd.Units < 0 ? sd.Units:0,
TotalOut = sd.Units < 0 ? sd.Units * sd.Price:0,
UnitsIn = sd.Units >= 0 ? sd.Units:0,
TotalIn = sd.Units >= 0 ? sd.Units * sd.Price:0,
UnitsDiff = sd.Units,
TotalDiff = sd.Units * sd.Price
})
You've got some old join syntax in that original sql! This is in addition to the left join. This is abbreviated here:
from stockdiary
join locations on stockdiary.location = locations.id
, products
left join categories on products.category = categories.id
where products.id = stockdiary.product
See if the following approach works out for you. It may not output exactly as you desire it, but it's hopefully close and sufficient for you to work with it after that. Although that being said, I don't have any sample data from you on which to test it, so the only thing I can confirm right now is that it won't error out.
I've got comments within the code describing its components.
var query =
from sd in Stockdiaries
join loc in Locations on sd.Location equals loc.Id
// Your old syntax join should work like an inner join
join prod in Products on sd.Product equals prod.Id
// This is a left join. So you've got to do the 'into' hoop and
// then 'overwrite' the cat table.
join cat in Categories on prod.Category equals cat.Id into pCat
from cat in pCat.DefaultIfEmpty()
// put it all together into one result set
select new {
Location = loc.Name,
Category = cat?.Name, // Because it's a left join, it may be null, hence the '?'
Reference = prod.Reference,
Product = prod.Name,
sd.Units,
sd.Price
} into cnd
// group as appropriate, and remember that in linq
// grouping is a separate operation from aggregation
group cnd by new { cnd.Location, cnd.Reference, cnd.Product, cnd.Category } into g
// aggregate
select new {
g.Key.Location,
g.Key.Reference,
g.Key.Product,
g.Key.Category,
UnitsOut = g.Sum(row => row.Units < 0 ? row.Units : 0),
TotalOut = g.Sum(row => row.Units < 0 ? row.Units * row.Price : 0),
UnitsIn = g.Sum(row => row.Units >= 0 ? row.Units : 0),
TotalIn = g.Sum(row => row.Units >= 0 ? row.Units * row.Price : 0),
UnitsDiff = g.Sum(row => row.Units),
TotalDiff = g.Sum(row => row.Units * row.Price)
};
query.Dump();
#pwilcox and all other friends,
Here is the final linq query which gave me the absolute result! I added orderby expression in addition to the above query.
(from sd in Stockdiaries
join loc in Locations on sd.Location equals loc.Id
join prod in Products on sd.Product equals prod.Id
join cat in Categories on prod.Category equals cat.Id into pCat
from cat in pCat.DefaultIfEmpty()
select new {
Location = loc.Name,
Category = cat.Name,
Reference = prod.Reference,
Product = prod.Name,
sd.Units,
sd.Price
} into cnd
group cnd by new {cnd.Location,cnd.Reference, cnd.Product, cnd.Category} into g
orderby g.Key.Location, g.Key.Category, g.Key.Product
select new {
g.Key.Location,
g.Key.Reference,
g.Key.Product,
g.Key.Category,
UnitsOut = g.Sum(row => row.Units < 0 ? row.Units : 0),
TotalOut = g.Sum(row => row.Units < 0 ? row.Units * row.Price : 0),
UnitsIn = g.Sum(row => row.Units >= 0 ? row.Units : 0),
TotalIn = g.Sum(row => row.Units >= 0 ? row.Units * row.Price : 0),
UnitsDiff = g.Sum(row => row.Units),
TotalDiff = g.Sum(row => row.Units * row.Price)
})
I need help with converting a SQL query to LINQ. I tried with Linqer but that didn't give the expected results. This is my SQL query:
SELECT
dr.startDate,
dr.endDate,
SUM(CASE WHEN me.Size <= 10 THEN 1 ELSE 0 END) AS FirstGroup,
SUM(CASE WHEN me.Size > 10 AND me.Size <= 20 THEN 1 ELSE 0 END) AS SecondGroup,
SUM(CASE WHEN me.Size > 20 AND me.Size <= 30 THEN 1 ELSE 0 END) AS ThirdGroup,
SUM(CASE WHEN me.Size > 30 THEN 1 ELSE 0 END) AS FourthGroup,
MAX(ISNULL(me.Size,0)) AS MaxSize,
SUM(ISNULL(me.Size,0)) AS SpaceTotal
FROM
time_intervals dr
LEFT OUTER JOIN Rooms me
ON ( me.DateTime BETWEEN dr.startDate AND dr.endDate)
GROUP BY
dr.startDate,
dr.endDate
ORDER BY dr.startDate
The LINQ i tried is:
var stats = from t in time_intervals
from q in query
where q.DateTime >= t.startDate && q.DateTime <= t.endDate
select new {
Date = t.startDate,
First = (q.Size <= 10),
Second = (q.Size > 10 && q.Size <= 20),
Third = (q.Size > 20 && q.Size <= 30),
Fourth = (q.Size > 30)
};
But that didn't give the same result as the SQL query.
You are not using group keyword in your LINQ while you are grouping records by by start date and end date.
Try this code:-
var stats = (from t in time_intervals
from q in query.Where(m=> m.DateTime >= t.startDate && m.DateTime <= t.endDate).DefaultIfEmpty()
group q by new { t.startDate, t.endDate, q.Size } into g
select new
{
Date = g.Key.startDate,
First = g.Count(m=>m.Size <= 10)
}).OrderBy(m => m.startDate);
Wish to convert this to LINQ.
select COUNT(*) as 'BillsOver30' from pssuite_web.pujhaccd
where billdays>30 and DATEDIFF(month,'07-07-2016', GETDATE()) <= 13
Group By Month(billdate)
This will show 13 rolling months from 07-07 with how many bills were over 30 for each month.
This is the terrible query I've written in LINQ, which doesn't work:
DateTime earliestDate = objdate1.DateStart.Value.AddMonths(-13);
var custQuery9 = ((from m in DataContext.pujhaccds
where m.billdays > 30
&& m.billdate >= earliestDate
&& m.billdate <= objdate1.DateStart
group m by m.billdays into p
select p)).Count();
To get result as you described in comments:
var result = (from m in DataContext.pujhaccds
where m.billdays > 30 &&
m.billdate >= earliestDate &&
m.billdate <= objdate1.DateStart
group m by m.billdate.Month into p
select new { Month = p.Key, Count = p.Count() }).ToList();
To get it like in original question replace the select above like this:
select p.Count()
That grouping will be problematic though if you have data from different years and want to separate it. If that is the case group by 2 fields - year and month:
var result = (from m in DataContext.pujhaccds
where m.billdays > 30 &&
m.billdate >= earliestDate &&
m.billdate <= objdate1.DateStart
group m by new { m.billdate.Value.Month, m.billdate.Value.Year } into p
select new { Date = $"{p.Key.Month} - {p.Key.Year}", Count = p.Count() }).ToList();
i'm trying to do this on LINQ:
select p.ProductID, p.ArticleCode, SUM((case h.OperationType when 0 then 1 else -1 end) * h.[Count])
from Products p
inner join StockItems s on p.ArticleCode = s.ArticleCode
inner join StockHistorical h on s.ArticleID = h.ArticleID
where h.[Date] < '23/08/2013 11:30:00'
group by p.ProductID, p.ArticleCode
I have this:
var products = (from p in e.Products
join s in e.StockItems on p.ArticleCode equals s.ArticleCode
join h in e.StockHistoricals on s.ArticleID equals h.ArticleID
where h.Date < DateTime.Parse("23/08/2013 11:30:00")
group p by p.ProductID into StockResult
select new { });
Anyone know how can i do the
SUM((case h.OperationType when 0 then 1 else -1 end) * h.[Count])
with LINQ?
Thanks!
I forgot to say that the problem is the "group by", because i can't access the OperationType property in the StockResult group.
Solved! The key is the:
let combined = new
{
Product = p,
HistoryCount = (h.OperationType == 0 ? 1 : -1) * h.Count
}
...
let combined = new
{
Product = p,
HistoryCount = (h.OperationType == 0 ? 1 : -1) * h.Count
}
group combined by combined.Product.ProductID into StockResult
select new
{
ProductID = StockResult.Key,
Total = StockResult.Sum(x => x.HistoryCount)
}
It's not a direct translation, but I'd go with:
(h.Count(his => his.OperationType != 0)
- h.Count(his => his.OperationType == 0))
* h.Count()
It should be functionally equivalent, and seems to better represent what you're trying to do.
You are trying to do something like this?
I am not sure this is going to work.
select new
{
S=Sum(((h.OperationType)!=0?-1:1)*h.Count)
}
I have a big problem.
I'm for last 5 year SQL-boy, but now I need to convert my SQL query into LINQ to entity C# format.
Because I'm new in LINQ (complex statements) right now I need fast help.
Thank's in advance.
P.S. also I need some advices, some start point to start rapidly to learn LINQ to entities.
Here is my SQL (direct from my app(#endDate,#endDate and #glChartID remain as parameters also in my c# app)):
SELECT budget.accountid,
budget.perioddate,
budget.lastyear,
budget.thisyear,
budget.budget,
budget.operplan,
budget.forecast,
glchart.accounttype,
glchart.headertype
FROM budget INNER JOIN glchart ON budget.accountid = glchart.id
WHERE budget.accountid = #glChartID AND budget.perioddate BETWEEN #startDate and #endDate AND glchart.headertype NOT LIKE 'Header%'
UNION
SELECT glchart.id,
budget.perioddate,
SUM(ISNULL(budget.lastyear, 0)),
SUM(ISNULL(budget.thisyear, 0)),
SUM(ISNULL(budget.budget, 0)),
SUM(ISNULL(budget.operplan, 0)),
SUM(ISNULL(budget.forecast, 0)),
glchart.accounttype,
glchart.headertype
FROM budget INNER JOIN glchart ON budget.accountid = glchart.id
WHERE budget.accountid
IN
(SELECT g.id FROM glchart g
WHERE g.code >= glchart.code AND g.code <
CASE
WHEN glchart. headerlevel = 1 AND
(SELECT MAX(g3.code)
FROM glchart g3
WHERE g3.headerlevel = 1
) = glchart.code
THEN
(SELECT MAX(g2.code)
FROM glchart g2
WHERE g2.code >= g.code)
ELSE
(SELECT MIN(g2.code)
FROM glchart g2
WHERE g2.code > glchart.code AND
g2.headerlevel = glchart. headerlevel) END ) AND
glchart.id = #glChartID AND
budget.perioddate BETWEEN #startDate AND #endDate AND
glchart.headertype LIKE 'Header%'
GROUP BY glchart.id, budget.perioddate, glchart.accounttype, glchart.headertype
Until today, I managed (thanks to DOK)how to do it and this is how my LINQ is look like right now:
var query = ((ObjectQuery<Budget>)(
from budgets in this.ObjectContext.Budgets
join glcharts in this.ObjectContext.GLCharts on new { AccountID = budgets.AccountID } equals new { AccountID = glcharts.ID }
where
(!(from glC in this.ObjectContext.GLCharts
where Convert.ToInt16(glC.Code) >= Convert.ToInt16(glcharts.Code) && glC.Code != (Convert.ToInt64(glcharts.HeaderLevel) == 1 &&
(from g3 in this.ObjectContext.GLCharts
where Convert.ToInt64(g3.HeaderLevel) == 1
select new {g3.Code}).Max(p => p.Code) == glcharts.Code ?
(from g2 in this.ObjectContext.GLCharts
where Convert.ToInt16(g2.Code) >= Convert.ToInt16(glC.Code)
select new {g2.Code}).Max(p => p.Code) :
(from g2 in this.ObjectContext.GLCharts
where Convert.ToInt16(g2.Code) > Convert.ToInt16(glcharts.Code) && g2.HeaderLevel == glcharts.HeaderLevel
select new {g2.Code}).Min(p => p.Code))
select new {glC.ID}
).Contains(new { budgets.AccountID }) &&
glcharts.ID == 2376 && budgets.PeriodDate >= StartDate &&
budgets.PeriodDate <= EndDate &&
glcharts.HeaderType.StartsWith("Header"))
).Contains(new { budgets.AccountID }) && glcharts.ID == 2376 && budgets.PeriodDate >= StartDate && budgets.PeriodDate <= EndDate && glcharts.HeaderType.StartsWith("Header")
group new {glc = glcharts, b = budgets}
by new {
glcharts.ID,
budgets.PeriodDate,
glcharts.AccountType,
glcharts.HeaderType
} into g
select new {
AccountID = (System.Int32?)g.Key.ID,
PeriodDate = (System.DateTime?)g.Key.PeriodDate,
LastYear = g.Sum(p => ((System.Decimal?)p.t.LastYear ?? (System.Decimal?)0)),
ThisYear = g.Sum(p => ((System.Decimal?)p.t.ThisYear ?? (System.Decimal?)0)),
Budget = g.Sum(p => ((int?)p.t.Budget1 ?? (int?)0)),
OperPlan = g.Sum(p => ((System.Decimal?)p.t.OperPlan ?? (System.Decimal?)0)),
Forecast = g.Sum(p => ((System.Decimal?)p.t.Forecast ?? (System.Decimal?)0)),
AccountType = g.Key.AccountType,
HeaderType = g.Key.HeaderType
}));
return query;
But in THIS LINE: .Contains(new { budgets.AccountID }) I'm getting next error :
Error 8'System.Linq.IQueryable' does not contain a definition for 'Contains' and the best extension method overload 'System.Linq.ParallelEnumerable.Contains(System.Linq.ParallelQuery, TSource)' has some invalid arguments
Does anybody have an idea where I'm wrong?
Thanks to everyone.
You might find some help in this excellent reference site.
That will lead you to, for example, two examples for UNION.
If you really must start out at this level of difficulty, you might consider breaking your SQL down into pieces and getting them working bit by bit. Do the first SELECT without the JOIN or WHERE, then add those one at a time. Then do the second SELECT the same way. Then add the UNION.
By the time you get this one worked out, SQL-boy, you will definitely be LINQ-man!