linq join tables with multiple columns with or condition - linq

I want to join 3 tables. From which two tables join with multiple columns by "or" condition then join 3rd table to the result of first two.
example as below:
from t1 in db.table1
from t2 in db.table2
where (t1.ISIN == t2.ISIN_GrowthDiv || t1.ISIN==t2.ISIN_DivReinv)
join t3 in table3 on t2.SchemeID equals t3.SchemeId
now tell me above query is correct or not?

Since you don't show your select clause, I will do a sample select; of course replace it with your own.
I have also created sample data, as you said you can't share yours, and stored in table1, table2 and table3:
var table1 = new List<Table1>()
{
new Table1() { ISIN = 1 },
new Table1() { ISIN = 4 }
};
var table2 = new List<Table2>() {
new Table2() { ISIN_DivReinv = 0, ISIN_GrowthDiv = 1, SchemeID = 111 },
new Table2() { ISIN_DivReinv = 1, ISIN_GrowthDiv = 0, SchemeID = 111 },
new Table2() { ISIN_DivReinv = 1, ISIN_GrowthDiv = 0, SchemeID = 222 },
new Table2() { ISIN_DivReinv = 2, ISIN_GrowthDiv = 2, SchemeID = 111 }
};
var table3 = new List<Table3>()
{
new Table3() { SchemeId = 111 },
new Table3() { SchemeId = 333 }
};
var Result =
from t1 in table1
from t2 in table2
where (t1.ISIN == t2.ISIN_GrowthDiv || t1.ISIN == t2.ISIN_DivReinv)
join t3 in table3 on t2.SchemeID equals t3.SchemeId
select new { t1.ISIN, t2.ISIN_DivReinv, t3.SchemeId };
These are the results I'm getting:
As you can see, there's no cross-join; which is not surprising, since by default LINQ provides inner joins with the join operator and the only way to get cross joins is to just select without join, like in this answer.
EDIT: WHAT IF T3.SCHEMEID HAS DUPLICATES?
A "special" case is when t3 contains duplicated values, e.g. like
var table3 = new List<Table3>()
{
new Table3() { SchemeId = 111 },
new Table3() { SchemeId = 111 }
};
In this case you will get 4 rows instead of 2, since the inner join will properly occur for the two rows of t2 twice, one per matching value of t3.
This doesn't make it a "cross-join" anyway, but you can take distinct values of t3.SchemeId if your select doesn't need values from t3:
var Result =
from t1 in table1
from t2 in table2
from t3 in table3.Select(f => f.SchemeId).Distinct()
where (t1.ISIN == t2.ISIN_GrowthDiv || t1.ISIN == t2.ISIN_DivReinv) & t3 == t2.SchemeID
select new { t1.ISIN, t2.ISIN_DivReinv, t2.SchemeID };

Related

Join Linq column with minimum value column

I have to join outer table column with inner table minimum value column
Here is my sql query:
SELECT O.Id, O.Name, O.Designation
FROM TableA AS O INNER JOIN
(SELECT MIN(SrNo) AS A_SNo, Id
FROM TableA
WHERE (Active = 1)
GROUP BY Id) AS I ON O.Id = I.Id AND O.SrNo = I.A_SNo AND O.Active = 1
I have tried this:
from tres in TableA join O in
(from tresp in TableA
where tresp.Active == true
group tresp by new { tresp.Id } into G
select new { Id = G.Key.Id, A_Sno =(int?)G.Min(X=>X.SrNo)}
) on new {tres.Id,a=(int?)tres.SrNo } equals new {O.Id,a=O.A_Sno } into tresss
where (tres.Active==true)
select new { tres.Id, tres.Name, tres.Designation }
in sql query I'm not getting duplicate rows but when i tried this in linq getting duplicate rows
try
from tres in TableA join O in
(from tresp in TableA
where tresp.Active == true
group tresp by new { tresp.Id } into G
select new { Id = G.Key.Id, A_Sno =(int?)G.Min(X=>X.SrNo)}
) on new {tres.Id,a=(int?)tres.SrNo } equals new {O.Id,a=O.A_Sno }
where (tres.Active==true)
select new {tres.Id,tres.Name,tres.Designation} into tresss
select new { tresss.Id, tresss.Name, tresss.Designation }

