LINQ Join with Group By - linq

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()
};

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 }

Inner join in Linq with more than 2 datatables

i have 3 tables
t1==>
t1.ID t1.co1 t1.col2
1 a b
2 a b
t2==>
t2.ID t2.co1 t2.col2
1 a b
2 a b
t3==>
t3.ID t3.co1 t3.col2
1 a b
2 a b
i want inner join between all three tables using Linq and want selected column in 4th datatable.
equivalent sql query:
SELECT t1.ID,t2.col1,t3.col2
FROM t1
INNER JOIN t2 ON t1.ID=t2.ID
INNER JOIN t3 ON t1.ID=t3.ID
t4==>
t1.ID t2.co1 t3.col2
1 a b
2 a b
Something like this
var Result =
from row1 in t1
join row2 in t2 on row1.ID equals row2.ID
join row3 in t3 on row1.ID equals row3.ID
select new { ID = row1.ID, Col1 = row2.col1, Col2 = row3.col2 }
DataTable dt = Result.CopyToDataTable();
Use LoadDataRow() to get a DataTable from an anonymous type as here. Else Result.CopyToDataTable().
//Get the column list as same as table1 to new datatable
DataTable table4 = table1.Clone();
var Result =
from x in t1.AsEnumerable() join
y in t2.AsEnumerable() on x.Field<int>("ID") equals y.Field<int>("ID") join
z in t3.AsEnumerable() on x.Field<int>("ID") equals z.Field<int>("ID")
select new table4.LoadDataRow(
new object[] {
x.ID,
y.col1,
z.col2
}, false);

GROUP BY and HAVING in linq

I want to convert this code to linq:
select t1.title, COUNT(*)as num
from t1 INNER join t2 on t2.gId = t1.Id
group by t1.title, t1.cId
having t1.cId = 2
I tried this below code:
from p in db.t1s join r in db.t2s on p.Id equals r.gId
where p.cId == 2
group p by p.title into g
select new{ name = from o in g select o.title, num = g.Count()}
But this doesn't return COUNT correctly.
please guide me how can I solve the problem
thanks
Without sample data its hard to get it right, but try this snippet
from p in db.t1s
join r in db.t2s on p.Id equals r.gId
where p.cId == 2
group p by new {p.title, p.cId} into grouped
select new{ name = grouped.Key.title, num = grouped.Count()}
Also, note that this sql:
select t1.title, COUNT(*)as num
from t1 INNER join t2 on t2.gId = t1.Id
group by t1.title, t1.cId
having t1.cId = 2
Will always return 1 as result of COUNT(*). The reason is that you have filtering t1.cId = 2 and grouping by t1.cId as second parameter.

multiple tables join by Linq

I have 3 tables which named Player, PlayerDetails and Team. I want to write a linq statement such as
from p in Player join d in PlayerDetails on p.ID equals d.PID
and then right join team table, Player has a column named TID which face to Team table's ID.
I have tried to write a statement like
from p in Player join d in PlayerDetails on p.ID equals d.PID into PlayerGroup
from t in team join g in PlayerGroup on t.ID equals g.p.ID
It certainly can't work. I'm not sure how to write such type of query statement, table left join table2 then right join table3.
Who can help?
I believe you could do something like this:
var LeftJoin =
from p in Player
join d in PlayerDetails on p.ID equals d.PID into pd
from d in pd.DefaultIfEmpty()
select new
{
pID = p.ID,
pTID = p.TID,
dID = d.ID
};
var RightJoin =
from t in Team
join l in LeftJoin on t.ID equals l.pTID into tl
from l in tl.DefaultIfEmpty()
select new
{
tID = t.ID,
pID = l.pID,
pTID = l.PTID,
dID = l.dID
};
To do everything in one query, I think you could do (not tested) something like this:
var RightJoin =
from t in Team
join l in
(from p in Player
join d in PlayerDetails on p.ID equals d.PID into pd
from d in pd.DefaultIfEmpty()
select new
{
pID = p.ID,
pTID = p.TID,
dID = d.ID
})
on t.ID equals l.pTID into tl
from l in tl.DefaultIfEmpty()
select new
{
tID = t.ID,
pID = l.pID,
pTID = l.PTID,
dID = l.dID
};

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