Linq Sum based on some columns - sql

I have a query returning some values for a specific CompanyId and a Specific Month/Year.
I want to make a report for the whole year. (So I need to sum up the values from different months, but of the same year and CompanyId)
Here is my query now:
from er in EconomicReports
join com in Companies on er.CompanyId equals com.Id
join cou in Countries on com.CountryId equals cou.Id
where er.Year == 2014
select new
{
Country = cou.Name,
CompanyId = com.Id,
CorporationId = com.CorporationId,
Year = er.Year,
RegisteredCases = er.NewCasesTotalCount,
RegisteredCasesAmount = er.NewCasesTotalAmount,
ResolvedCases = er.ClosedCasesTotalCount,
ResolvedCasesAmount = er.ClosedCasesCapitalAmount + er.ClosedCasesInterestAmount,
ActiveCases = (er.NewCasesTotalCount ?? 0) - (er.ClosedCasesTotalCount ?? 0),
ActiveCasesAmount = (er.NewCasesTotalAmount ?? 0) - (er.ClosedCasesCapitalAmount ?? 0) - (er.ClosedCasesInterestAmount ?? 0)
}
Basically, rows 1 and 5 need to be one row, because they are from the same year, same company Id (I have put also Month in the results for you to see that is a different month, but same year)

you need a GroupBy:
var query = (from er in EconomicReports
join com in Companies on er.CompanyId equals com.Id
join cou in Countries on com.CountryId equals cou.Id
where er.Year == 2014
select new
{
Country = cou.Name,
CompanyId = com.Id,
CorporationId = com.CorporationId,
Year = er.Year,
RegisteredCases = er.NewCasesTotalCount,
RegisteredCasesAmount = er.NewCasesTotalAmount,
ResolvedCases = er.ClosedCasesTotalCount,
ResolvedCasesAmount = er.ClosedCasesCapitalAmount + er.ClosedCasesInterestAmount,
ActiveCases = (er.NewCasesTotalCount ?? 0) - (er.ClosedCasesTotalCount ?? 0),
ActiveCasesAmount = (er.NewCasesTotalAmount ?? 0) - (er.ClosedCasesCapitalAmount ?? 0) - (er.ClosedCasesInterestAmount ?? 0)
});
var result = query
.GroupBy(u => new {u.Country, u.CompanyId, u.CorporationId, u.Year})
.Select(u => new
{
Country = u.Key.Country,
CompanyId = u.Key.CompanyId,
CorporationId = u.Key.CorporationId,
Year = u.Key.Year,
RegisteredCases = u.Select(t => t.RegisteredCases).DefaultIfEmpty().Sum(),
RegisteredCasesAmount = u.Select(t => t.RegisteredCasesAmount).DefaultIfEmpty().Sum(),
ResolvedCases = u.Select(t => t.ResolvedCases).DefaultIfEmpty().Sum(),
ResolvedCasesAmount = u.Select(t => t.ResolvedCasesAmount).DefaultIfEmpty().Sum(),
ActiveCases = u.Select(t => t.ActiveCases).DefaultIfEmpty().Sum(),
ActiveCasesAmount = u.Select(t => t.ActiveCasesAmount).DefaultIfEmpty().Sum()
})
.ToList();
i think Country and CorporationId must be same for grouped records based on CompanyId and Year, so i was included them in group by, to use in Select

Related

Multiple aggregate functions in the same query using LINQ expression [duplicate]

I want to get count of a set based on different condition:
var invoices = new AccountingEntities().Transactions
var c1 = invoices.Count(i=>i.Type = 0);
var c2 = invoices.Count(i=>i.Type = 1);
var c3 = invoices.Count(i=>i.Type = 2);
How its possible to call all three queries in one DB round trip to increase performance?
Sure, just wrap up your three counts in a POCO or anonymous type:
using (var invoices = new AccountingEntities())
{
var c = (from i in invoices.Transactions
select new
{
c1 = invoices.Count(i=>i.Type = 0),
c2 = invoices.Count(i=>i.Type = 1),
c3 = invoices.Count(i=>i.Type = 2)
}).Single();
}
Also, dispose your context, as I show.
To aggregate arbitrary subqueries, use a dummy single-row result set from which you nest the desired subqueries. Assuming db represents your DbContext, the code to count invoice types will look like this:
var counts = (
from unused in db.Invoices
select new {
Count1 = db.Invoices.Count(i => i.Type == 0),
Count2 = db.Invoices.Count(i => i.Type == 1),
Count3 = db.Invoices.Count(i => i.Type == 2)
}).First();
If the want to generically get a count of all types, use grouping:
var counts =
from i in db.Invoices
group i by i.Type into g
select new { Type = g.Key, Count = g.Count() };