How do I convert this query into LINQ?

SELECT *
FROM
ProcedureLookup ProcLookup
INNER JOIN (SELECT PatientProcedures.PP_ProcedureId, COUNT(*) as ProcCount
FROM (PatientProcedures INNER JOIN Treatments ON PatientProcedures.PP_TreatmentId = Treatments.TS_TreatmentId)
WHERE YEAR(Treatments.TS_Date) = YEAR(GETDATE())
GROUP BY PatientProcedures.PP_ProcedureId) cyearProc ON ProcLookup.PL_ProcedureId = cyearProc.PP_ProcedureId
ORDER BY ProcCount DESC;
Here ProcedureLookup, Treatments, PatientProcedures are the tables.
Here linq query.
var result = (from ProcLookup in db.ProcedureLookup
join cyearProc in (
from p in db.PatientProcedures
join t in db.Treatments on p.PP_TreatmentId equals
t.TS_TreatmentId
where
t.TS_Date.Year == DateTime.Now.Year
group p by p.PP_ProcedureId into g
select new
{
PP_ProcedureId = g.Key,
ProcCount = g.Count()
}
) on ProcLookup.PL_ProcedureId equals
cyearProc.PP_ProcedureId
orderby cyearProc.ProcCount descending
select new
{
// Columns
PP_ProcedureId = ProcLookup.PP_ProcedureId,
ProcCount = cyearProc.ProcCount
}).ToList();

LINQ Join with Group By

I have a table structure like following
Table_A
Id Description
1 A
2 B
3 C
4 D
Table_B
Table_A_Id Id Description
1 1 A
1 2 B
2 3 C
2 4 D
3 5 E
3 6 F
4 7 G
4 8 H
4 9 I
4 10 J
I want to JOIN them in a way to get List of following Class
Public Resultset
{
public Table_A table_a {get;set;}
public List<Table_B> table_b {get;set;}
}
// suppose we have classes for Table_A and Table_B as per their table definition
Following is my try
var filter [] = {1,3,5};
var query = from a in context.Table_A
joins b in context.Table_B
on a.Id equals b.Table_A_id
where filter.Contains(b.Id)
// Need something here perhaps to group it to get desired results
Select new ResultSet()
{
// what to do here
}
You can try the following group by:
var query = from a in context.Table_A
joins b in context.Table_B
on a.Id equals b.Table_A_id
where filter.Contains(b.Id)
group new{A=a, B=b } by a.Id into g
select new ResultSet()
{
table_a=g.FirstOrDefault().A,
table_b=g.Select(e=>e.B).ToList()
};
Another way if you were using navigation properties between those entities:
var query = from b in context.Table_B
where filter.Contains(b.Id)
group b by b.Table_A_id into g
select new ResultSet()
{
table_a=g.FirstOrDefault().A,
table_b=g.ToList()
};
I think you need a simple Group Join:
var filter = new [] { 1, 3, 5 };
var query = from a in context.Table_A
join b in (from b in context.Table_B where filter.Contains(b.Id) select b)
on a.Id equals b.Table_A_id into items_B
select new ResultSet
{
table_a = a,
table_b = items_B.ToList()
};

LINQ Join Where Clause

