简体   繁体   中英

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM