LINQ join two DataTables
This will let you default to 0 if the row doesn't exist in table2:
var result = from dataRows1 in table1.AsEnumerable()
join dataRows2 in table2.AsEnumerable()
on dataRows1.Field<string>("ID") equals dataRows2.Field<string>("ID") into lj
from r in lj.DefaultIfEmpty()
select dtResult.LoadDataRow(new object[]
{
dataRows1.Field<string>("ID"),
dataRows1.Field<string>("name"),
r == null ? 0 : r.Field<int>("stock")
}, false);
MSDN source
C# LINQ join two DataTables with a common field
The qry
is not executed. You need .CopyToDataTable()
to execute it.
qry.CopyToDataTable();
Sample program
How to use Linq to join multiple DataTables on multiple columns containing DBNull values
Linq will match DBNull.Value
to another DBNull.Value
correctly. I believe that was your question and not joining a second child table as this is trivial
DataTable parent = new DataTable();
parent.Columns.Add("Id1", typeof(string));
parent.Columns.Add("Id2", typeof(string));
DataRow r1 = parent.NewRow();
r1["Id1"] = "1";
r1["Id2"] = DBNull.Value;
parent.Rows.Add(r1);
DataRow r3 = parent.NewRow();
r3["Id1"] = "1";
r3["Id2"] = "2";
parent.Rows.Add(r3);
DataTable child1 = new DataTable();
child1.Columns.Add("Id1", typeof(string));
child1.Columns.Add("Id2", typeof(string));
child1.Columns.Add("BeginDate", typeof(DateTime));
child1.Columns.Add("SomeData", typeof(float));
DataRow r2 = child1.NewRow();
r2["Id1"] = "1";
r2["Id2"] = DBNull.Value;
child1.Rows.Add(r2);
DataRow r4 = child1.NewRow();
r4["Id1"] = "1";
r4["Id2"] = "2";
child1.Rows.Add(r4);
var dataToReturn =
from
p in parent.AsEnumerable()
join c1 in child1.AsEnumerable()
on new { Id1 = p["Id1"], Id2 = p["Id2"] }
equals new { Id1 = c1["Id1"], Id2 = c1["Id2"] }
select new
{
Id1 = p["Id1"],
Id2 = p["Id2"]
};
foreach(var l in dataToReturn)
{
Console.WriteLine(l.Id1 + "|" + l.Id2);
}
Console.ReadKey();
Output:
1|
1|2
LINQ two datatables join
(Untested code ahead.....)
var newRows = FirstDatatable.Rows
.Where(row =>SecondDatatable.Rows
.Any(secondRow => row["Por"] >= secondRow["FirstPor"]
&& row["Por"] <= secondRow["LastPor"]);
FinalDataTable.Rows.AddRange(newRows);
However, if speed is your real concern, my first suggestion is to dump the datatables, and use a list. I'm gonna gues that SecondDatatable, is largely fixed, and probabaly changes less than once a day. So, less create a nice in-memory structure for that:
class Range
{
public int FirstPor {get; set;}
public int LastPor {get; set;}
}
var ranges = (from r in SecondDatatable.Rows
select new Range
{
FirstPor = Int32.Parse(r["FirstPor"]),
LastPor = Int32.Parse(r["LastPor"])
}).ToList();
Then our code becomes:
var newRows = FirstDatatable.Rows
.Where(row =>ranges
.Any(range => row["Por"] >= range.FirstPor
&& row["Por"] <= range.LastPor).ToList();
Which by itself should make this considerably faster.
Now, on a success, it will scan the Ranges up until it finds one that matches. On a failure, it will have to scan the whole list before it gives up. So, the first thing we need to do to speed this up, is to sort the list of ranges. Then we only have to scan up to the point where the low end of the range it higher than the value we are looking for. That should cut the processing time for those rows outside any range in half.
Using LINQ to JOIN two datatables using two key columns
var list1 = (from t1 in dataTable1.AsEnumerable()
select new
{
Key1 = t1.Field<int>("Key1"),
Key2 = t1.Field<int>("Key2"),
A = t1.Field<string>("A"),
B = t1.Field<string>("B")
});
var list2 = (from b in dataTable2.AsEnumerable()
select new
{
Key1 = b.Field<int>("Key1"),
Key2 = b.Field<int>("Key2"),
X = b.Field<string>("X"),
Y = b.Field<string>("Y")
});
// Now join the 2 collections and get the result you want.
var result = (from x in list1
join y in list2 on new { x.Key1,x.Key2} equals new { y.Key1,y.Key2 }
select new { A = x.A, X = y.X }).ToList();
Assuming Key1 and Key2 are int
type and A.B,X and Y are of string
type.
Inner Join Two Datatable using Linq without having relation with another table
Here
select * from table1 Inner join table2 on table2.id in (1,2,3)
technically speaking, table2.id in (1,2,3)
is just a filter (where
), and there is no Inner Join
, but Cross Join, i.e. no join (relation) between the tables, but Cartesian product of the two.
So it really is something like this
select * from table1, table2 where table2.id in (1,2,3)
hence translating it to LINQ could be like this
var t2Filter = new HasSet<int>(new int[] { 1, 2, 3});
var result = (
from t1 in table1.AsEnumerable()
from t2 in table2.AsEnumerable()
where t2Filter.Contains(t2.Field<int>("id"))
select new
{
ID = t1.Field<int>("ID")
// ...
}
).ToList();
Use .Select().Join() to Join Two DataTables
I typically accomplish this by building an anonymous object that contains a reference to my source and destination objects through a Join or GroupJoin, then looping over the result of the Join to update my destination object. See the example below.
Take a look at the documentation on Join and GroupJoin. Join is great for a 1-1 match, while GroupJoin is a 0-* match (like a SQL left join). The arguments to Join and GroupJoin allow you to specify a selector function for each IEnumerable followed by a selector function for the output object. Note that t1
and t2
below refer to table1
and table2
.
using System;
using System.Data;
using System.Linq;
public class Program
{
public static void Main()
{
var table1 = GetEmptyTable();
table1.Rows.Add(1, "Old Value", false);
table1.Rows.Add(2, "Untouched Value", false);
var table2 = GetEmptyTable();
table2.Rows.Add(1, "New Value", false);
table2.Rows.Add(3, "Unused Value", false);
Console.WriteLine("Before...");
Console.WriteLine(PrintTable(table1));
var matched = table1.Select()
.Join(table2.Select(), t1 => (int)t1["A"], t2 => (int)t2["A"], (t1, t2)
=> new
{
DestinationRow = t1,
SourceRow = t2
});
foreach (var match in matched)
{
match.DestinationRow["B"] = match.SourceRow["B"];
match.DestinationRow["C"] = true;
}
Console.WriteLine("After...");
Console.WriteLine(PrintTable(table1));
}
private static DataTable GetEmptyTable()
{
var table = new DataTable();
table.Columns.Add("A", typeof(int));
table.Columns.Add("B", typeof(string));
table.Columns.Add("C", typeof(bool));
return table;
}
private static string PrintTable(DataTable table)
{
return string.Join(Environment.NewLine, table.Select().Select(x => "[" +
string.Join(", ", x.ItemArray) + "]"));
}
}
Related Topics
Most Efficient Way to Insert Rows into MySQL Database
How Much Memory Does a C#/.Net Object Use
What Is the Impact of Thread.Sleep(1) in C#
How to Treat the Circle as a Control After Drawing It? - Moving and Selecting Shapes
Validation Error Style in Wpf, Similar to Silverlight
Differencebetween Bool and Boolean Types in C#
How to "Kill" Background Worker Completely
Webclient Accessing Page with Credentials
How to Return Anonymous Type from C# Method That Uses Linq to SQL
How to Get the File Size in C#
How to Draw Directly on the Windows Desktop, C#
Authorization Header Is Lost on Redirect
Is There a Lower Bound Function on a Sortedlist<K ,V>
How to Restrict/Control the Navigation Routes the User Can Visit Based on Login Status/Role
Best Practice to Make a Multi Language Application in C#/Winforms