Left outer join of 2 datatables - c#

I want to left join 2 data tables AllTimesTxnTable and resolvedDt in C#, Where I want every row from AllTimesTxnTable and only matching rows from resolvedDt.
The join condition should be based on mid and txndate and finally while selecting I want mid and txndate from AllTimesTxnTable and txncount from resolvedDt, if no record in resolvedDt then a 0.
I tried the following LINQ query:
var results = from table2 in AllTimesTxnTable.AsEnumerable()
join table1 in resolvedDt.AsEnumerable()
on new { mid = table2.Field<int>("mid"), txndate = table2.Field<string>("txndate") } equals new { mid = table1.Field<int>("mid"), txndate = table1.Field<string>("txndate") }
into temp
from leftTable in temp.DefaultIfEmpty()
select new
{
MId = (int)table2["mid"],
TxnDate = (string)table2["txndate"],
TxnCount = leftTable["txncount"] == null ? 0M : (decimal)leftTable["txncount"]
};
But it gives me an Error: Object reference not set to an instance of an object. while selecting.
Not getting whats going wrong here.

Updated the code. Its working now.
var results = from table2 in AllTimesTxnTable.AsEnumerable()
join table1 in resolvedDt.AsEnumerable()
on new { mid = table2.Field<int>("mid"), txndate = table2.Field<string>("txndate") } equals new { mid = table1.Field<int>("mid"), txndate = table1.Field<string>("txndate") }
into temp
from row in temp.DefaultIfEmpty()
select new
{
MId = (int)table2["mid"],
TxnDate = (string)table2["txndate"],
TxnCount = row == null ? 0M : (decimal)row["txncount"]
};

Related

How to linq join if datatable doesn't have all the rows

