如何比较两个数据表

本文关键字:数据表 两个 比较 何比较 | 更新日期: 2023-09-27 18:09:35

我有2个数据表,我只是想知道它们是否相同。通过"相同",我的意思是它们是否具有完全相同的行数,每列中具有完全相同的数据。我想写(找到)一个方法,接受两个表,并返回一个布尔值。

我如何以这种方式比较两个数据表?

如何比较两个数据表

 public static bool AreTablesTheSame( DataTable tbl1, DataTable tbl2)
 {
    if (tbl1.Rows.Count != tbl2.Rows.Count || tbl1.Columns.Count != tbl2.Columns.Count)
                return false;

    for ( int i = 0; i < tbl1.Rows.Count; i++)
    {
        for ( int c = 0; c < tbl1.Columns.Count; c++)
        {
            if (!Equals(tbl1.Rows[i][c] ,tbl2.Rows[i][c]))
                        return false;
        }
     }
     return true;
  }

如果你要返回一个DataTable作为一个函数,你可以:

DataTable dataTable1; // Load with data
DataTable dataTable2; // Load with data (same schema)
// Fast check for row count equality.
if ( dataTable1.Rows.Count != dataTable2.Rows.Count) {
    return true;
}
var differences =
    dataTable1.AsEnumerable().Except(dataTable2.AsEnumerable(),
                                            DataRowComparer.Default);
return differences.Any() ? differences.CopyToDataTable() : new DataTable();

您需要遍历每个表的行,然后遍历该循环中的每个列,以比较单个值。

这里有一个代码示例:http://canlu.blogspot.com/2009/05/how-to-compare-two-datatables-in-adonet.html

OP MAW74656最初在问题正文中发布了这个答案,作为对被接受的答案的回应,正如这条评论所解释的:

我使用它并编写了一个公共方法来调用代码并返回布尔值。

OP的答案:

代码:

public bool tablesAreTheSame(DataTable table1, DataTable table2)
{
    DataTable dt;
    dt = getDifferentRecords(table1, table2);
    if (dt.Rows.Count == 0)
        return true;
    else
        return false;
}
//Found at http://canlu.blogspot.com/2009/05/how-to-compare-two-datatables-in-adonet.html
private DataTable getDifferentRecords(DataTable FirstDataTable, DataTable SecondDataTable)
{
    //Create Empty Table     
    DataTable ResultDataTable = new DataTable("ResultDataTable");
    //use a Dataset to make use of a DataRelation object     
    using (DataSet ds = new DataSet())
    {
        //Add tables     
        ds.Tables.AddRange(new DataTable[] { FirstDataTable.Copy(), SecondDataTable.Copy() });
        //Get Columns for DataRelation     
        DataColumn[] firstColumns = new DataColumn[ds.Tables[0].Columns.Count];
        for (int i = 0; i < firstColumns.Length; i++)
        {
            firstColumns[i] = ds.Tables[0].Columns[i];
        }
        DataColumn[] secondColumns = new DataColumn[ds.Tables[1].Columns.Count];
        for (int i = 0; i < secondColumns.Length; i++)
        {
            secondColumns[i] = ds.Tables[1].Columns[i];
        }
        //Create DataRelation     
        DataRelation r1 = new DataRelation(string.Empty, firstColumns, secondColumns, false);
        ds.Relations.Add(r1);
        DataRelation r2 = new DataRelation(string.Empty, secondColumns, firstColumns, false);
        ds.Relations.Add(r2);
        //Create columns for return table     
        for (int i = 0; i < FirstDataTable.Columns.Count; i++)
        {
            ResultDataTable.Columns.Add(FirstDataTable.Columns[i].ColumnName, FirstDataTable.Columns[i].DataType);
        }
        //If FirstDataTable Row not in SecondDataTable, Add to ResultDataTable.     
        ResultDataTable.BeginLoadData();
        foreach (DataRow parentrow in ds.Tables[0].Rows)
        {
            DataRow[] childrows = parentrow.GetChildRows(r1);
            if (childrows == null || childrows.Length == 0)
                ResultDataTable.LoadDataRow(parentrow.ItemArray, true);
        }
        //If SecondDataTable Row not in FirstDataTable, Add to ResultDataTable.     
        foreach (DataRow parentrow in ds.Tables[1].Rows)
        {
            DataRow[] childrows = parentrow.GetChildRows(r2);
            if (childrows == null || childrows.Length == 0)
                ResultDataTable.LoadDataRow(parentrow.ItemArray, true);
        }
        ResultDataTable.EndLoadData();
    }
    return ResultDataTable;
}

尝试使用linq to Dataset

(from b in table1.AsEnumerable()  
    select new { id = b.Field<int>("id")}).Except(
         from a in table2.AsEnumerable() 
             select new {id = a.Field<int>("id")})

