Linq issue select Sum of one column minus another from different table - c#

This is my sql code
SELECT M.PartNo AS ModulePartNo,
(SELECT SUM(Delivered - Allocated)
FROM V_InStock Stk
WHERE Stk.PartNo = M.PartNo) AS Available
FROM V_Products M
WHERE M.PartNo='100-25897'
I am having real problems getting this to work in Linq, can't work out the sum part - any help would be really appreciated

This should work.
var query = from stk in V_InStock
group stk by stk.PartNo into stkg
where stkg.Key == '100-25897'
select new
{
ModulePartNo = stkg.Key,
Available = stkg.Sum(s => s.Delivered) - stkg.Sum(s => s.Allocated)
}

If you need to do aggregate grouping etc you will probably need to set up an object to "select" everything into. However for a straight join something like this should work.
var outputObject = (from t1 in dbContext.table1
join t2 in dbContext.table2 on t1.PartNo equals t2.PartNo
select (t1.Delivered - t2.Allocated));

Related

LINQ Left Join SQL equivalent via DefaultIfEmpty fails to return results

I have had an extensive look around on SE, tried all of the suggestions, checked out MSDN how to perform Left Join equivalent in LINQ to SQL and I have constructed my LINQ query according to MSDN example.
However, the result is not what SQL would return and I am completely lost as to where am I going wrong.
Here is some details:
I have two tables, Customers and Reports. A customer can submit many reports or none. In the current state I have many more reports than customers.
LINQ code:
var query = {from c in customers
join r in reports on c.Id equals r.Id into temp
from items in temp.DefaultIfEmpty()
select new {
c.Id,
LastReportDate = items?.DateCreated ?? DateTime.MinValue
}).ToList();
SQL code:
SELECT [Customers].[Id], R.LastReport AS LastReportDate FROM [Customers]
LEFT JOIN (
SELECT Reports.Id, MAX( [Reports].[Created] ) AS LastReport
FROM Reports GROUP BY Reports.Id
) AS r ON [Customers].[Id] = r.[Id]
The problem is that the query returns number of elements equal to number of reports. However, what I want is to get a list with all customers and for those who have submitted a report I wish to display the date of the most recent report, for those who have not submitted anything, I am happy to leave it NULL or DateTime.MinValue
Any help would be greatly appreciated. I guess I am missing a group by call somewhere in my LINQ code...
Im thinking probably something like this:
var query =
from c in customers
join r in reports on c.Id equals r.Id into g
select new
{
c.Id,
LastReportDate = g.Max(x => (DateTime?)x.Created)
};
you are now joining on join r in reports on c.Id equals r.Id into temp
this looks like: join on a customer.Id on Reports.Id, since you say there are 1 to many relation/rapport. I think your table will have a Reports.CustomerId. Is this correct?
So your query should something look like:
var results = customer.Where(c => c.Reports.Any())
.SelectMany(c => {c, c.Reports.Max(r => r.Created)})
.ToList();
the select comes out of my head, so i am probably missing something ;)
Have you tried LinqPad ? There you can type your linq-queries, and directly see your sql code and results. Works like a charm!

Linq return distinct values from table if not exist in another

I am trying to return all distinct rows from Staging below where Staging.CenterCode does not exist in Centers.CenterCode.
At the moment Stagings has around 850 distinct CenterCodes and Centers is empty so I should be getting all of the distinct rows, but count begs to differ :)
Any ideas?
var query =
(from s in db.Stagings
join t in db.Centers on s.CenterCode equals t.CenterCode into tj
from t in tj.DefaultIfEmpty()
where s.CenterCode != t.CenterCode
select s.CenterCode).Distinct();
var c = query.Count();
I only need the unique columns from staging so not sure if I actually need a join with the above as I am not ever using data returned from Centers - I have however tried both and get the same 0 value for count.
Any ideas?
I would not use a join, but use a Contains.
var centerCodesQuery = db.Centers.CenterCode
.Select(x => x.CenterCode);
var query = db.Staging
.Where(x => !centerCodesQuery.Contains(x.CenterCode))
.Select(x => x.CenterCode)
.Distinct();
var c = query.Count();
the join is an inner join. So, if none of the rows in 1 table match the other table on the specified identifier then it will return 0. In yours you are trying to join 1 table with 850 distinct rows with an empty table. This will return 0.
If you actually want to return only those rows in 1 table that aren't in another you can use Except:
var query = (from s in db.Stagings
select s.CenterCode)
.Except(from t in db.Centers
select t.CenterCode);
var c = query.Count();
Looks like you are trying to implement antijoin via left outer join, which is one of the possible ways, but in order to make it work, you need to change
where s.CenterCode != t.CenterCode
to
where t == null

Select all tags that are user in questions asp.net c# EF