LINQ and Lambda, query based on an array

I have this model and I want to write a where clause that query specific results based on and array, for example I want to show only the song that has an id in the array [1, 3, 7, 8]:
I wrote the expression below but I don't know how to write the where statement:
var model = from c in _db.Categories
from co in _db.Composers
from k in _db.Keys
from p in _db.Poets
from si in _db.Singers
from t in _db.Types
join s in _db.Songs on
new
{
Catid = c.id,
Comid = co.id,
Keyid = k.id,
Poetid = p.id,
Singerid = si.id,
Typeid = t.id
}
equals
new
{
Catid = s.CategoryId,
Comid = s.ComposerId,
Keyid = s.KeymId,
Poetid = s.PoetId,
Singerid = s.SingerId,
Typeid = s.TypeId
}
where
............
select new SongViewModel
{
id = s.id,
Name = s.Name,
Lyric = s.Lyric,
Chord = s.Chord,
Note = s.Note,
Audio = s.Audio,
Lycho = s.Lycho,
Likes = s.Likes,
Dislikes = s.Dislikes,
Category = c.Name,
Composer = co.Name,
Keym = k.Name,
Poet = p.Name,
Singer = si.Name,
Type = t.Name
};
Try this:
var ids = new List<int> {1,3,7,8};
...
where ids.Contains(s.Id)
select
...

SQL to LINQ query equivalent

Hello I need to crate linq query from this SQL:
SQL:
select
p.id,
p.Name,
sum(h.Hour)
from
dbo.Hour h
INNER JOIN dbo.ProjectView p ON h.ProjectId = p.Id
WHERE
h.PeopleId = 7999
group by
p.Name, p.Id
LINQ: I tried this but it is not the same:
var query = from hours in _hourRepository.GetAll()
join proj in _projectRepository.GetAll() on hours.ProjectId equals proj.Id
where hours.PeopleId == personId
group hours by new { proj.Id, proj.Name, proj.Flag, hours.Hours } into g
select new PopleProjectsSumDto
{
Id = g.Key.Id,
Name = g.Key.Name,
Flag = g.Key.Flag,
Hours = g.Sum(h => h.Hours)
};
OK i find solution by removing hours from group:
LINQ:
var query = from hours in _hourRepository.GetAll()
join proj in _projectRepository.GetAll() on hours.ProjectId equals proj.Id
where hours.PeopleId == personId
group hours by new { proj.Id, proj.Name, proj.Flag } into g
select new PopleProjectsSumDto
{
Id = g.Key.Id,
Name = g.Key.Name,
Flag = g.Key.Flag,
Hours = g.Sum(h => h.Hours)
};

Join Subquery result in Linq

I am posting one more doubt of mine:
Is there a way by which we can use the result of one query and then join the same further just like we do in SQL:
SELECT Applications.* , ApplicationFees.ApplicationNo, ApplicationFees.AccountFundDate1,ApplicationFees.AccountFundDate2 ,ApplicationFees.AccountFundDate3 , ApplicationFees.AccountCloseDate1, ApplicationFees.AccountCloseDate2,ApplicationFees.AccountCloseDate3,
isnull(SUBQRY11.AMNT ,0) as SCMSFEE1R,
isnull(SUBQRY12.AMNT,0) as SCMSFEE2R,
Left Join
(
SELECT ApplicationNo,COUNT(ApplicationNo) AS CNT, SUM(Amount) as AMNT
FROM Payments where (FEETYPE=1 AND FeePosition=1) and (FeeDate>='2011-01-01')
and (FeeDate<='2012-01-01')
GROUP BY ApplicationNo
)SUBQRY11
ON ApplicationFees.ApplicationNo= SUBQRY11.ApplicationNo
Left Join
(
SELECT ApplicationNo,COUNT(ApplicationNo) AS CNT2, SUM(Amount) as AMNT
FROM Payments where (FEETYPE=1 AND FeePosition=2) and (FeeDate>='2011-01-01')
and (FeeDate<='2012-01-01')
GROUP BY ApplicationNo )SUBQRY12 ON ApplicationFees.ApplicationNo=SUBQRY12.ApplicationNo
I want to avoid the same in foreach of the query as that will be quite time consuming.
Yes, you can join sub queries. Like this:
var query = from f in db.ApplicationFees
join sub in (from p in db.Payments
where p.Type == 1 && p.Position == 1 &&
p.Date >= fromDate && p.Date <= toDate
group p by p.ApplicationNo into g
select new {
ApplicationNo = g.Key,
CNT = g.Count(),
AMNT = g.Sum(x => x.Amount)
})
on f.ApplicationNo equals sub.ApplicationNo into feePayments
select new { Fee = f, Payments = feePayments };
But writing it in single query is not very maintainable. Consider to compose your query from sub-queries defined separately:
var payments = from p in db.Payments
where p.Type == 1 && p.Position == 1 &&
p.Date >= fromDate && p.Date <= toDate
group p by p.ApplicationNo into g
select new {
ApplicationNo = g.Key,
CNT = g.Count(),
AMNT = g.Sum(x => x.Amount)
};
var query = from f in db.ApplicationFees
join p in payments
on f.ApplicationNo equals p.ApplicationNo into feePayments
select new { Fee = f, Payments = feePayments };

