Linq expression resquested - linq

Let's say I have List of object containing these two records :
EmployeeId - Category - Amount
1 - T - 150
1 - D - 300
The result I want in the final is something looking lie this :
EmployeeId - TAmount - DAmount
1 - 150 - 300
How can I achive this using LINQ, I just don't see how to do this with a simple group by on my EmployeeId field ...

var employeeId = 1;
var query =
from row in table
group row by row.EmployeeId into g
where g.Key == employeeId
select new
{
EmployeeId = row.Key,
TAmount = g.SingleOrDefault(r => r.Categpry == "T"),
DAmount = g.SingleOrDefault(r => r.Categpry == "D"),
};

Related

Linq - Inner join with group with sum

I have 2 tables, first table if transactions
transaction table:
Id LoanId
1 100
The second table I have is a TransactionLeg table
transactionleg table:
ID TransactionId GLAmount
1 1 200
2 1 200
I would like to join the two on the TransactionId column, group by the loanID and sum the GLAmount
So it should produce the following:
LoanId TotalGlAmount
100 400
var investmentsWritten = from transaction in ctx.Transactions
join transactionleg in ctx.TransLegs on transaction.Id equals transactionleg.TransactionId
where
transaction.Class == Transaction.TransactionClasses.WriteOff &&
transaction.Created >= StartDate.Date && transaction.Created <= EndDate.Date
group transaction by transaction.LoanId
into g
select new { Id = g.Key, Value = _____ };
I was wondering what goes where the underline is, the value is transactionleg.GLAmount. I tried g.Sum(x => x.GLAmount) but GLAmount is not recognized, it is highlighted in red stating Cannot resolve symbol GLAmount
It is because GLAmount is in transactionleg not in transaction,
Modify your group by like this:
group new
{
transaction,
transactionleg
}
by new
{
transaction.LoanId
}
and now in Select:
select new
{
Id = g.Key,
Value = g.Sum(x=>x.transactionleg.GLAmount)
}

Linq query with two sub-queries that group by, one with an average, and one with a max

I have a parent table, parentTable which may or may not have children in childTable. I am looking to get average % complete of any given parent's children, and the MAX(due) (date) of the children where they exist. My SQL is this:
SELECT parentRecord_id, assigned_to,
(SELECT avg(complete)
FROM childTable
WHERE parent_id = parentRecord_id
and deleted IS NULL
GROUP BY parent_id),
(SELECT max(due)
FROM childTable
WHERE parent_id = parentRecord_id
and deleted IS NULL
GROUP BY parent_id
)
FROM parentTable s
WHERE s.deleted IS NULL and assigned_to IS NOT NULL
My result set gives me rows with either correct values for the average and max, or null. In this instance I have to do follow up processing so I could ignore the null values if I was doing a foreach through DataTable rows. However I am trying to do this in Linq and can't figure out how to avoid a System.InvalidOperationException where Linq is trying to cast null to a double. Here is what I've tried so far.
var query8 = from s in db.parentTable
where s.deleted == null
select new
{
ID = s.assigned_to,
Average =
((from t in db.childTable
where t.parent_id == s.strategy_id
group t by new { t.parent_id } into g
select new
{
a0 = g.Average(f0 => f0.complete )
}).FirstOrDefault().a0)
};
foreach (var itm in query8)
{
Console.WriteLine(String.Format("User id:{0}, Average: {1}", itm.ID, itm.Average));
}
Here's my question. How do I get the query to handle those returned rows where average complete or max due (date) are null?
You can either filter out the records where the values are null (by another condition) or if you want to include them do something like this:
a0 = g.Average(f0 => f0.complete.HasValue? f0.complete: 0 )
I would cast the list to nullable double before calling Average/Max like so:
var query8 =
from s in db.parentTable
where s.deleted == null
select new
{
ID = s.assigned_to,
Average =
from t in db.childTable
where t.parent_id == s.strategy_id
group t by t.parent_id into g
select g.Cast<double?>().Average(f0 => f0.complete)
};
Assuming complete is a Nullable, you should be able to do:
var query8 = from s in db.parentTable
where s.deleted == null
select new
{
ID = s.assigned_to,
Average =
((from t in db.childTable
where t.parent_id == s.strategy_id
&& s.complete.HasValue()
group t by new { t.parent_id } into g
select new
{
a0 = g.Average(f0 => f0.complete )
}).FirstOrDefault().a0)
};
Thanks to all who responded.
I was unable get around the null anonymous issue with the basic query as I had it, but adding a join to the childTable eliminated the nulls.
Another solution is to use a from x in g.DefaultIfEmpty clause.
var query8 =
from st in db.tableParent
select new { Ass = st.assigned_to ,
Avg =
(from ta in db.tableChild
group ta by ta.parent_id into g
from x in g.DefaultIfEmpty()
select g.Average((f0=>f0.complete))).FirstOrDefault()
};

LINQ Group and SelectMany

