How to check a dataset belongs to another dataset - c#

I have one dataset which contains Student Fee Structure of a single FeeID as mentioned below:
FeeID Amount FeeItem Type
*---------------------------------------------*
10 7500 Admission Fee T
10 900 Annual Fee T
10 150 Application Fee T
10 850 Boy's Uniform T
10 50 Computer Fee R
For example I have another dataset having following data:
FeeID Amount FeeItem Type
*---------------------------------------------*
9 8500 Admission Fee T
9 950 Annual Fee T
9 150 Application Fee T
9 850 Boy's Uniform T
9 50 Computer Fee R
11 7500 Admission Fee T
11 900 Annual Fee T
11 150 Application Fee T
11 850 Boy's Uniform T
11 50 Computer Fee R
I want to check whether the set comprising of last three columns belongs to another dataset that contains data of all Fee Structures where FeeID may vary. Actual I want to retrieve matching FeeID having same Fee Structure.
In the above example if I search for the first one in the second it will return True and matching FeeID will be 11.

You can use this trick
Dataset ds1
DataSet ds2
DataSet dest;
dest.Merge(ds1);
dest.AcceptChanges();
dest.Merge(ds2);
diff = destination.GetChanges()
and check if diff is empty

Edit: I've made ade some improvements to below code. Following DataTable.IndexOf(otherTable) extension method checks if a table is a subset of another table.
You can pass column names that you want to ignore in the comparison. The order of the columns does not matter but the order of DataRows(the subset must have the same order of rows).
It returns -1 when no equal subset of DataRows was found or the first index in the main-table(this in the extension) where the equal subset starts.
public static class DataTableExtensions
{
public static int IndexOf(this DataTable tblMain, DataTable tblSub, params String[] ignoreColumns)
{
if (tblMain == null)
throw new ArgumentNullException("tblMain");
if (tblSub.Rows.Count == 0)
throw new ArgumentException("tblSub must not be empty", "tblSub");
if (tblSub.Rows.Count > tblMain.Rows.Count)
return -1;
IEnumerable<String> relevantColumnNames = tblSub.Columns.Cast<DataColumn>()
.Select(c => c.ColumnName)
.Except(ignoreColumns)
.ToArray();
foreach (String colName in relevantColumnNames)
if (!tblMain.Columns.Contains(colName))
return -1;
for (int mainRowIndex = 0; tblMain.Rows.Count - mainRowIndex >= tblSub.Rows.Count; mainRowIndex++)
{
// check if current window is equal to tblSub
bool allRowsAreEqual = true;
for (int windowIndex = mainRowIndex; windowIndex < tblSub.Rows.Count + mainRowIndex; windowIndex++)
{
DataRow currentMain = tblMain.Rows[windowIndex];
DataRow currentSub = tblSub.Rows[windowIndex - mainRowIndex];
bool allFieldsAreEqual = relevantColumnNames.All(colName =>
Object.Equals(currentMain[colName], currentSub[colName]));
if (!allFieldsAreEqual)
{
allRowsAreEqual = false;
break; // continue with next window in main-table
}
}
if (allRowsAreEqual)
return mainRowIndex;
}
// no equal window found in main-table
return -1;
}
}
Your sample data:
var TblSub = new DataTable();
var TblMain = new DataTable();
TblSub.Columns.Add("FeeID", typeof(int));
TblSub.Columns.Add("Amount", typeof(int));
TblSub.Columns.Add("FeeItem", typeof(string));
TblSub.Columns.Add("Type", typeof(char));
TblMain.Columns.Add("FeeID", typeof(int));
TblMain.Columns.Add("Amount", typeof(int));
TblMain.Columns.Add("FeeItem", typeof(string));
TblMain.Columns.Add("Type", typeof(char));
TblSub.Rows.Add(10, 7500, "Admission Free", 'T');
TblSub.Rows.Add(10, 900, "Annual Fee", 'T');
TblSub.Rows.Add(10, 150, "Application Free", 'T');
TblSub.Rows.Add(10, 850, "Boy's Uniform", 'T');
TblSub.Rows.Add(10, 50, "Computer Free", 'R');
TblMain.Rows.Add(9, 8500, "Admission Free", 'T');
TblMain.Rows.Add(9, 950, "Annual Fee", 'T');
TblMain.Rows.Add(9, 150, "Application Free", 'T');
TblMain.Rows.Add(9, 850, "Boy's Uniform", 'T');
TblMain.Rows.Add(9, 50, "Computer Free", 'R');
TblMain.Rows.Add(10, 7500, "Admission Free", 'T');
TblMain.Rows.Add(11, 900, "Annual Fee", 'T');
TblMain.Rows.Add(11, 150, "Application Free", 'T');
TblMain.Rows.Add(11, 850, "Boy's Uniform", 'T');
TblMain.Rows.Add(11, 50, "Computer Free", 'R');
You can use it in this way:
int firstIndex = TblMain.IndexOf(TblSub, "FeeID");
if (firstIndex == -1)
Console.Write("Second table does not contain first table");
else
Console.Write("Second table does contain first table at row-index " + firstIndex);
Output is:
Second table does contain first table at row-index 5
old approach:
You could use following method which checks whether or not two DataTables are equal.
You need to add using System.Linq for Enumerable.SequenceEqual. If you cannot use Linq, use loops.
static bool TablesEqual(DataTable table1, DataTable table2, params int[] skipColumns)
{
if (table1.Rows.Count != table2.Rows.Count)
return false;
for (int i = 0; i < table1.Rows.Count; i++)
{
var array1 = table1.Rows[i].ItemArray
.Where((obj, index) => !skipColumns.Contains(index));
var array2 = table2.Rows[i].ItemArray
.Where((obj, index) => !skipColumns.Contains(index)); ;
if (!array1.SequenceEqual(array2))
{
return false;
}
}
return true;
}
You just have to pass the indices of the columns you want o ignore, like:
bool allEqual = TablesEqual(t1, t2); // all equal
bool equalIgnore0 = TablesEqual(t1, t2, 0); // ignore first column
bool equalIgnore0and2 = TablesEqual(t1, t2, 0, 2); // ignore first and third column