查看这篇文章:使用LINQ比较数据集

    /// <summary>
    /// https://stackoverflow.com/a/45620698/2390270
    /// Compare a source and target datatables and return the row that are the same, different, added, and removed
    /// </summary>
    /// <param name="dtOld">DataTable to compare</param>
    /// <param name="dtNew">DataTable to compare to dtOld</param>
    /// <param name="dtSame">DataTable that would give you the common rows in both</param>
    /// <param name="dtDifferences">DataTable that would give you the difference</param>
    /// <param name="dtAdded">DataTable that would give you the rows added going from dtOld to dtNew</param>
    /// <param name="dtRemoved">DataTable that would give you the rows removed going from dtOld to dtNew</param>
    public static void GetTableDiff(DataTable dtOld, DataTable dtNew, ref DataTable dtSame, ref DataTable dtDifferences, ref DataTable dtAdded, ref DataTable dtRemoved)
    {
        try
        {
            dtAdded = dtOld.Clone();
            dtAdded.Clear();
            dtRemoved = dtOld.Clone();
            dtRemoved.Clear();
            dtSame = dtOld.Clone();
            dtSame.Clear();
            if (dtNew.Rows.Count > 0) dtDifferences.Merge(dtNew.AsEnumerable().Except(dtOld.AsEnumerable(), DataRowComparer.Default).CopyToDataTable<DataRow>());
            if (dtOld.Rows.Count > 0) dtDifferences.Merge(dtOld.AsEnumerable().Except(dtNew.AsEnumerable(), DataRowComparer.Default).CopyToDataTable<DataRow>());
            if (dtOld.Rows.Count > 0 && dtNew.Rows.Count > 0) dtSame = dtOld.AsEnumerable().Intersect(dtNew.AsEnumerable(), DataRowComparer.Default).CopyToDataTable<DataRow>();
            foreach (DataRow row in dtDifferences.Rows)
            {
                if (dtOld.AsEnumerable().Any(r => Enumerable.SequenceEqual(r.ItemArray, row.ItemArray))
                    && !dtNew.AsEnumerable().Any(r => Enumerable.SequenceEqual(r.ItemArray, row.ItemArray)))
                {
                    dtRemoved.Rows.Add(row.ItemArray);
                }
                else if (dtNew.AsEnumerable().Any(r => Enumerable.SequenceEqual(r.ItemArray, row.ItemArray))
                    && !dtOld.AsEnumerable().Any(r => Enumerable.SequenceEqual(r.ItemArray, row.ItemArray)))
                {
                    dtAdded.Rows.Add(row.ItemArray);
                }
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.ToString());
        }
    }

没有任何东西可以为你做到这一点;完成此操作的唯一方法是遍历所有行/列,并将它们相互比较。

如果你正在使用一个数据表,那么,而不是比较两个'数据表',你可以只是比较数据表,将有原始数据的变化,当它被加载AKA数据表。GetChanges Method (DataRowState)

或者这个,我没有实现数组比较,所以你也会有一些乐趣:)

public bool CompareTables(DataTable a, DataTable b)
{
    if(a.Rows.Count != b.Rows.Count)
    {
        // different size means different tables
        return false;
    }
    for(int rowIndex=0; rowIndex<a.Rows.Count; ++rowIndex)
    {
        if(!arraysHaveSameContent(a.Rows[rowIndex].ItemArray, b.Rows[rowIndex].ItemArray,))
        {
            return false;
        }
    }
    // Tables have same data
    return true;
}
private bool arraysHaveSameContent(object[] a, object[] b)
{
    // Here your super cool method to compare the two arrays with LINQ,
    // or if you are a loser do it with a for loop :D
}

灵感来自samneric使用DataRowComparer的答案。默认值,但需要一些只比较数据表内列的子集的东西,我做了一个DataTableComparer对象,您可以指定在比较中使用哪些列。如果它们有不同的列/模式,那就更棒了。

DataRowComparer。Default可以工作,因为它实现了IEqualityComparer。然后我创建了一个对象,您可以在其中定义将比较DataRow的哪些列。

public class DataTableComparer : IEqualityComparer<DataRow>
{
    private IEnumerable<String> g_TestColumns;
    public void SetCompareColumns(IEnumerable<String> p_Columns)
    {
        g_TestColumns = p_Columns; 
    }
    public bool Equals(DataRow x, DataRow y)
    {
        foreach (String sCol in g_TestColumns)
            if (!x[sCol].Equals(y[sCol])) return false;
        return true;
    }
    public int GetHashCode(DataRow obj)
    {
        StringBuilder hashBuff = new StringBuilder();
        foreach (String sCol in g_TestColumns)
            hashBuff.AppendLine(obj[sCol].ToString());               
        return hashBuff.ToString().GetHashCode();
    }
}

可以这样使用:

DataTableComparer comp = new DataTableComparer();
comp.SetCompareColumns(new String[] { "Name", "DoB" });
DataTable celebrities = SomeDataTableSource();
DataTable politicians = SomeDataTableSource2();
List<DataRow> celebrityPoliticians = celebrities.AsEnumerable().Intersect(politicians.AsEnumerable(), comp).ToList();

合并两个数据表然后比较变化如何?我不确定这是否能100%满足你的需求,但为了快速比较,它会起作用的。

public DataTable GetTwoDataTablesChanges(DataTable firstDataTable, DataTable secondDataTable)
{ 
     firstDataTable.Merge(secondDataTable);
     return secondDataTable.GetChanges();
}

你可以阅读更多关于DataTable.Merge()

这里的

如果数据库中有这些表,则可以执行一个完整的外连接来获取差异。例子:

select t1.Field1, t1.Field2, t2.Field1, t2.Field2
from Table1 t1
full outer join Table2 t2 on t1.Field1 = t2.Field1 and t1.Field2 = t2.Field2
where t1.Field1 is null or t2.Field2 is null

所有相同的记录将被过滤掉。根据记录来自哪个表,前两个字段或最后两个字段中都有数据。