I'm having an issue where I'm getting nothing back. Here is my code:
var final = (from table1 in dtS.AsEnumerable()
join table2 in DataDT.AsEnumerable()
on table1.Field<string>(1) equals table2.Field<string>(0)
join table3 in DataDT2.AsEnumerable()
on table1.Field<string>(1) equals table3.Field<string>(0)
join table4 in DataDT3.AsEnumerable()
on table1.Field<string>(1) equals table4.Field<string>(0)
select new Model
{
TestID = table1.Field<int>(0),
ID = table1.Field<string>(1),
Name = table1.Field<string>(2),
Absent = table1.Field<bool>(3),
Gender = table1.Field<string>(4),
Grade = table1.Field<int>(5),
TestDate = table1.Field<string>(7),
SessionNumber = table1.Field<int>(8),
Room = table1.Field<string>(9),
Code = table1.Field<string>(10),
Booklet = table1.Field<string>(11),
Color = table4.Field<string>(3),
Accomm = table3.Field<string>(1),
SID = table2.Field<string>(1),
LocalName = table2.Field<string>(2)
}).ToList();
If I comment out the last two joins and "Color, Accomm, SID and Local" . I seem to get all of my info.
table1 has 300 rows. This has all the people
table2 has 1000 rows. Has some extra data I need to add
table3 has 10. Has some extra data that I need to add (but doesn't have everyone)
table4 has 17. Has some extra data that I need to add (but doesn't have everyone)
Doesn't seem to "Linq" up (drums). Thanks for the help. I know I'm over thinking something..
Thanks to #Marcus Hoglund for pointing out the outer join. I was able to make some changes and it's working.
Here you go:
var final = (from studData in dtS.AsEnumerable()
join table2 in DataDT.AsEnumerable() on studData[1] equals table2[0] into part1
from p1 in part1.DefaultIfEmpty()
join table3 in DataDT2.AsEnumerable() on studData[1] equals table3.Field<string>(0) into part2
from p2 in part2.DefaultIfEmpty()
join table4 in DataDT3.AsEnumerable() on studData[1] equals table4.Field<string>(0) into part3
from p3 in part3.DefaultIfEmpty()
select new Model
{
TestID = table1.Field<int>(0),
ID = table1.Field<string>(1),
Name = table1.Field<string>(2),
Absent = table1.Field<bool>(3),
Gender = table1.Field<string>(4),
Grade = table1.Field<int>(5),
TestDate = table1.Field<string>(7),
SessionNumber = table1.Field<int>(8),
Room = table1.Field<string>(9),
Code = table1.Field<string>(10),
Booklet = table1.Field<string>(11),
Color = (p3 == null) ? "" : p3[1],
Accomm = (p2 == null) ? "" : p2[1],
SID = (p1 == null) ? "" : p1[1],
LocalName = (p1 == null) ? "" : p1[2],
}).ToList();

LEFT JOIN query with Entity Framework Core

I did a lot of research and read some of the similar questions and answers, but still have no clue how to write the EF Core code to create the following SQL server query. Can someone help. I have seen tutorials explaining how to join 2 tables with LEFT JOIN, but couldn't find any that includes 3 or more tables.
SELECT std.DocID, std.ServiceCode,
CASE std.Description
WHEN 'Car Wash'
THEN 'Misc'
ELSE std.Description
END AS 'Description',
std.StandardRate, std.StandardHours,
det.ParticipantCount, det.TotalHours, det.TotalFees
FROM StandardServices std
INNER JOIN Sorted srt
ON std.ServiceCode = srt.ServiceCode
LEFT OUTER JOIN ServiceDetails det
ON det.ParentRecordUNID='00000000-0000-0000-0000-000000000000' AND det.ServiceTypeUNID=std.DocID
WHERE std.IsDeleted='N' AND std.TopService = 'Y'
ORDER BY srt.SortOrder
Following is what came close to the above (I have replaced some text for privacy concerns, so may not exactly match). But for some reasons, it selects all of the columns than what is mentioned. Also, it adds a (SELECT 1) at the end.
var results=await (from sso in context.StandardServices
join mos in context.Sorted on sso.ServiceCode equals mos.ServiceCode
join mad in context.ServiceDetails
on new { key1 = sso.DocID, key2 = parentId } equals new { key1 = (Guid)mad.ServiceTypeUnid, key2 = mad.ParentRecordUnid }
into jointable
where sso.IsDeleted == "N" && sso.TopService =="Y"
orderby mos.SortOrder
from mad1 in jointable.DefaultIfEmpty()
select new ServiceRowDetails()
{
DocID = mad1.DocID,
ParentRecordUnid = mad1.ParentRecordUnid,
ServiceTypeUnid = sso.DocID,
ServiceType = sso.Description,
ParticipantCount = mad1.ParticipantCount ?? 0,
StandardFees = sso.StandardRate ?? 0,
StandardHours = sso.StandardHours ?? 0,
TotalFees = mad1.TotalFees ?? 0,
TotalHours = mad1.TotalHours ?? 0
}).ToListAsync();
UPDATE: Made changes as #IvanStoev commented below and it worked just fine.
var results=await (from sso in context.StandardServices
join mos in context.Sorted on sso.ServiceCode equals mos.ServiceCode
join mad in context.ServiceDetails
on new { key1 = sso.DocID, key2 = parentId } equals new { key1 = (Guid)mad.ServiceTypeUnid, key2 = mad.ParentRecordUnid }
into jointable
from mad1 in jointable.DefaultIfEmpty()
where sso.IsDeleted == "N" && sso.TopService =="Y"
orderby mos.SortOrder
select new ServiceRowDetails()
{
DocID = mad1.DocID,
ParentRecordUnid = mad1.ParentRecordUnid,
ServiceTypeUnid = sso.DocID,
ServiceType = sso.Description,
ParticipantCount = mad1.ParticipantCount ?? 0,
StandardFees = sso.StandardRate ?? 0,
StandardHours = sso.StandardHours ?? 0,
TotalFees = mad1.TotalFees ?? 0,
TotalHours = mad1.TotalHours ?? 0
}).ToListAsync();

SQL Query to LINQ C# [Joining multiple table]

I am working on this query in my sql server
select a.care_type_id, a.description,
isChecked = case when b.care_type_id is null then 'false' else 'true' end
from caretype a
left join patientinsurancetacitem b on a.care_type_id = b.care_type_id and
b.tac_id = 1
I want to translate the query into LINQ. However, I am having trouble with the and operator. I have this code so far;
from a in context.CareTypes
join b in context.PatientInsuranceTACItems on a.care_type_id equals
b.care_type_id into x
from xx in x.Where(w => w.tac_id == 1).DefaultIfEmpty()
select new {
isChecked = (b.care_type_id == null ? false : true),
care_type_id = a.care_type_id,
description = a.description}
And, also, I cannot get the b that I equated in isChecked variable. From where will I start modifying in order to get the same result as my sql query? In where I got it wrong?
Try this
from a in context.caretype
join b on context.patientinsurancetacitem
on new { CA = a.care_type_id, CB = 1} equals
new { CA = b.care_type_id, CB = b.tac_id}
into tmp from b in tmp.DefaultIfEmpty()
select new
{
care_type_id = a.care_type_id,
description = a.description,
checked = (b != null) // Or ((b == null) ? false : true)
}
Also check this StackOverflow answer.
The very simple example about joining on multiple columns is ;
from x in entity1
join y in entity2
on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }

Converting an SQL Containing inner and Outer Joins into Linq

I need to convert an SQL query to Linq/Lambda expression, I am trying doing the same but not getting the desired results.
SQL:
SELECT b.*, n.notes
FROM Goal_Allocation_Branch as b
INNER JOIN Goal_Allocation_Product as g
on b.Product = g.ProductID
and b.Year = g.Year
left join Goal_Allocation_Branch_Notes as n
on b.branchnumber = n.branch
and n.year = ddlYear
WHERE b.Year = ddlYear
and g.Show = 1
and branchnumber = ddlBranch
I am new to Linq , I am getting error on Join Clause , and X is not containing any data from first Join
var result = (from br in _DB_Branches.Goal_Allocation_Branches
join pr in _DB_Product.Goal_Allocation_Products on new { br.Product, br.Year } equals new {Product= pr.ProductID, Year= pr.Year }
join n in _DB_Notes.Goal_Allocation_Branch_Notes.Where(n => n.Year == ddlYear) on br.BranchNumber equals n.Branch into Notes
from x in Notes.DefaultIfEmpty()
select new BranchNotesViewModel
{
Year = x.Year,
BranchNumber = x.Branch,
ProductID = x.ProdID
}
).ToList();
Update: My First Join clause initially giving error "The type of one of the expression in Join Clause is incorrect " is resolved, when I Changed On Clause
from
"on new { br.Product, br.Year } equals new {pr.ProductID, pr.Year}"
"on new { br.Product, br.Year } equals new {Product=pr.ProductID,Year= pr.Year}"
still not getting desired results as expected from above SQL query. Please advise..
It should be something like this (see note):
var result =
(from br in _DB_Branches.Goal_Allocation_Branches
join pr in _DB_Product.Goal_Allocation_Products
on br.Product equals pr.ProductID
from n in _DB_Notes.Goal_Allocation_Branch_Notes.Where(x=>
x.branch == br.branchnumber
&& x.year == ddlYear
).DefaultIfEmpty()
where
br.Year == ddlYear
&& and br.Year == pr.Year
&& pr.Show == 1
&& br.branchnumber == ddlBranch
select new BranchNotesViewModel
{
Year = ...,
BranchNumber = ...,
ProductID = ...
}
).ToList();
Note: Change the select, to the properties you want.
Edit: fixed some syntax errors.
I finally figured out the correct answer. Working absolutely fine
var result = (from br in _DB_Branches.Goal_Allocation_Branches
join pr in _DB_Product.Goal_Allocation_Products on new { br.Product, br.Year } equals new { Product = pr.ProductID, Year = pr.Year }
join n in _DB_Notes.Goal_Allocation_Branch_Notes.Where(n=>n.Year==ddlYear) on br.BranchNumber equals n.Branch into Notes
where br.Year==ddlYear
&& pr.Show== true
&& br.BranchNumber==ddlBranch
from x in Notes.DefaultIfEmpty()
select new BranchNotesViewModel
{
Year=x.Year,
BranchNumber=x.Branch,
ProductID=br.Product,
Notes = x.Notes,
//All other fields needed
}
).ToList();

How to write Outer Join using LINQ

I am using the below Inner Join to retrive the Data between the two tables, but all data is not getting populated. I tried implementing Outer join by connecting using CCY1== CCY1 and PCODE == PCODE, but no luck.
var q = from g1 in TableCCY1.AsEnumerable()
join g2 in TableCCY2.AsEnumerable()
on g1.Field<string>("CCY1") equals g2.Field<string>("CCY1")
where g1.Field<string>("PCODE") == g2.Field<string>("PCODE")
select new
{
g1currency = g1.Field<string>("CCY1"),
g2currency = g2.Field<string>("CCY1"),
g1code = g1.Field<string>("PCODE"),
g2code = g2.Field<string>("PCODE"),
g1Amt1 = g1.Field<string>("AMT1"),
g2Amt2 = g2.Field<string>("AMT2")
};
Thanks for your help.
For left join you can use this approuch: http://msdn.microsoft.com/en-us/library/vstudio/bb397895.aspx
The code should be:
var q = from g1 in TableCCY1
join g2 in TableCCY2 on g1.CCY1 equals g2.CCY1 && g1.PCODE equals g2.PCODE into TableCCY3
from g3 in TableCCY3.DefaultIfEmpty()
select new
{
g1currency = g1.CCY1,
g2currency = (g3 == null ? String.Empty : g3.CCY1),
g1code = g1.PCODE,
g2code = (g3 == null ? String.Empty : g3.PCODE),
g1Amt1 = g1.AMT1,
g2Amt2 = (g3 == null ? 0 : g3.AMT2)
};
It looks like you just want to union/concat the two tables into one and then just group on those two columns. You're not logically joining the two tables. That actually makes it much easier.
var q = from row in TableCCY1.AsEnumerable().Concat(TableCCY2.AsEnumerable())
group row by new
{
CCY1 = row.Field<string>("CCY1"),
PCode = row.Field<string>("PCODE")
} into matches
select new
{
CCY1 = matches.Key.CCY1,
PCODE = matches.Key.PCode,
Sum = matches.Sum(match => match.Field<decimal?>("AMT2")),
};

Categories

Resources