2011-09-22 80 views
16

我有2個數據表,我只是想知道它們是否相同。 「相同」,我的意思是他們有完全相同數量的行,每列中的數據完全相同,或者沒有。我很想寫(找到)接受兩個表並返回一個布爾值的方法。如何比較2個數據表

如何以這種方式比較2個數據表?兩者都有相同的模式。

+0

這已經在這裏問:http://stackoverflow.com/questions/164144/c-how-to-compare-two -datatables -ab-how-to-show-rows-which-in-b-but-not問題並不完全相同。在你的情況下,你需要遍歷行,並在該循環內循環遍歷行中的列來比較值。 – David

+0

@DavidStratton -Sorry,這不是同一個問題。 – MAW74656

+0

想要這樣做的目的是爲了給它一些背景? – Coops

回答

0

沒有什麼會爲你做到這一點;要實現這一點,唯一的方法是迭代所有行/列並將它們相互比較。

+0

- .NET的下一個版本將包括一個DataTable.CompareTo(DataTable)方法來爲我們處理這個問題。 – MAW74656

1

如果在數據庫中的表,你可以做一個完全外部連接,以獲得差異。例如:

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 

所有記錄是相同的被過濾掉。在前兩個或後兩個字段中都有數據,具體取決於記錄來自哪個表。

+0

- 我想在不涉及SQL服務器的情況下進行比較(嘗試保存到DB的往返行程),因此在這種情況下這不適合我。 – MAW74656

2

儘量讓使用LINQ到數據集

(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")}) 

檢查這篇文章:Comparing DataSets using LINQ

+0

- 我沒有在問題中指定這個(因此+1),但我想避免LINQ,所以我可以在.NET 2.0的工作站上運行。是的,它的跛腳,但它的一種要求。 – MAW74656

17
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; 
    } 
+0

- 是的,我明白這可以如何工作。我可能會看到它是否比其他選項快。 PizzaTime! – MAW74656

+0

代碼不可編譯,也應該使用!Equals而不是'!='運算符。查看帖子http://geekswithblogs.net/mnf/archive/2013/08/27/methods-to-verify-are-datatables-or-datasets-the-same.aspx –

0

或此,我並沒有實現數組對比,所以你也會有一些樂趣:)

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 
} 
+1

*嘆息我需要學習linq –

+0

感謝小修正;-) –

+0

@Davide Piras -Loser的使用循環?如果你針對比.NET 3.5更低的東西進行編程會怎樣?這是一個苛刻的人。 – MAW74656

5

的OP,MAW74656,最初發布在提問身體這個答案響應accepted answer,在解釋數據表this comment

我用這個,寫了一個公共方法來調用代碼並返回布爾值。

的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; 
} 
6

如果您正在返回一個DataTable作爲一個功能你可以:

DataTable dataTable1; // Load with data 
DataTable dataTable2; // Load with data (same schema) 

    var differences = 
     dataTable1.AsEnumerable().Except(dataTable2.AsEnumerable(), 
              DataRowComparer.Default); 

    return differences.Any() ? differences.CopyToDataTable() : new DataTable(); 
+0

不錯,根據這個 – netfed

+0

但是當你從表中刪除一行時,不顯示差異。哼! – netfed

1
/// <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()); 
     } 
    }