【问题标题】:How do I compare two datatables如何比较两个数据表
【发布时间】:2011-01-15 07:58:40
【问题描述】:

我有一个包含 72 列的数据表。

我将使用 VSTO 将其下载到 Excel 表中,效果很好。

现在用户将更改这些行中的一个或所有这些行,并且还将插入一个新行。

考虑先下载的数据表为dtA,在excel表中修改后的数据表为dtB。

我想比较 dtA 和 dtB。

我需要找出 dtB 中所有不存在于 dtA 中的行。

我不能为每一行都放置 foreach 循环并评估它是一种非常不整洁的编码方式。

有什么更好的方法来做到这一点?

我是这样做的,

    DataTable dtA = new DataTable();
    dtA.Columns.Add("ENo");
    dtA.Columns.Add("ENo1");
    dtA.Columns.Add("ENo2");
    dtA.Columns.Add("ENo3");
    dtA.Columns.Add("ENo4");

    for (int i = 0; i < 5; i++)
    {
        DataRow dr = dtA.NewRow();
        dr[0] = "Part 0 " + i.ToString();
        dr[1] = "Part 1 " + i.ToString();
        dr[2] = "Part 2 " + i.ToString();
        dr[3] = "Part 3 " + i.ToString();
        dr[4] = "Part 4 " + i.ToString();
        dtA.Rows.Add(dr);
    }

    DataTable dtB = new DataTable();
    dtB.Columns.Add("ENo");
    dtB.Columns.Add("ENo1");
    dtB.Columns.Add("ENo2");
    dtB.Columns.Add("ENo3");
    dtB.Columns.Add("ENo4");

    for (int i = 5; i < 10; i++)
    {
        DataRow dr = dtB.NewRow();
        dr[0] = "Part 0 " + i.ToString();
        dr[1] = "Part 1 " + i.ToString();
        dr[2] = "Part 2 " + i.ToString();
        dr[3] = "Part 3 " + i.ToString();
        dr[4] = "Part 4 " + i.ToString();
        dtB.Rows.Add(dr);
    }

    Response.Write("\n");
    Response.Write("dt A");
    Response.Write("\n");

    for (int i = 0; i < dtA.Rows.Count; i++)
    {
        Response.Write(dtA.Rows[i][i].ToString());
        Response.Write("\n");
    }

    Response.Write("\n");
    Response.Write("dt B");
    Response.Write("\n");
    for (int i = 0; i < dtB.Rows.Count; i++)
    {
        Response.Write(dtB.Rows[i][i].ToString());
        Response.Write("\n");
    }

    var VarA = dtA.AsEnumerable();
    var varB = dtA.AsEnumerable();

    var diff = VarA.Except(varB);
    Response.Write("except");
    foreach (var n in diff)
    {
        Response.Write(n.Table.Rows[0].ToString());

    }

但我不知道在 foreach var 中使用什么, 请问我应该用什么?

【问题讨论】:

    标签: c#


    【解决方案1】:
    SELECT id FROM dtB WHERE id NOT IN (SELECT id FROM dtA)
    

    【讨论】:

    • 感谢 James 的回答,但这只会获取新行,那么 dtA 中的行会被修改吗
    • 您的原始问题未指定查找更改。由于 excel 没有“ON UPDATE CURRENT TIMESTAMP”列的能力,您可以尝试在电子表格中创建一个宏来挂钩 Worksheet_Change 事件。见ozgrid.com/forum/showthread.php?t=63176&page=1
    【解决方案2】:

    也许LINQ for DataSets(这只是表示数据集支持 LINQ 并且是 .NET 3.5+ 框架的一部分的事实)可能是一种选择。特别是,查看ExceptRows Set Pattern,它只使用了IEnumerable.Except。如果行包含一些“唯一 ID”是最简单的,但它应该足以涵盖行本身唯一缺失和/或检测是否有任何行被修改的情况。

    还有QueryADataSet——我所知道的唯一一个“支持Data[Set|Table] 上的SQL 语法”的产品(尽管可能[微弱地] 认为LINQ 提供了“SQL 语法”)。开发许可证是 200 美元一个流行音乐,但它可能是值得的,视情况而定。 (我与该产品没有任何关系,也没有尝试过该产品;我在尝试寻找类似问题的解决方案时偶然发现了它,但最终只是改变了我的方法。)

    编码愉快。

    【讨论】:

    • 嗨,pst。我尝试了来自网站eggheadcafe.com/tutorials/aspnet/… 的编码,它工作正常,但我观察到当 Ienumerable 之一确实具有值时,它会引发强制转换错误。我给了 if newRec.count()>0 然后做一些工作,如果没有计数它会抛出错误,无法将 dbnull 转换为十进制。有什么解决办法
    【解决方案3】:
    SELECT dtB.* FROM dtB LEFT JOIN dtA ON dtB.id=dtA.id /* AND ...  */
    WHERE dtA.id IS NULL
    

    您只会看到 dtB 中与 dtA 不匹配的行。

    您可以添加任何需要相同的列,以便在 JOIN 条件中计为同一行。

    根据数据库,可能有更简单的方法。例如,Oracle 有 MINUS 关键字,用于删除完全相同的行;已修改的行仍会出现在结果中。

    或者:您可以将两个 Excel 文件导出为文本(CSV、制表符分隔、...),前提是它们的行顺序相同,并使用命令行实用程序 diff 来查看发生了什么变化。

    您的编程语言可能有一个库可以实现差异算法,因此您可以在内存中完成所有操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-20
      • 2015-09-26
      • 2021-07-29
      相关资源
      最近更新 更多