【问题标题】:DataTable column compare and write differences to a another columnDataTable 列比较差异并将差异写入另一列
【发布时间】:2019-07-25 09:55:06
【问题描述】:

我正在用 c# 编写一个应用程序,它可以自动比较两个不同数据库中的值。

数据以两个 .xlsx 文件的形式提供。这些由最终用户加载到应用程序中。然后从这两个文件创建内存中的 DataTable。每人一份。

现在我需要将 DataTable 1 中的第 1 列与 DataTable 2 中的第 3 列进行比较。 内容的顺序不一样,但它们都是数字值。 有几种可能的结果:

  • 所有单元格匹配(但不按顺序)。换句话说,DataTable 1 的第 1 列中的所有单元格也位于 DataTable 2 的第 3 列中。没有其他细胞存在。

  • DataTable 1 的第 1 列中存在一个单元格,DataTable 2 的第 3 列中不存在该单元格。在这种情况下,我想将这些单元格写入单独的工作表。我正在使用 closedXML,并且已经创建并呈现了一个工作簿。

  • DataTable 2 的第 3 列中存在一个单元格,DataTable 1 的第 1 列中不存在该单元格。在这种情况下,我想将这些单元格写入单独的工作表。我正在使用 closedXML,并且已经创建并呈现了一个工作簿。

我考虑过创建一个接受两个参数的函数。两个数据表。然后将对表一的第一列和表三的第三列进行比较。

我正在研究的另一个解决方案是通过 ClosedXML 将两个 DataTables 粘贴到工作表中。将相关列(1 和 3)提取到另一个单独的工作表,并使用 for each 循环比较两个工作表中的所有单元格并获取差异。但我不知道如何继续下去,将不在第 1 列但在第 3 列的内容放到工作表 A 中,将在第 1 列但不在第 3 列的内容放到工作表 B 中。

【问题讨论】:

    标签: c# datatable closedxml


    【解决方案1】:

    您可以使用 Linq 查找第 1 列中的内容,而不是第 3 列中的内容,反之亦然。

    您只需添加 System.Data.DataSetExtensions 以引用您的项目,例如 here

    然后是 Linq 查询:

    var dataTable1 = new DataTable();
    dataTable1.Columns.Add(new DataColumn("Data Column 1"));
    
    dataTable1.Rows.Add(1, "", "");
    dataTable1.Rows.Add(3, "", "");
    dataTable1.Rows.Add(5, "", "");
    dataTable1.Rows.Add(7, "", "");
    dataTable1.Rows.Add(9, "", "");
    
    var dataTable2 = new DataTable();
    dataTable2.Columns.Add(new DataColumn("Data Column 1"));
    dataTable2.Columns.Add(new DataColumn("Data Column 2"));
    dataTable2.Columns.Add(new DataColumn("Data Column 3"));
    
    dataTable2.Rows.Add("", "", 1);
    dataTable2.Rows.Add("", "", 2);
    dataTable2.Rows.Add("", "", 4);
    dataTable2.Rows.Add("", "", 6);
    dataTable2.Rows.Add("", "", 7);
    dataTable2.Rows.Add("", "", 8);
    dataTable2.Rows.Add("", "", 9);
    
    // Use the id of the column
    var column1 = dataTable1.AsEnumerable().Select(r => r.ItemArray[0]).ToList();
    var column3 = dataTable2.AsEnumerable().Select(r => r.ItemArray[2]).ToList();
    
    // Use the name of the column
    var column1WithName = dataTable1.AsEnumerable().Select(r => r.Field<string>("Data Column 1")).ToList();
    var column3WithName = dataTable2.AsEnumerable().Select(r => r.Field<string>("Data Column 3")).ToList();
    
    // All element of the Column 1 (DataTable1) that are not in Column 3 (DataTable2)
    var column1Without3 = column1.Except(column3).ToList(); // [ "3", "5" ]
    // All element of the Column 3 (DataTable2) that are not in Column 1 (DataTable1)
    var column3Without1 = column3.Except(column1).ToList(); // [ "2", "4", "6", "8" ]
    

    【讨论】:

    • 谢谢。就比较而言,它现在正在工作。但它总是采用 DataTable 的最后一列。第一个 DataTable 共有 4 列,第二个 DataTable 共有 6 列。第一个 DataTable 的第一列和第二个 DataTable 的第三列是包含可比较值的列。我尝试将您的代码更改为直接索引引用,但它仍然需要 DataTables 的最后一列进行实际比较(因此它需要第一个 DataTable 的第四列和第二个 DataTable 的第六列)
    • @JB1989 您是否更改了 2 变量 column1 和 column3 的 ItemArray[] ?您也可以尝试使用列的名称。我在 datatable1 中添加了 2 列,代码仍然有效
    • 我做到了。我是否通过字符串或索引位置使用列的名称并不重要。它总是从两个数据表中获取最后一列。
    • @JB1989 你能提供更多关于你的数据表的细节吗?如果它适用于我的 2 张桌子而不是你的桌子,我帮不了你
    • 我明白了。感谢您到目前为止的帮助。实际上,在直接从 DataTable 中提取相关列然后使用您提供的 LINQ except 方法之后,我自己使用传统的 for each 循环来解决这个问题。由于某种原因,lambda 表达式无法正常工作。尝试使用 5 列的 DataTable 和 7 列的 DataTable,然后尝试使用 lambda 和 Linq except 方法检索第 1 列和第 3 列。它将提供其他预期的输入。
    猜你喜欢
    • 2018-01-12
    • 1970-01-01
    • 2014-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-26
    • 1970-01-01
    • 2016-09-05
    相关资源
    最近更新 更多