dynamically change LINQ to Entity query

int year = 2009; // get summ of TONS2009 column
var query = from ODInfo in DataContext.CIMS_TRUCKS
where pLocationIDs.Contains(ODInfo.OID)
group ODInfo by ODInfo.OID into g
select new
{
OID = g.Key,
TotalTons = g.Sum( ODInfo => ODInfo.TONS2009)
};
IN the expression 'ODInfo => ODInfo.TONS2009', how do I change TONS2009 to TONS2010 or TONS2011 based on the method parameter 'int year' ?
K06a's answer is close but won't work server-side. Try this:
IEnumerable<OutputType> myQuery(IEnumerable<InputType> data, Expression<Func<InputType,decimal>> expr)
{
return from ODInfo in DataContext.CIMS_TRUCKS
where pLocationIDs.Contains(ODInfo.OID)
group ODInfo by ODInfo.OID into g
select new OutputType
{
OID = g.Key,
TotalTons = g.AsQueryable().Sum(expr)
};
}
var query = myQuery(DataContext.CIMS_TRUCKS, ODInfo => ODInfo.TONS2009);
I haven't tried this, but did something similar here.
UPDATE
If you really need to translate input strings (like "2009") to expressions, it's still possible:
string year = "2009";
Type ODInfoType = typeof(ODINFOTYPE); // substitute with the type of ODInfo
ParameterExpression pe = ParameterExpression.Parameter(ODInfoType, "ODInfo");
MemberInfo mi = ODInfoType.GetProperty("TONS" + year);
MemberExpression me = Expression.MakeMemberAccess(pe, mi);
var expr = Expression.Lambda<Func<ODINFOTYPE, decimal>>(me, pe);
Be aware that this is a patch to the extremly evil structure of your database.
You can try something like that:
TotalTons = g.Sum( ODInfo => (year == 2009) ? ODInfo.TONS2009 : ((year == 2010)
? ODInfo.TONS2010 : ODInfo.TONS2011))
Or make it more readable and use { } to split that lambda expression into more then one line and use eg. switch statement.
The best solution is to break this up into multiple querys that you can compose to a final query:
int year = 2009; // get summ of TONS2009 column
var odInfos =
year == 2009 ? DataContext.CIMS_TRUCKS.Select(x => new { x.OID, TONS = x.TONS2009 })
year == 2010 ? DataContext.CIMS_TRUCKS.Select(x => new { x.OID, TONS = x.TONS2010 })
year == 2011 ? DataContext.CIMS_TRUCKS.Select(x => new { x.OID, TONS = x.TONS2011 })
: null;
var query = from ODInfo in odInfos
where pLocationIDs.Contains(ODInfo.OID)
group ODInfo by ODInfo.OID into g
select new
{
OID = g.Key,
TotalTons = g.Sum(ODInfo => ODInfo.TONS)
};
This will specialize to three possible queries at runtime, thereby giving the best possible performance. It is better than a case-switch.
Try this way:
IEnumerable<OutputType> myQuery(IEnumerable<InputType> data, Func<InputType,decimal> func)
{
return from ODInfo in data
where pLocationIDs.Contains(ODInfo.OID)
group ODInfo by ODInfo.OID into g
select new OutputType
{
OID = g.Key,
TotalTons = g.Sum(func)
};
}
var query = myQuery(DataContext.CIMS_TRUCKS, ODInfo => ODInfo.TONS2009);
Using DynamicLinq which works with EF also:
int year = 2009; // get summ of TONS2009 column
var query = from ODInfo in DataContext.CIMS_TRUCKS
where pLocationIDs.Contains(ODInfo.OID)
group ODInfo by ODInfo.OID into g
select g;
var projectedGroups = query.Select("new (Key as OID, Sum(TONS" + year + ") as TotalTons)");