Linq Queryable - Joining two tables with no relationships - c#

Firstly, this is for a legacy application, so I cannot radically change any logic.
I have database with two tables that do not have any relationships. I asked if I change this, but was told I cannot.
These tables can be described as
Create Table T1
[doc_id] [int] NOT NULL, -- Primary Key
[customer_acc_no] [varchar](16) NULL,
[gcompany] [varchar](30) NULL,
....
extra fields
and table
Create Table T2
[UserURN] [int] NOT NULL, -- All three fields make up
[AccountNumber] [varchar](20) NOT NULL, -- the primary key
[Company] [varchar](50) NOT NULL,
....
extra fields
As you can see, not only are the field names different, but they have different lengths too.
I am using the Repository and UnitOfWork patterns. So far I have managed to code the following:
private IRepository<T1> _t1Repository;
private IRepository<T2> _t2Repository;
These are populated within the constructor.
Next I use the following code to configure get a queryable repository.
var retVal = _t1Repository.Queryable();
From this, I am trying to add the following join.
from q in T1
join w in T2
on new { X1 = q.gcompany, X2 = q.Customer_acc_no }
equals new { X1 = w.Company, X2 = w.AccountNumber }
I am thinking it would be along the lines of:
var query = T1.GroupJoin(T2,
c => c.gcompany,
o => o.Company,
(c, result) => new Result(c.doc_id, result))
.GroupJoin(T2,
c => c.Customer_acc_no,
o => o.AccountNumber ,
(c, result) => new Result(c.doc_id, result));
but i'm not sure as all attempts so far end in errors within visual studio.

See code below :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication42
{
class Program
{
static void Main(string[] args)
{
DataTable dt1 = new DataTable();
dt1.Columns.Add("doc_id", typeof(int));
dt1.Columns.Add("customer_acc_no", typeof(string));
dt1.Columns.Add("gcompany", typeof(string));
dt1.Rows.Add(new object[] { 1, "100", "abc" });
dt1.Rows.Add(new object[] { 2, "100", "def" });
dt1.Rows.Add(new object[] { 3, "100", "def" });
dt1.Rows.Add(new object[] { 4, "101", "abc" });
dt1.Rows.Add(new object[] { 5, "101", "ghi" });
dt1.Rows.Add(new object[] { 6, "102", "jkl" });
dt1.Rows.Add(new object[] { 7, "102", "abc" });
dt1.Rows.Add(new object[] { 8, "102", "def" });
dt1.Rows.Add(new object[] { 9, "103", "abc" });
dt1.Rows.Add(new object[] { 10, "103", "abc" });
DataTable dt2 = new DataTable();
dt2.Columns.Add("UserURN", typeof(int));
dt2.Columns.Add("AccountNumber", typeof(string));
dt2.Columns.Add("Company", typeof(string));
dt2.Rows.Add(new object[] { 11, "100", "abc" });
dt2.Rows.Add(new object[] { 12, "100", "def" });
dt2.Rows.Add(new object[] { 13, "100", "def" });
dt2.Rows.Add(new object[] { 14, "101", "abc" });
dt2.Rows.Add(new object[] { 15, "101", "ghi" });
dt2.Rows.Add(new object[] { 16, "102", "jkl" });
dt2.Rows.Add(new object[] { 17, "102", "abc" });
dt2.Rows.Add(new object[] { 18, "102", "def" });
dt2.Rows.Add(new object[] { 19, "103", "abc" });
dt2.Rows.Add(new object[] { 20, "103", "abc" });
var results = from r1 in dt1.AsEnumerable()
join r2 in dt2.AsEnumerable() on
new { x1 = r1.Field<string>("customer_acc_no"), x2 = r1.Field<string>("gcompany") } equals
new { x1 = r2.Field<string>("AccountNumber"), x2 = r2.Field<string>("Company") }
select new { t1 = r1, t2 = r2 };
}
}
}

Related

Linq groupby on values of List of dictionary<string,string> with unknown number of keys or key names

This is something I have spent several hours on and haven't been able to figure it out. Basically, I have a List<object>, and each object in that list has a Dictionary<long, Dictionary<string,string>>. The Dictionary<string,string> is data pair sets that need to be grouped by. Is there a way with linq to iterate through the List<object> with an unknown number/name of Dictionary<string,string> keys and use group by?
Each dictionary is actually a row of data, and the string key value pair is actually column/data, for context. And unfortunately, I cannot change how I am receiving this data.
Most of the examples I can find only seem to work with DataTables, or are hard coded for certain column names. If it is not possible while the dictionaries are inside objects in that list, can it be done if it was just a List<Dictionary<string,string>> ?
For the purpose of this code snippet please assume that the variable AllDataList is the complete list of ContainerClass objects. The routine Projection was borrowed from:
https://www.codeproject.com/Questions/141367/Dynamic-Columns-from-List-using-LINQ
Lastly, unfortunately I cannot bring in third party library's for this.
public class ContainerClass
{
public Dictionary<long, Dictionary<string, string>> data;
public ContainerClass()
{
data = Dictionary<long, Dictionary<string, string>>;
data.add(0,new Dictionary<string,string>());
}
}
private dynamic Projection(object a, IEnumerable<string> props)
{
if (a == null)
{
return null;
}
IDictionary<string, object> res = new System.Dynamic.ExpandoObject();
var type = a.GetType();
foreach (var pair in props.Select(n => new {
Name = n,
Property = type.GetProperty(n)
}))
{
res[pair.Name] = pair.Property.GetValue(a, new object[0]);
}
return res;
}
public void DoStuff()
{
List<string> cols = new List<string>();
//normally cols would be determined at runtime
cols.add("Column1");
cols.add("Column2");
cols.add("Column3");
List<ContainerClass> res = (List<ContainerClass>) this.AllDataList.GroupBy(x => new[] {
Projection(x.data,cols)
}).Select(y =>Projection(y, cols)); //unsure if the select is necessary
}
EDIT: We ended up pursuing a different route
Do you have something like this?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(long));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Value", typeof(string));
dt.Rows.Add(new object[] { 1, "abc", "mno" });
dt.Rows.Add(new object[] { 1, "def", "mnp" });
dt.Rows.Add(new object[] { 1, "def", "mnq" });
dt.Rows.Add(new object[] { 2, "abc", "mnr" });
dt.Rows.Add(new object[] { 2, "abd", "mns" });
dt.Rows.Add(new object[] { 3, "abe", "mnt" });
dt.Rows.Add(new object[] { 3, "abf", "mnu" });
dt.Rows.Add(new object[] { 4, "abc", "mnv" });
dt.Rows.Add(new object[] { 4, "ade", "mnw" });
Dictionary<long, Dictionary<string, string>> dict = dt.AsEnumerable()
.GroupBy(x => x.Field<long>("ID"), y => y)
.ToDictionary(x => x.Key, y => y
.GroupBy(a => a.Field<string>("Name"), b => b.Field<string>("Value"))
.ToDictionary(a => a.Key, b => b.FirstOrDefault())
);
//Now back to a datatable
DataTable dt2 = new DataTable();
dt2.Columns.Add("Col A", typeof(long));
dt2.Columns.Add("Col B", typeof(string));
dt2.Columns.Add("Col C", typeof(string));
foreach(long id in dict.Keys)
{
foreach (KeyValuePair<string, string> value in dict[id])
{
dt2.Rows.Add(new object[] {id, value.Key, value.Value});
}
}
}
}
}
Here is another method that may work
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(long));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Value", typeof(string));
dt.Rows.Add(new object[] { 1, "abc", "mno" });
dt.Rows.Add(new object[] { 1, "def", "mnp" });
dt.Rows.Add(new object[] { 1, "def", "mnq" });
dt.Rows.Add(new object[] { 2, "abc", "mnr" });
dt.Rows.Add(new object[] { 2, "abd", "mns" });
dt.Rows.Add(new object[] { 3, "abe", "mnt" });
dt.Rows.Add(new object[] { 3, "abf", "mnu" });
dt.Rows.Add(new object[] { 4, "abc", "mnv" });
dt.Rows.Add(new object[] { 4, "ade", "mnw" });
Dictionary<long, Dictionary<string, List<DataRow>>> dict = dt.AsEnumerable()
.GroupBy(x => x.Field<long>("ID"), y => y)
.ToDictionary(x => x.Key, y => y
.GroupBy(a => a.Field<string>("Name"), b => b)
.ToDictionary(a => a.Key, b => b.ToList())
);
//Now back to a datatable
DataTable dt2 = new DataTable();
foreach(long id in dict.Keys)
{
foreach (KeyValuePair<string, List<DataRow>> value in dict[id])
{
dt2.Merge(value.Value.CopyToDataTable());
}
}
}
}
}