There are four tables:
Questions(questionId, question)
QuestionTags(questionTagId, questionId, tagId)
CodingKeys(codingKeyId, codingTypeId ..)
Codings(codingId, codingKeyId, coding ..)
I want to select all question tagIds and their codings (codingKeyId is foreign key of tagId) that are represented in Questions... So if I have 10 different codings in Codings table but only two of them are represented in Questions I want to select only these two.
I tried with join like this:
var query = from qt in context.QuestionTags
join c in context.Codings on qt.tagId equals c.codingKeyId
select new
{
tagId = qt.tagId,
coding = c.coding
};
But the above solution gave me double results. For example, if one tag is included in more than one question, I get the same tag twice (I tried distinct, but that didn't work).
I also tried using Any:
var query= context.QuestionTags
.Where(qt => qt.Questions.QuestionTags.Any(q => q.tagId == qt.tagId))
.Select(qt => new
{
codingKeyId = qt.questionId,
coding = context.Codings.FirstOrDefault(c => c.CodingKeys.codingKeyId == qt.tagId).coding
});
The same thing happened here, I got duplicate results, but Distinct didn't work (don't know why).
However, if I use this SQL statement:
SELECT distinct tagId, coding
FROM QuestionTags
LEFT OUTER JOIN Codings ON codingKeyId LIKE QuestionTags.tagId
WHERE Codings.languageId = 1
I get the right result, but I don't want to write and store a procedure for this. I really wan't to know if I can solve this with EF (linq), and I am also not sure if distinct is the right solution.
Thanks for your help.
You can use group by in order to get just the results you want.
var query = from qt in context.QuestionTags
join c in context.Codings on qt.tagId equals c.codingKeyId
group qt by new {tagId = qt.tagId,coding = c.coding } into element
select new
{
tagId = element.Key.tagId,
coding = element.Key.coding
};
Please mark it as answer if you find it useful
var result = from qt in context.QuestionTags
join c in context.Codings on qt.tagId equals c.codingKeyId
where c.languageId == 1
select new
{
codingKeyId = qt.tagId,
coding = c.coding
};
return result.Distinct()
Ok, like this it is working, but is this the only way to use it with distinct and join... I am not sure if this is the right solution (but it gives me the right result) ... maybe it can be optimized a bit...
Try
var query = from qt in context.Codings
join c in context.QuestionTags on qt.tagId equals c.codingKeyId
select new
{
tagId = qt.tagId,
coding = c.coding
};

how to convert this T-SQL statment to linq

i'm starter in linq, i have write this T-SQL Query
select * from DOCUMENT_TYPES where document_id in(
select document_id from Clearance_Document where Clearance_id=(select clearance_id from clearance_id from request where request_id=3))
i want convert this T-SQL Query to linq, please help me, thanks
Well, I would start first by refactoring your SQL into something other than a chain of nested sub-queries. I think this ought to do the same thing, and it's much more readable:
SELECT
*
FROM
DOCUMENT_TYPES dt
JOIN
Clearance_Document cd
ON
dt.document_id = cd.document_id
JOIN
Request r
ON
cd.clearance_id = r.clearance_id
WHERE
r.request_id = 3
(I'm assuming that from clearance_id from request was a typo.)
Then you can easily refactor into a LINQ statement:
var result = from dt in DOCUMENT_TYPES
join cd in Clearance_Document on dt.document_id equals cd.document_id
join r in Request on cd.clearance_id equals r.clearance_id
where r.request_id = 3
select new {
property1 = dt.something,
property2 = cd.somethingElse,
...
};
var result =
from a in DOCUMENT_TYPES
let list =
(
from b in Clearance_Document
where b.Clearance_id == (from c in clearance_id where request_id == 3).First<string>())
select b
).ToList()
where list.Contains(a.document_id)
select a;
Something like that should do (i guessed you're using EF, but you can easyly adapt to other LinQ-Types):
context.Document_Types.Where(doc =>
conext.Clearance_Document.Where(cd =>
cd.Clearance_Id == context.Request.Single(r => r.Request_Id == 3)
).Contains(doc.Document_Id)
).ToList();
How about
var result = c.Id context.Request.Single(r => r.Id == 3)
.Clearances.SelectMany(c => x.DocumentTypes);
In effect, get the one and only Request with an Id equal to 3, then get all the DocumentTypes of all its Clearances.
If your database is set up with the appropriate foreign keys these relationships will be automatically generated as part of your model.

Most efficient way to get MAX value of joined table in LINQ query using C#

I am trying to find the most efficient way to get the most recent record in a joined table in LINQ.
This query may handle thousands of records so I didn't want to perform a subquery.
I need everything from items, but only the most recent date from the "Notes" table, whose field name is SubmittedDate.
var items = (from t1 in db.Items
from t2
in db.Notes
.Where(o => (t1.Item_ID == o.Item_ID))
select new ItemModel
{
Name = t1.Name,
MostRecentUpdate = t2.SubmittedDate <== Need max value in model
});
Any help would be greatly appreciated.
It looks like you probably just want a group join:
var items = from t1 in db.Items
join t2 in db.Notes on t1.Item_ID equals t2.Item_ID into notes
select new ItemModel
{
Name = t1.Name,
MostRecentUpdate = notes.Max(x => (DateTime?) x.SubmittedDate)
};
Now MostRecentUpdate should be null if there are no non-null dates in the matching Notes rows. At least, that's what the LINQ to Objects behaviour would be, so fingers crossed the abstraction holds...

Categories