【问题标题】:Compare two DataTables and select first table records NOT in the second table比较两个数据表并选择不在第二个表中的第一个表记录
【发布时间】:2017-03-01 10:59:48
【问题描述】:

我有两个数据表,它们从两个不同的来源获取数据。我想要一个新的 DataTable Table3,其中只有没有匹配 Table2 行的 Tables1 行。我的两个数据表具有不同的结构,如下所示。但是,它们都共享相同的主键 - CarReg。因此,我想使用 CarReg 列比较行并返回 Table1 中但不在 Table2 中的所有行。我返回的 Table3 DataTable 将具有与 Table1 相同的结构。

Table1.Columns.Add("CarReg", typeof(string));
Table1.Columns.Add("Site", typeof(string));
Table1.Columns.Add("Route", typeof(double));
Table1.Columns.Add("Driver", typeof(string));
Table1.Columns.Add("StartingDate", typeof(string));

Table2.Columns.Add("CarReg", typeof(string));
Table2.Columns.Add("SITE DESC", typeof(string));
Table2.Columns.Add("Route DESC", typeof(double));
Table2.Columns.Add("Driver", typeof(string));
Table2.Columns.Add("KILOS", typeof(string));

我尝试了以下方法,但是,我从第一个表 Table1 中获取所有记录。我只需要获取 Table1 中但不在 Table2 中的记录。因此,例如,如果 Table1 有 20 条记录,Tables2 有 15 条记录,我只需要 5 条记录。请帮忙。

var recordsNotInB = TableA.AsEnumerable().Select(r =>r.Field<string>("CarReg").Except(TableB.AsEnumerable().Select(r => r.Field<string>("CarReg")));

【问题讨论】:

  • 那么您是否想要 Table1 中所有在 Table2 中没有匹配 CarReg 的记录?
  • @YawarMurtaza 是的,我想要 Table1 中所有在 Table2 中没有匹配 CarReg 的记录。感谢您用一个简单的英语句子来说明这一点。

标签: c# winforms linq linq-to-dataset system.data.datatable


【解决方案1】:

如果不知道你的任何代码,我会想出这个。

var idsFromTableB = TableB.AsEnumerable().Select(tb => tb.Field<string>("CarReg"));
var recordsNotInB = TableA.AsEnumerable().Where(ta => !idsFromTableB.Contains(ta.Field<string>("CarReg")));

【讨论】:

  • 我获得的记录数与我的代码获得的记录数相同,也就是说,我获得了第一个表 TableA 中的所有记录。我只需要获取 TableA 而不是 TableB 中的记录。否则感谢您的回复。
  • 谢谢,我成功了。因为,我正在处理一个字符串字段列,我需要修剪我在两个表上获得的值以便比较工作。再次感谢您。
【解决方案2】:

您可以提高性能,还可以使用哈希集指定比较方法。

var idsFromTableB = new HashSet<string>(TableB.AsEnumerable()
    .Select(tb => tb.Field<string>("CarReg")), StringComparer.OrdinalIgnoreCase);

var recordsNotInB = TableA.AsEnumerable()
    .Where(ta => !idsFromTableB.Contains(ta.Field<string>("CarReg")));

【讨论】:

    【解决方案3】:

    好的,这是一个冗长的解决方案,但我已经对其进行了测试并且它有效。

    我通过为每个 Table 创建 POCO 对象来完成它,然后将差异视为使用公共属性比使用容易出错的 Table1["CarReg"] 更容易玩。

    可能有人可以改进此解决方案。

    让您的表由 POCO 类表示,例如:

    public class Table1
    {
        public string CarReg { get; set; }
        public string Site { get; set; }
        public double Route { get; set; }
        public string Driver { get; set; }
        public string DateString { get; set; }
    }
    
    public class Table2
    {
        public string CarReg { get; set; }
        public string Site { get; set; }
        public double Route { get; set; }
        public string Driver { get; set; }
        public string Kilos { get; set; }
    }
    

    让我们填充数据:

    IEnumerable<Table1> data1 = new List<Table1>()
                {
                    new Table1() { CarReg = "123ABC", DateString = "20/02/2018", Driver = "Driver 1", Route = 45.45, Site = "England" },
                    new Table1() { CarReg = "456ABC", DateString = "20/03/2018", Driver = "Driver 2", Route = 55.45, Site = "Scotland" },
                    new Table1() { CarReg = "789ABC", DateString = "20/04/2018", Driver = "Driver 3", Route = 65.45, Site = "Wales" },
                };
    
                IEnumerable<Table2> data2 = new List<Table2>() {
                    new Table2() { CarReg = "123XYZ", Kilos = "34KG", Driver = "Driver 5", Route = 45.45, Site = "Karachi" },
                    new Table2() { CarReg = "456ABC", Kilos = "44KG", Driver = "Driver 2", Route = 55.45, Site = "Scotland" },
                    new Table2() { CarReg = "789CCC", Kilos = "54KG", Driver = "Driver 7", Route = 65.45, Site = "Hyderabad" },
                };
    

    创建一个列表来保存结果数据:

     List<Table1> oneList = new List<Table1>();
    

    循环识别不在Table2中的行

      bool matchFound = false; // an indicator if match is found in table 2
    
            foreach (var item in data1)
            {
                foreach (var item2 in data2)
                {
                    if (item.CarReg != item2.CarReg)
                    {
                        matchFound = false;
                    }
                    else
                    {
                        matchFound = true;
                        break;
                    }
                }
                if (!matchFound)
                {
                    if (!oneList.Contains(item))
                    {
                        oneList.Add(item);
                    }
                }
    
            }
    

    希望对您有所帮助!

    【讨论】:

      【解决方案4】:

      你可以用下一个代码 sn-p 试试:

              var result = new List<DataRow>();
              //convert to list to avoid multiple enumerations
              var table2List = Table2.AsEnumerable().ToList();
      
              foreach(var row in Table1.AsEnumerable())
              {
                  var matchingRow = table2List.FirstOrDefault(x => x["CarReg"] == row["CarReg"]);
      
                  if(matchingRow == null)
                  {
                      result.Add(row);
                  }
              }  
      

      您应该根据 CarReg 字段从 Table1 中获取不在 Table2 中的 DataRows 集合。

      【讨论】:

      • 这对我不起作用。这段代码实际上返回了更多的记录——比如笛卡尔积。澄清一下,表 1 和表 2 具有相同的主要结构。因此,如果 Table1 中的一条记录恰好在 Table2 中,它只会在 Table2 中出现一次。所以,在我的情况下,我想要当前在 Table1 中的所有记录,但记录(因为主键“CarReg”)还没有在 Table2 中
      • 我添加了应该能够完成您请求的任务的更改。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-05
      • 1970-01-01
      • 2019-09-12
      • 1970-01-01
      • 2021-06-17
      • 2020-06-29
      • 1970-01-01
      相关资源
      最近更新 更多