Linq count condition in query

I am stuck on this problem. I want to get users who are in the "Developer" role, who either are not assigned any tasks or are assigned 3 or fewer tasks which are marked "Active" or "Testing".
I don't know how to make a statement where I get all tasks with Status "Active, Testing" and sum them up for my count statement.
//here i specific role for users
var role = unitOfWork.RoleRepository._context.Roles.SingleOrDefault(m => m.Name == "Developer");
var query = (from u in users
where u.Roles.Any(r => r.RoleId == role.Id)
from t in u.ProjectTasks.Where(x => x.Users.Any(user => user.Id == u.Id)).DefaultIfEmpty()
//here I am able to get those users without assigned tasks but I dont know how to make the second condition with 3 or less tasks
where ((u.ProjectTasks.Count() == 0) || u.ProjectTasks.Any(z => z.Status == Status.Active || z.Status == Status.Testing))
select new { User = u } into Users
group Users by Users.User).ToList();
Here is my database model:
Perhaps the LINQ Count function is called for:
var query = (from u in users
where u.Roles.Any(r => r.RoleId == role.Id)
from t in u.ProjectTasks.Where(x => x.Users.Any(user => user.Id == u.Id)).DefaultIfEmpty()
where ((u.ProjectTasks.Count() == 0) || u.ProjectTasks.Count(z => z.Status == Status.Active || z.Status == Status.Testing) <= 3)
select new { User = u } into Users
group Usersby Users.User).ToList();
For examples of usages: http://www.csharp-examples.net/linq-count/
I simulated the database with DataTable to show how it is done
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable AspNetRoles = new DataTable();
AspNetRoles.Columns.Add("Id", typeof(int));
AspNetRoles.Columns.Add("Name", typeof(string));
AspNetRoles.Rows.Add(new object[] { 123, "Developer" });
AspNetRoles.Rows.Add(new object[] { 456, "Non Developer" });
DataTable AspNetUserRoles = new DataTable();
AspNetUserRoles.Columns.Add("UserId", typeof(int));
AspNetUserRoles.Columns.Add("RoleId", typeof(int));
AspNetUserRoles.Rows.Add(new object[] { 100, 123 });
AspNetUserRoles.Rows.Add(new object[] { 200, 456 });
AspNetUserRoles.Rows.Add(new object[] { 300, 123 });
AspNetUserRoles.Rows.Add(new object[] { 400, 456 });
DataTable AspNetUsers = new DataTable();
AspNetUsers.Columns.Add("Id", typeof(int));
AspNetUsers.Rows.Add(new object[] { 100 });
AspNetUsers.Rows.Add(new object[] { 200 });
AspNetUsers.Rows.Add(new object[] { 300 });
AspNetUsers.Rows.Add(new object[] { 400 });
DataTable UserToTask = new DataTable();
UserToTask.Columns.Add("UserId", typeof(int));
UserToTask.Columns.Add("TaskId", typeof(int));
UserToTask.Rows.Add(new object[] { 100, 1000 });
UserToTask.Rows.Add(new object[] { 100, 1001 });
UserToTask.Rows.Add(new object[] { 100, 1002 });
UserToTask.Rows.Add(new object[] { 200, 1001 });
UserToTask.Rows.Add(new object[] { 200, 1004 });
UserToTask.Rows.Add(new object[] { 200, 1006 });
UserToTask.Rows.Add(new object[] { 300, 1005 });
UserToTask.Rows.Add(new object[] { 300, 1006 });
UserToTask.Rows.Add(new object[] { 400, 1007 });
UserToTask.Rows.Add(new object[] { 400, 1008 });
DataTable ProjectTasks = new DataTable();
ProjectTasks.Columns.Add("Id", typeof(int));
ProjectTasks.Columns.Add("Status", typeof(string));
ProjectTasks.Rows.Add(new object[] { 1000, "Active" });
ProjectTasks.Rows.Add(new object[] { 1001, "Testing" });
ProjectTasks.Rows.Add(new object[] { 1002, "Idle" });
ProjectTasks.Rows.Add(new object[] { 1003, "Active" });
ProjectTasks.Rows.Add(new object[] { 1004, "Testing" });
ProjectTasks.Rows.Add(new object[] { 1005, "Idle" });
ProjectTasks.Rows.Add(new object[] { 1006, "Active" });
ProjectTasks.Rows.Add(new object[] { 1007, "Testing" });
ProjectTasks.Rows.Add(new object[] { 1008, "Idle" });
var results = (from aspNetUser in AspNetUsers.AsEnumerable()
join task in UserToTask.AsEnumerable() on aspNetUser.Field<int>("Id") equals task.Field<int>("UserId")
join proj in ProjectTasks.AsEnumerable() on task.Field<int>("TaskId") equals proj.Field<int>("Id")
join aspNetUserRole in AspNetUserRoles.AsEnumerable() on aspNetUser.Field<int>("Id") equals aspNetUserRole.Field<int>("UserId")
join aspNetRole in AspNetRoles.AsEnumerable() on aspNetUserRole.Field<int>("RoleId") equals aspNetRole.Field<int>("Id")
select new { aspNetUser = aspNetUser, task = task, proj = proj, aspNetUserRole = aspNetUserRole, aspNetRole = aspNetRole }).ToList();
var finalResults = results.GroupBy(x => x.aspNetUser.Field<int>("Id"))
.Where(x => (x.Select(y => y.task).Count() == 0) || (x.Where(y => (y.proj.Field<string>("Status") == "Active") || (y.proj.Field<string>("Status") == "Testing"))).Count() <= 3).ToList();
}
}
}

How to Change DataRow value of one datatable to colum name of new Datatable?

My first DataTable is
Name | Value
---------------+----------
A | 12
B | 22
and i want this table as
A | B
---------------+----------
12 | 22
How to resolve this,please help me i tried a lot but i didn't get.Thank You in Advance.
You can convert rows into column using below line of code:
DataTable Pivot(DataTable table, string pivotColumnName)
{
// TODO make sure the table contains at least two columns
// get the data type of the first value column
var dataType = table.Columns[1].DataType;
// create a pivoted table, and add the first column
var pivotedTable = new DataTable();
pivotedTable.Columns.Add("Row Name", typeof(string));
// determine the names of the remaining columns of the pivoted table
var additionalColumnNames = table.AsEnumerable().Select(x => x[pivotColumnName].ToString());
// add the remaining columns to the pivoted table
foreach (var columnName in additionalColumnNames)
pivotedTable.Columns.Add(columnName, dataType);
// determine the row names for the pivoted table
var rowNames = table.Columns.Cast<DataColumn>().Select(x => x.ColumnName).Where(x => x != pivotColumnName);
// fill in the pivoted data
foreach (var rowName in rowNames)
{
// get the value data from the appropriate column of the input table
var pivotedData = table.AsEnumerable().Select(x => x[rowName]);
// make the rowName the first value
var data = new object[] { rowName }.Concat(pivotedData).ToArray();
// add the row
pivotedTable.Rows.Add(data);
}
return pivotedTable;
}
In case you have any problem or query please feel free to ask me.
Here is a pivot table
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication33
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Value", typeof(int));
dt.Columns.Add("Date", typeof(DateTime));
dt.Rows.Add(new object[] {"A", 100, DateTime.Parse("12/1/16")});
dt.Rows.Add(new object[] { "A", 101, DateTime.Parse("12/2/16") });
dt.Rows.Add(new object[] { "A", 102, DateTime.Parse("12/3/16") });
dt.Rows.Add(new object[] { "A", 103, DateTime.Parse("12/4/16") });
dt.Rows.Add(new object[] { "B", 104, DateTime.Parse("12/1/16") });
dt.Rows.Add(new object[] { "B", 110, DateTime.Parse("12/2/16") });
dt.Rows.Add(new object[] { "B", 114, DateTime.Parse("12/3/16") });
dt.Rows.Add(new object[] { "B", 112, DateTime.Parse("12/4/16") });
dt.Rows.Add(new object[] { "B", 100, DateTime.Parse("12/5/16") });
dt.Rows.Add(new object[] { "C", 120, DateTime.Parse("12/1/16") });
dt.Rows.Add(new object[] { "C", 130, DateTime.Parse("12/2/16") });
dt.Rows.Add(new object[] { "C", 140, DateTime.Parse("12/3/16") });
dt.Rows.Add(new object[] { "C", 150, DateTime.Parse("12/4/16") });
dt.Rows.Add(new object[] { "C", 160, DateTime.Parse("12/5/16") });
dt.Rows.Add(new object[] { "C", 101, DateTime.Parse("12/6/16") });
string[] uniqueNames = dt.AsEnumerable().Select(x => x.Field<string>("Name")).Distinct().ToArray();
var groups = dt.AsEnumerable().GroupBy(x => x.Field<DateTime>("Date")).ToList();
DataTable pivot = new DataTable();
pivot.Columns.Add("Date", typeof(DateTime));
foreach (var name in uniqueNames)
{
pivot.Columns.Add(name, typeof(string));
}
foreach (var group in groups)
{
DataRow newRow = pivot.Rows.Add();
newRow["Date"] = group.Key;
foreach (DataRow row in group)
{
newRow[row.Field<string>("Name")] = row.Field<int>("Value");
}
}
}
}
}