Finally I am able to solve this issue. The following is my function. I am using the function TablesEqual as provided by Tim Schmelter. The function will return a valid FeeID which is a positive integer else -1 if no match is found.
private int MatchFeeID(DataTable Dt)
{
DataTable mainDt = bl.GetDataSet("Select * From FeeMaster"); //assume this is a function that will return all the fee structures from database.
var fids = (from row in mainDt.AsEnumerable().Distinct()
group row by row.Field<string>("fid") into rowGroup
select new
{
fid = rowGroup.Key
});
foreach (var fid in fids)
{
string id = fid.fid;
DataTable t1 = new DataTable();
DataTable t2 = new DataTable();
DataRow[] dr1 = mainDt.Select(String.Format("fid = '{0}'", id));
t1 = dr1.CopyToDataTable();
t2 = Dt;
bool res = TablesEqual(t1, t2, 0, 1);
if (res) return Convert.ToInt32(id);
}
return -1;
}

Related

Rounding to 2 decimal points a DataTable based NuGet package

I'm using ConsoleTableExt to print a tabulated table. I wanted to round a few decimals to 2 points. The NuGet package is using DataTable. Currently, I'm using .ToString(f2"), but I read a post which states that it's a bad practice to do that in a DataTable. Any suggestions?
// Main()
var tableBuilder = ConsoleTableBuilder.From(backtest.ReportResults(backtestResults)).WithFormat(ConsoleTableBuilderFormat.Alternative);
tableBuilder.ExportAndWriteLine();
public static DataTable ReportResults(List<BacktestResult> backtestResults)
{
var table = new DataTable();
table.Columns.Add("Pair", typeof(string));
table.Columns.Add("Trades", typeof(int));
table.Columns.Add("Average Profit %", typeof(string));
table.Columns.Add("Cumulative Profit %", typeof(string));
table.Columns.Add($"Total Profit", typeof(string));
table.Columns.Add($"Total Profit %", typeof(string));
foreach (var pair in _backtestOptions.Pairs)
{
var results = backtestResults.Where(e => e.Pair.Equals(pair)).ToList();
var trades = results.Count;
var profitMean = results.Count > 0 ? results.Average(e => e.ProfitPercentage) : 0;
var profitMeanPercentage = results.Count > 0 ? results.Average(e => e.ProfitPercentage) * 100 : 0;
var profitSum = results.Sum(e => e.ProfitPercentage);
var profitSumPercentage = results.Sum(e => e.ProfitPercentage) * 100;
var profitTotalAbs = results.Sum(e => e.ProfitAbs);
var profitTotal = results.Sum(e => e.ProfitAbs) / 1;
var profitTotalPercentage = results.Sum(e => e.ProfitPercentage) * 100;
table.Rows.Add(pair, trades, profitMeanPercentage.ToString("f2"), profitSumPercentage.ToString("f2"), profitTotalAbs.ToString("f8"),
profitTotalPercentage.ToString("f2"));
}
return table;
}
You can use the function Round of Math for round value. Round(double value, MidpointRounding mode) where the second parameter specification for how to round value if it is midway between two other numbers.
Example:
decimal decimalVal = 123.456M;
Math.Round(decimalVal, 2);

How to compare two datatables and only check for the rows found

var qry = from r1 in dtCMS.AsEnumerable() //row count - 416
from r2 in dtEcho.AsEnumerable() //row count - 175
where
r1.Field<string>("Name") == r2.Field<string>("Name")
select r2;
DataTable dt1 = dtEcho.AsEnumerable().Except(qry).CopyToDataTable();
Error:
The source contains no DataRows.
How can I modify the code above so that the comparison will only happen for the rows in r2?
I would like two functions:
One, that compare dtEcho to dtCMS, and return anything that is in
dtEcho but not in dtCMS.
Two, that compare dtEcho to dtCMS, and return anything that is in
dtCMS but not in dtEcho.
The code fails if the DataTable I am comparing against has more rows and hence it can't compare.
CopyToDataTable will throw an InvalidOperationException if the source sequence does not contain any DataRow objects:
The source contains no DataRows.
Your code is OK in general and to solve the problem with minimum changes, the only thing that you should change is the way that you create the result.
Instead of using CopyToDataTable put results in the result table using a for loop. To do so, first you should create a clone of your second table.
var qry = from r1 in table1.AsEnumerable() //row count - 416
from r2 in table2.AsEnumerable() //row count - 175
where
r1.Field<string>("Name") == r2.Field<string>("Name")
select r2;
var dt = table2.Clone();
table2.AsEnumerable().Except(qry).ToList().ForEach(x =>
{
dt.Rows.Add(x);
});
this.dataGridView1.DataSource = dt;
If I got right what you want, the code should look like this:
// setup
var dtCMS = new DataTable();
dtCMS.Columns.Add("ID", typeof(int));
dtCMS.Columns.Add("Name", typeof(String));
for (int i = 0; i < 416; i++)
dtCMS.Rows.Add(i, "Name " + i);
var dtEcho = new DataTable();
dtEcho.Columns.Add("ID", typeof(int));
dtEcho.Columns.Add("Name", typeof(String));
for (int i = 400; i < 575; i++)
dtEcho.Rows.Add(i, "Name " + i);
// convert to enumerables
var cmsEnum = dtCMS.AsEnumerable();
var echoEnum = dtEcho.AsEnumerable();
var CmsMinusEcho = cmsEnum.Where(cms => !echoEnum.Any(echo => echo.Field<String>("Name").Equals(cms.Field<String>("Name"))));
var EchoMinusCms = echoEnum.Where(echo => !cmsEnum.Any(cms => cms.Field<String>("Name").Equals(echo.Field<String>("Name"))));
// get DataTable with check
var CmsMinusEchoDt = CmsMinusEcho.Count() > 0 ? CmsMinusEcho.CopyToDataTable() : null;
var EchoMinusCmsDt = EchoMinusCms.Count() > 0 ? EchoMinusCms.CopyToDataTable() : null;

Reordering all rows of a datatable based on one of the fields

I have a DataTable with columns such as the following:
Field1 | val 1 | val 2 | val 3
Field2 | val 1 | val 2 | val 3
Field3 | val 1 | val 2 | val 3
Field4 | val 1 | val 2 | val 3
and so so on.. all the way to Field20
What would be the best way to completely reorder the rows before binding to the grid on my page. I would use the Field column to determine where each row should go.
I did research and saw that one of the only techniques was to Clone, Delete, Re-insert the row where it should go.
If I have to do this for all of the rows since none of the rows are in their correct position does anyone have a good way of doing it?
Here is what I tried:
DataTable dataTable2 = new DataTable();
DataRow[] row = dataTable1.Select("Field ='" + "Field2" +"'");
dataTable2 .Rows.InsertAt(row, 0);
You can use LINQ to sort your DataTable. The result of the LINQ operation (dt2) is IEnumerable, but you can still it to bind your grid.
var dt = new DataTable();
dt.Columns.Add("Key", typeof(string));
dt.Columns.Add("Position", typeof(int));
dt.Rows.Add("Key1Value", 2);
dt.Rows.Add("Key2Value", 3);
dt.Rows.Add("Key3Value", 4);
dt.Rows.Add("Key4Value", 5);
dt.Rows.Add("Key5Value", 0);
dt.Rows.Add("Key6Value", 1);
var dt2 = dt.AsEnumerable().OrderBy(x => x.Field<int>("Position"));
foreach (DataRow dr in dt2)
{
Console.WriteLine("{0} {1}", dr["Key"], dr["Position"]);
}
I edited my code so it matches your sort order. I add a column named Position, so I can sort it anyway I want. Just change the value of Position if you want different order.
If you don't want to add an extra column, you can use switch statement in the OrderBy method.
var dt = new DataTable();
dt.Columns.Add("Key", typeof(string));
dt.Rows.Add("Key1Value");
dt.Rows.Add("Key2Value");
dt.Rows.Add("Key3Value");
dt.Rows.Add("Key4Value");
dt.Rows.Add("Key5Value");
dt.Rows.Add("Key6Value");
var dt2 = dt.AsEnumerable().OrderBy(x =>
{
switch (x.Field<string>("Key"))
{
case "Key5Value": return 0;
case "Key6Value": return 1;
case "Key1Value": return 2;
case "Key2Value": return 3;
case "Key3Value": return 4;
case "Key4Value": return 5;
default : return -1;
}
}
);
foreach (DataRow dr in dt2)
{
Console.WriteLine(dr["Key"]);
}
Basically, the OrderBy() method accepts an anonymous method that define the sort order. Since "Key5Value" returns 0, then it is placed before "Key6Value" (returns 1). Use OrderByDescending() method if you want to sort it from largest value to smallest value.
I also edit your code. The getPosition method is similar to what the OrderBy() method in my LINQ code.
using System;
using System.Data;
using System.Linq;
class Program
{
static void Main()
{
var dt = new DataTable();
dt.Columns.Add("Key", typeof(string));
dt.Rows.Add("Key1Value");
dt.Rows.Add("Key2Value");
dt.Rows.Add("Key3Value");
dt.Rows.Add("Key4Value");
dt.Rows.Add("Key5Value");
dt.Rows.Add("Key6Value");
var dt2 = dt.Clone();
foreach (DataRow dr in dt.Rows)
{
string key = dr["Key"].ToString();
var dRow = dt2.NewRow();
dRow.ItemArray = dr.ItemArray;
dt2.Rows.InsertAt(dRow, getPosition(key));
}
foreach (DataRow dr in dt2.Rows)
{
Console.WriteLine(dr["Key"]);
}
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
static int getPosition(string key)
{
switch (key)
{
case "Key5Value":
return 0;
case "Key6Value":
return 1;
case "Key1Value":
return 2;
case "Key2Value":
return 3;
case "Key3Value":
return 4;
case "Key4Value":
return 5;
default:
return -1;
}
}
}
Version 2:
I add a dictionary which contains the key value (eg. Key1Value) and a pair of values. The pair values are the new key value (eg. Key 1 Value) and the position. The reason I use a dictionary is to replace the switch-case expression. You can add additional value if you want. Just add more type to the tuple.
Tuple<string, int, int, bool> // holds a sequence of a string, two integers and a boolean.
Here's the complete code.
using System;
using System.Data;
using System.Linq;
using System.Collections.Generic;
class Program
{
static void Main()
{
// create table
var dt = new DataTable();
dt.Columns.Add("Key", typeof(string));
dt.Columns.Add("Val1", typeof(int));
dt.Columns.Add("Val2", typeof(int));
dt.Columns.Add("Val3", typeof(int));
dt.Columns.Add("Position", typeof(int));
// populate table
dt.Rows.Add("Key1Value", 100, 200, 300);
dt.Rows.Add("Key2Value", 100, 200, 300);
dt.Rows.Add("Key3Value", 100, 200, 300);
dt.Rows.Add("Key4Value", 100, 200, 300);
dt.Rows.Add("Key5Value", 100, 200, 300);
dt.Rows.Add("Key6Value", 100, 200, 300);
// initialize dictionary
var dict = new Dictionary<string, Tuple<string, int>>() {
{ "Key1Value", new Tuple<string, int>("Key 1 Value", 2) }, // Key1Value's new value is Key 1 Value, position is 2
{ "Key2Value", new Tuple<string, int>("Key 2 Value", 3) },
{ "Key3Value", new Tuple<string, int>("Key 3 Value", 4) },
{ "Key4Value", new Tuple<string, int>("Key 4 Value", 5) },
{ "Key5Value", new Tuple<string, int>("Key 5 Value", 0) },
{ "Key6Value", new Tuple<string, int>("Key 6 Value", 1) }
};
// set position and new key value
dt.AsEnumerable()
.ToList()
.ForEach(x => {
x["Position"] = dict[x.Field<string>("Key")].Item2;
x["Key"] = dict[x.Field<string>("Key")].Item1; // must be the last because the dictionary key is "KeyXValue", not "Key X Value"
});
// sort by Position
var dt2 = dt.AsEnumerable().OrderBy(x => x.Field<int>("Position"));
foreach (DataRow dr in dt2)
{
Console.WriteLine("{0}, {1}, {2}, {3}, {4}", dr["Key"], dr["Val1"], dr["Val2"], dr["Val3"], dr["Position"]);
}
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
Here is the best solution that I could some up with due to time being a factor. Please comment if you feel like it can be done in a better way.
This technique involves creating a clone of the source datatable. Then looping through the source datatable and re-adding rows to datatable2 in the desired order.
// Make a clone of the source datatable
DataTable dataTable2 = dataTable1.Clone();
// Loop through each row in the source datatable and check for key
foreach (DataRow dr in dataTable1.Rows)
{
string key = dr["Key"].ToString();
DataRow dRow = dataTable2.NewRow();
switch (key)
{
case "Key5Value":
// Rename actual key value if needed
dr["Key"] = "Key Rename if needed";
// Set new datarow item array to current row in loop item array
dRow.ItemArray = dr.ItemArray;
// Add datarow to desired position in dataTable 2
dataTable2.Rows.InsertAt(dRow, 0);
break;
case "Key6Value":
dr["Key"] = "Key Rename if needed";
dRow.ItemArray = dr.ItemArray;
dataTable2.Rows.InsertAt(dRow, 1);
break;
case "Key1Value":
dr["Key"] = "Key Rename if needed";
dRow.ItemArray = dr.ItemArray;
dataTable2.Rows.InsertAt(dRow, 2);
break;
case "Key2Value":
dr["Key"] = "Key Rename if needed";
dRow.ItemArray = dr.ItemArray;
dataTable2.Rows.InsertAt(dRow, 3);
break;
case "Key4Value":
dr["Key"] = "Key Rename if needed";
dRow.ItemArray = dr.ItemArray;
dataTable2.Rows.InsertAt(dRow, 4);
break;
case "Key3Value":
dr["Key"] = "Key Rename if needed";
dRow.ItemArray = dr.ItemArray;
dataTable2.Rows.InsertAt(dRow, 5);
break;
}
}
Another solution could be:
Add a new column "IntegerKey" in the data table.
Update value of column "Integer Key" based on the desired column's value
e.g. when desired Column value is say "column2" then column "IntegerKey" value = 1
when desired Column value is say "column1" then column "IntegerKey" value = 2
when desired Column value is say "column4" then column "IntegerKey" value = 3
datarows[] arrROWS = Datatable.Select(string.empty, "IntegerKey desc")

How to count and sum total of DataTable with LINQ?

I have a DataTable which has a column "amount" for each rows and I'd like to have the total sum of all the rows. And also, I'd like to get total number of rows in the DataTable. Could anyone teach me how to have it done with LINQ instead of ordinary way?
Number of rows:
DataTable dt; // ... populate DataTable
var count = dt.Rows.Count;
Sum of the "amount" column:
DataTable dt; // ... populate DataTable
var sum = dt.AsEnumerable().Sum(dr => dr.Field<int>("amount"));
Aggregate allows you to avoid enumerating the rows twice (you could get the row count from the rows collection but this is more to show how to extract multiple aggregates in 1 pass):
var sumAndCount = table.AsEnumerable().Aggregate(new { Sum = 0d, Count = 0},
(data, row) => new { Sum = data.Sum + row.Field<double>("amount"), Count = data.Count + 1});
double sum = sumAndCount.Sum;
int count = sumAndCount.Count;
decimal[] Amount = {2,3,5 };
var sum = Amount.Sum();
var count = Amount.Count();
Based on Roy Goode's Answer you could also create an Extension
public static int Sum(this DataTable table, string Column)
{
return table.AsEnumerable().Sum(dr => dr.Field<int>(Column));
}
Unfortunately you can't be more generic her because there is no where T : numeric

Create a new row from 2 tables

New to LINQ and c# but having problem with one specific problem.
I have 2 Data tables.
DataTable 1 has Name, House Number in it. DataTable 2 holds Street, FirstHouseNumber, LastHouseNumber.
What I want to do is create a new table that has Name, House Number, Street in it but I keep ending up with lots of DataTable1 Count * DataTable2 Count when I would only expect the same count as DataTable 1.
Heres the expression I am using:
var funcquery = from name in DT1.AsEnumerable()
from street in DT2.AsEnumerable()
where name.Field<int>("Number") >= street.Field<int>("FirstHouseNumber") && name.Field<int>("Number") <= street.Field<int>("LastHouseNumber")
select new { Name = name.Field<string>("Name"), Number = name.Field<int>("Number"), street.Field<string>("Street") };
What am I doing wrong? I just cant get it at all.
TIA.
This will be easier to think about with a more specific example:
Name House Number
------ ------------
Chris 123
Ben 456
Joe 789
Street First House Last House
Number Number
-------- ------------ ------------
Broadway 100 500
Main 501 1000
To demonstrate the results using this data, I use the following code:
class HouseInfo
{
public string Name;
public int HouseNumber;
public HouseInfo(string Name, int HouseNumber)
{
this.Name = Name;
this.HouseNumber = HouseNumber;
}
}
class StreetInfo
{
public string Street;
public int FirstHouseNumber;
public int LastHouseNumber;
public StreetInfo(string Street, int FirstHouseNumber, int LastHouseNumber)
{
this.Street = Street;
this.FirstHouseNumber = FirstHouseNumber;
this.LastHouseNumber = LastHouseNumber;
}
}
static void Main(string[] args)
{
HouseInfo[] houses = new HouseInfo[] {
new HouseInfo("Chris", 123),
new HouseInfo("Ben", 456),
new HouseInfo("Joe", 789) };
StreetInfo[] streets = new StreetInfo[] {
new StreetInfo("Broadway", 100, 500),
new StreetInfo("Main", 501, 1000)};
var funcquery = from name in houses
from street in streets
where name.HouseNumber >= street.FirstHouseNumber && name.HouseNumber <= street.LastHouseNumber
select new { Name = name.Name, Number = name.HouseNumber, Street = street.Street };
var results = funcquery.ToArray();
for (int i = 0; i < results.Length; i++)
{
Console.WriteLine("{0} {1} {2}", results[i].Name, results[i].Number, results[i].Street);
}
}
The results are:
Chris 123 Broadway
Ben 456 Broadway
Joe 789 Main
This seems to be what you are after, so I don't think the problem is in the code you've given. Perhaps it is in the data itself (if multiple streets include the same house range) or something else. You may need to supply more specific data that demonstrates your problem.
Here's the same code implemented using DataTables instead of classes. It yields the same result:
System.Data.DataTable DT1 = new System.Data.DataTable("Houses");
System.Data.DataTable DT2 = new System.Data.DataTable("Streets");
DT1.Columns.Add("Name", typeof(string));
DT1.Columns.Add("Number", typeof(int));
DT2.Columns.Add("Street", typeof(string));
DT2.Columns.Add("FirstHouseNumber", typeof(int));
DT2.Columns.Add("LastHouseNumber", typeof(int));
DT1.Rows.Add("Chris", 123);
DT1.Rows.Add("Ben", 456);
DT1.Rows.Add("Joe", 789);
DT2.Rows.Add("Broadway", 100, 500);
DT2.Rows.Add("Main", 501, 1000);
var funcquery = from System.Data.DataRow name in DT1.Rows
from System.Data.DataRow street in DT2.Rows
where (int)name["Number"] >= (int)street["FirstHouseNumber"]
&& (int)name["Number"] <= (int)street["LastHouseNumber"]
select new { Name = name["Name"], Number = name["Number"], Street = street["Street"] };
var results = funcquery.ToArray();
for (int i = 0; i < results.Length; i++)
{
Console.WriteLine("{0} {1} {2}", results[i].Name, results[i].Number, results[i].Street);
}

Categories