I'm struggling with a join/where clause with what is a rather simple sql select statement.
I am trying to retrieve a list of product information from tb1 with the where condition behind situated in tbl2 but this must be joined by three different columns.
so the SQL would look something along the lines of:
SELECT tb1.*
FROM tb2 INNER JOIN
tb1 ON tb2.Col1 = tb1. Col1 AND tb2.Col2 = tb1. Col2 AND
tb2.Col3 = tb1.Col3
WHERE (tb2.Col1 = col1) AND (tb2.Col2 = col2) AND (tb2.Col4 = string)
ColX is the main where clause with the string to be passed in as parameter; all other columns are within the contexts.
How do you implement multiple joins with a where clause?
And shoves in the right direction, muchly appreciated.
To join on multiple field in LINQ, you have to create a new anonymous type containing the columns you want to compare and then use that anonymous type in the join:
var results = from t1 in context.tb1
join t2 in context.tb2
on new { t1.Col1, t1.Col2, t1.Col3 } equals
new { t2.Col1, t2.Col2, t2.Col3 }
where t2.Col1 == col1 && t2.Col2 == col2 && t2.Col4 == someString
select t1;
And here is the equivalent Lambda Syntax:
var results = context.tb1.Join(
context.tb2,
t1 => new { t1.Col1, t1.Col2, t1.Col3 },
t2 => new { t2.Col1, t2.Col2, t2.Col3 },
(t1, t2) => new { t1, t2 })
.Where(o => o.t2.Col1 == col1
&& o.t2.Col2 == col2
&& o.t2.Col4 == someString)
.Select(o => o.t1);
As you can see, in the case of joins, query syntax usually produces an easier to read statement.
You can also include the WHERE clause in lamda syntax in the reference to the table you're joining on.
var query = from pt in dc.ProjectTasks
join ttab in dc.TimeTaskAssigns on pt.Id equals ttab.ProjectTaskId
join ttb2 in dc.CMS_TAT_TIMEs.Where(a => a.WIP_STATUS == 'B') on ttab.CmsTimeUno equals ttb2.TIME_UNO
select pt;
Seems obvious now, doesn't it? It took me a long time to find that solution.
Also you can group result and use subquery
var innerGroupJoinQuery2 =
from category in categories
join prod in products on category.ID equals prod.CategoryID into prodGroup
from prod2 in prodGroup
where prod2.UnitPrice > 2.50M
select prod2;
ref.: join clause (C# Reference)

Group by Multiple Columns and Count

I have Table1 and Table2 in the form of IEnumerable<DataRow>. Both the tables have columns Column1 and Column2.
I would like to do a left outer join on Column1 and would like to get a count of the rows present in Table2 and load the records into a DataTable.
I tried the following query
var query = from p in Table1
join q in Table2 on p.Field<string>("Column1") equals q.Field<string>("Column1") into pq
from xyz in pq.DefaultIfEmpty()
group xyz by new { Col1 = p.Field<string>("Column1"), Col2 = p.Field<string>("Column2") } into g
select dtFinalData.LoadDataRow(new object[]
{
g.Key.Col1,
g.Key.Col2,
g.Count
}, false);
Since the 'g' represents the grouped data the g.count returns 1 for rows which does not have entries in Table 2. I would like to return '0' for those rows.
Input :
Table 1
Col1Val1 Col2Val1
Col1Val2 Col2Val2
Table 2
Col1Val1 Col2Val1
Col1Val1 Col2Val1
Current Output :
Col1Val1 Col2Val1 2
Col2Val2 Col2Val2 1
Expected Results :
Col1Val1 Col2Val1 2
Col2Val2 Col2Val2 0
I have looked at LINQ - Left Join, Group By, and Count but I could not apply the same into my query ...
Can you help me fix this query ?
let it be so:
from p in Table1
let p1 = p.Field<string>("Column1")
let p2 = p.Field<string>("Column2")
let qs =
from q in Table2
where p1 == q.Field<string>("Column1")
select q
let qCount = qs.Count()
select dtFinalData.LoadDataRow(new object[]
{
p1,
p2,
qCount
}, false);
Since I didn't join, I don't have to group. Each result row corresponds to a row in Table1.
Here's a GroupJoin solution:
from p in Table1
let pkey = new { c1 = p.Field<string>("Column1"), c2 = p.Field<string>("Column2") }
join q in Table2 on pkey equals
new { c1 = q.Field<string>("Column1"), c2 = q.Field<string>("Column2") }
into qs
select dtFinalData.LoadDataRow(new object[]
{
pkey.c1,
pkey.c2,
qs.Count()
}, false);
And here's a Join and Group solution.
from p in Table1
let pkey = new { c1 = p.Field<string>("Column1"), c2 = p.Field<string>("Column2") }
join q in Table2 on pkey equals
new { c1 = q.Field<string>("Column1"), c2 = q.Field<string>("Column2") }
into right
from q in right.DefaultIfEmpty()
group q by pkey into g
select dtFinalData.LoadDataRow(new object[]
{
g.Key.c1,
g.Key.c2,
g.Count(q => q != null)
}, false);

Resources