How to Group Datatable rows with 6 columns with c#.net

Need help. I have 6 columns in a datatable. I've converted it to a dataview, and sorted it by all six, then updated the datatable accordingly. I need to group rows when the values in the last 4 columns are identical and place them in their own, unique tables that I can use later, removing them from the original table.
My columns are: CurveNumber, ObjectId, Length, Radius, Delta, and Tangent.
Thanks for any help you can provide.
another solution here
DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[] { new DataColumn("CurveNumber"), new DataColumn("ObjectId"), new DataColumn("Length"),
new DataColumn("Radius"), new DataColumn("Delta"), new DataColumn("Tangent") });
dt.Rows.Add(new object[] { "1","0851ax","20","20","20","20" });
dt.Rows.Add(new object[] { "2", "0852ab", "20", "20", "20", "20" });
dt.Rows.Add(new object[] { "3", "0853ac", "25", "32", "12", "10" });
dt.Rows.Add(new object[] { "4", "0854ad", "12", "31", "15", "20" });
dt.Rows.Add(new object[] { "5", "0855ca", "20", "20", "20", "20" });
dt.Rows.Add(new object[] { "6", "0856ad", "25", "32", "12", "10" });
//Group by distinct 4 column
var GroupBy4ColumnDistinct = dt.Rows.Cast<DataRow>()
.ToLookup(x => (Convert.ToString(x["Length"]) + Convert.ToString(x["Radius"]) + Convert.ToString(x["Delta"]) + Convert.ToString(x["Tangent"])).GetHashCode())
.Select(x => new { key = x.Key, values = x.Select(y => Convert.ToString(y["CurveNumber"])).ToList() }).ToList();
// add new table to dataset. dataset contain 3 table as shown in our sample output
DataSet ds = new DataSet();
foreach (var item in GroupBy4ColumnDistinct)
{
DataView dv = new DataView(dt);
dv.RowFilter = " CurveNumber in ( " + string.Join(",", item.values) + " )";
ds.Tables.Add(dv.ToTable());
}</pre>
An approach - start with a DataView and use its .ToTable() method to first obtain a unique collection of values for your last four columns. Then loop through it looking for matches in the original table (source at: https://dotnetfiddle.net/PlAZSi):
// Initial table set up and population
DataTable originalTable = new DataTable("originaltable");
originalTable.Columns.Add("CurveNumber", (123).GetType());
originalTable.Columns.Add("ObjectID", ("String").GetType());
originalTable.Columns.Add("Length", (123).GetType());
originalTable.Columns.Add("Radius", (123).GetType());
originalTable.Columns.Add("Delta", (123).GetType());
originalTable.Columns.Add("Tangent", (123).GetType());
originalTable.Rows.Add(new object[] { 1, "0851ax", 20, 20, 20, 20} );
originalTable.Rows.Add(new object[] { 2, "0852ab", 20, 20, 20, 20} );
originalTable.Rows.Add(new object[] { 3, "0853ac", 25, 32, 12, 10} );
originalTable.Rows.Add(new object[] { 4, "0854ad", 12, 31, 15, 20} );
originalTable.Rows.Add(new object[] { 5, "0855ca", 20, 20, 20, 20} );
originalTable.Rows.Add(new object[] { 6, "0856ad", 25, 32, 12, 10} );
// Create a new datatable containing the unique values
// for the four columns in question
DataTable uniqueValues = (new DataView(originalTable))
.ToTable(true, new string[] {"Length",
"Radius",
"Delta",
"Tangent"});
// Create a DataSet of DataTables each one containing the grouped
// rows based on matches on the four columns in question.
DataSet groupedRows = new DataSet("groupedRows");
foreach (DataRow uniqueValue in uniqueValues.Rows) {
// Create the individual table of grouped rows based on the
// structure of the original table
DataTable groupTable = originalTable.Clone();
groupTable.TableName = String.Format("{0}-{1}-{2}-{3}",
uniqueValue["Length"],
uniqueValue["Radius"],
uniqueValue["Delta"],
uniqueValue["Tangent"]);
// Fetch the rows from the original table based on matching to the
// unique combination of four columns
DataRow[] groupRows = originalTable.Select(String.Format(" Length = {0} AND Radius = {1} AND Delta = {2} AND Tangent = {3} ",
uniqueValue["Length"],
uniqueValue["Radius"],
uniqueValue["Delta"],
uniqueValue["Tangent"]));
// Add each matched row into the individual grouped DataTable
foreach (DataRow groupRow in groupRows) {
groupTable.Rows.Add(groupRow.ItemArray);
}
// Finally, add the DataTable to the DataSet
groupedRows.Tables.Add(groupTable);
}
I would like to point out that there is, very likely, a much more elegant solution using LINQ. However, this should get you where you need to be.

The best way to search in DataTable on multiple conditions in C#?

I have 2 DataTable with the following columns:
Table 1
Title
NUMBER
Sub_num1
Sub_num2
Table 2
NUMBER
Sub_num1
Sub_num2
In Table 2 Combination of NUMBER, Sub_num1 and Sub_num2 is unique. Can be Many NUMBERS, but with different set of Sub1 and Sub2.
In Table 1 Title is unique. A couple titles can have the same NUMBER, but again different set of Subs.
I need to loop through Table 2 and check if Table 1 has exact match with all 3 columns, then get this title, if not I need to get all Titles that have this NUMBER.
What is the best and fastest way to do this search? On the top of my head I have only next:
Loop through records in Table 2 and for each record loop through Table 1 and check for match, but I think that this process can be very resource-intensive...
Any help, please?
UPDATE
Example:
var dt1 = new DataTable("Table 1");
dt1.Columns.Add("title", typeof(string));
dt1.Columns.Add("number", typeof(int));
dt1.Columns.Add("subnum1", typeof(int));
dt1.Columns.Add("subnum2", typeof(int));
dt1.Rows.Add(new object[] { "a", 1111, 1, 1 }); // Exact match!
dt1.Rows.Add(new object[] { "b", 2222, 1, 1 }); // Only NUMBER match
dt1.Rows.Add(new object[] { "b", 2222, 2, 2 }); // Only NUMBER match
dt1.Rows.Add(new object[] { "d", 3333, 1, 1 }); // Exact match!
dt1.Rows.Add(new object[] { "d", 3333, 1, 2 });
dt1.Rows.Add(new object[] { "d", 3333, 2, 1 });
var dt2 = new DataTable("Table 2");
dt2.Columns.Add("number", typeof(int));
dt2.Columns.Add("subnum1", typeof(int));
dt2.Columns.Add("subnum2", typeof(int));
dt2.Rows.Add(new object[] { 1111, 1, 1 }); // Exact match!
dt2.Rows.Add(new object[] { 2222, "", 5 }); // Only NUMBER match
dt2.Rows.Add(new object[] { 3333, 1, 1 }); // Exact match!
dt2.Rows.Add(new object[] { 3333, "", "" }); // Only NUMBER match
SO I'm looping through Table 2:
foreach (DataRow row in dt2.Rows)
{
// HERE Should be logic and search
}
RESULT should be:
If match print title, if not print ALL titleS with number, that match, so:
1. "a", 1111, 1, 1
2.1 "b", 2222, 1, 1
2.2 "b", 2222, 2, 2
3. "d", 3333, 1, 1
4.1 "d", 3333, 1, 1
4.2 "d", 3333, 1, 2
4.3 "d", 3333, 2, 1
One possibility would be to use the DataTable class build in filtering. You can define a dynamic filter and apply it to the DataTable object. The dynamic filter language is something like a subset of SQL, it has LIKE and other SQL keywords. An example of filtering code:
var dt = new DataTable("test");
dt.Columns.Add("A", typeof(string));
dt.Columns.Add("B", typeof(string));
dt.Rows.Add(new object[] { "a", "1" });
dt.Rows.Add(new object[] { "a", "2" });
var rows = dt.Select("B = '2'");
This way you can define the filter and apply it to both tables and compare only the result set and not every entry. The result is an array of Rows.
I used it in a project, that has DataTable objects containing more than 2K entries each and the performance is really good.
Another possibility would be to use LINQ to filter the data. You can query the DataTable's rows like this:
var rows = (from DataRow dr in dt.Rows
where dr["B"] == "2"
select dr).ToList();
This query returns the same result as the direct filtering. You can apply again the same approach here to check the mathching result only.
If i understood your question correctly, a possible solution to your problem could look like this:
// test DataTable objects for the example
var dt1 = new DataTable("Table 1");
dt1.Columns.Add("title", typeof(string));
dt1.Columns.Add("number", typeof(int));
dt1.Columns.Add("subnum1", typeof(int));
dt1.Columns.Add("subnum2", typeof(int));
dt1.Rows.Add(new object[] { "a", 1111, 1, 1 }); // Exact match!
dt1.Rows.Add(new object[] { "b", 2222, 1, 1 }); // Only NUMBER match
dt1.Rows.Add(new object[] { "b", 2222, 2, 2 }); // Only NUMBER match
dt1.Rows.Add(new object[] { "d", 3333, 1, 1 }); // Exact match!
dt1.Rows.Add(new object[] { "d", 3333, 1, 2 });
dt1.Rows.Add(new object[] { "d", 3333, 2, 1 });
var dt2 = new DataTable("Table 2");
dt2.Columns.Add("number", typeof(int));
dt2.Columns.Add("subnum1", typeof(int));
dt2.Columns.Add("subnum2", typeof(int));
dt2.Rows.Add(new object[] { 1111, 1, 1 }); // Exact match!
dt2.Rows.Add(new object[] { 2222, 0, 5 }); // Only NUMBER match
dt2.Rows.Add(new object[] { 3333, 1, 1 }); // Exact match!
dt2.Rows.Add(new object[] { 3333, 0, 0 }); // Only NUMBER match
foreach (DataRow row in dt1.Rows)
{
var matches = dt2.Select(string.Format("number = {0} and subnum1 = {1} and subnum2 = {2}", row["number"], row["subnum1"], row["subnum2"]));
if (matches.Count() > 0)
{
Console.WriteLine(row["title"]);
}
else
{
var fallback = dt2.Select(string.Format("number = {0}", row["number"]));
if (fallback.Count() > 0)
{
Console.WriteLine(" > " + row["title"]);
}
}
}
The output in this case is:
a
> b
> b
d
> d
> d
What values shoule be written to the output is up to you - at the point where the match is found you have all that you need.

Categories