I have a great LINQ statement that Oracle doesn't like:
var result = from r in Context.Accounts
where Statuses.Contains(r.DEC_CD)
&& r.Deposit.Payments.Where(n => n.CreatedDate >= DateStart).Sum(n => n.Total - n.Fees) > 3000
select r;
Unfortunately the .Where(...).Sum(...) creates invalid SQL using the Oracle EF provider.
I have tried to rewrite it using group instead:
var result = from g in Context.Payment
where g.CreatedDate >= DateStart
group g by g.Total - g.Fees into grp
where grp.Key >= 3000
select g;
The above example does not compile.
var result = from g in Context.Payment
where g.CreatedDate >= DateStart
group g by g.Total - g.Fees into grp
where grp.Key >= 3000
select new { g };
Also does not compile
var result = from g in Context.Payment
where g.CreatedDate >= DateStart
group g by g.Total - g.Fees into grp
where grp.Key >= 3000
select grp.SelectMany(n => n);
Looks like it's going to work from Intellisense, but I get an error The type arguments for method SelectMany cannot be inferred from the usage
The only thing I am able to select is simply grp and if I select that I get Igrouping<decimal, Payment>' which has keys and multiple rows underneath. I just want the rows, hence the.SelectMany`
Any idea how to get a flattened IEnumerable<Payment>?
You probably just want this
var result = from g in Context.Payment
where g.CreatedDate >= DateStart
&& (g.Total - g.Fees) >= 3000
select g;
Right? All Payments where total - fees is gte 3000 and the date criteria. It seems the group is not intended or needed.
You have to add a from statement to re-select the group:
var result = from g in Context.Payment
where g.CreatedDate >= DateStart
group g by g.Total - g.Fees into grp
where grp.Key >= 3000
from i in grp
select i;
var result =
from p in Context.Payment
where p.CreatedDate >= DateStart
group p by p.Total - p.Fees into g
where g.Key >= 3000
select g; // select group here
Or better without grouping:
var result =
from p in Context.Payment
where p.CreatedDate >= DateStart &&
(p.Total - p.Fees) >= 3000
select p;

query each month record in the table by linq

I have a datatable named testable, it has two columns id(primary key, int) and time(datetime). I want to calculate the number of records of every specific month in the table. For example, there are 5 rows in the table,
Id datetime(d/m/y)
1 12/3/2011
2 15/3/2011
3 4/4/2011
4 1/8/2011
5 19/12/2011
How to write a Linq query to query out the record like this,
Id datetime count
1. 1/2011 0
2. 2/2011 0
3. 3/2011 2
4. 4/2011 1
5. 5/2011 0
6. 6/2011 0
7. 7/2011 0
8. 8/2011 1
9. 9/2011 0
10. 10/2011 0
11. 11/2011 0
12. 12/2011 1
I have written a query statement like this,
var query = from c in testtable.AsEnumerable()
group c by new
{
years = Convert.ToDateTime(c.Field<string>("Posted")).Year,
months = Convert.ToDateTime(c.Field<string>("Posted")).Month
}
into d
orderby d.Key.years,d.Key.months
select new
{
Date = String.Format("{0}/{1}",d.Key.months,d.Key.years),
Count = d.Count()
};
But it only queries out the month 3/4/8/12, it can’t query out other month records.
Anyone can help?
You need to generate a sequence of all dates and left join your existing query with that sequence.
var allMonths = Enumerable.Range(1, 12)
.Select(i => String.Format("{0}/{1}", i, "2011"));
var query = new[]
{
new{ Date= "3/2011" , Count = 2},
new{ Date= "4/2011" , Count = 1},
new{ Date= "8/2011" , Count = 1},
new{ Date= "12/2011", Count = 1},
};
var query2 = from month in allMonths
join date in query on month equals date.Date into g
from date in g.DefaultIfEmpty()
select new
{
Date = month,
Count = (date == null) ? 0 : date.Count
};
foreach (var q in query2)
{
Console.WriteLine(q);
}

LINQ distinct on 2 fields

I have a LINQ query that returns data and I want to filter based on 2 fields (fkProfileID and fkOrgID) that are often the same. I only want to show 1 record when fkProfileID and fkOrgID match, so it is similar to doing an SQL distinct, but on 2 fields rather than one.
My data will look like this (other fields have been removed) :
fkProfileID fkOrgID
1 1001
1 1001
1 1001
2 1001
2 1001
1 1005
1 1005
So here I want to return only the following:
fkProfileID fkOrgID
1 1001
2 1001
1 1005
Here is my current LINQ (both fields above are in tblUserRights), how do I need to change it to do this?
List<ProfileJSON> lstProfiles = (from r in _database.tblUserRights
join p in _database.LuProfiles on r.fkProfileID equals p.luProfileID
join o in _database.tblOrganisations on r.fkOrgID equals o.pkOrgID
where r.fkUniqueID == intPKUserID
orderby o.OrgDesc, p.ProfileName
select new ProfileJSON
{
SiteID = o.pkOrgID,
SiteName = o.OrgDesc,
ProfileID = p.luProfileID,
ProfileName = p.ProfileName
}).ToList();
You can use .Distinct() after your query
List<ProfileJSON> lstProfiles = (from r in _database.tblUserRights
join p in _database.LuProfiles on r.fkProfileID equals p.luProfileID
join o in _database.tblOrganisations on r.fkOrgID equals o.pkOrgID
where r.fkUniqueID == intPKUserID
orderby o.OrgDesc, p.ProfileName
select new ProfileJSON
{
SiteID = o.pkOrgID,
SiteName = o.OrgDesc,
ProfileID = p.luProfileID,
ProfileName = p.ProfileName
}).Distinct().ToList(); //Distinct here

Resources