web-dev-qa-db-fra.com

Comment comparer 2 dataTables

J'ai 2 tables de données et je veux juste savoir si elles sont identiques ou non. Par "le même", je veux dire, ont-ils exactement le même nombre de lignes avec exactement les mêmes données dans chaque colonne, ou non. J'aimerais écrire (trouver) une méthode qui accepte les deux tables et retourne un booléen. 

Comment puis-je comparer 2 tables de données de cette façon? Les deux ont des schémas identiques.

20
MAW74656

Vous devez parcourir les lignes de chaque table, puis chaque colonne de cette boucle pour comparer des valeurs individuelles.

Il y a un exemple de code ici: http://canlu.blogspot.com/2009/05/how-to-compare-two-datatables-in-adonet.html

7
David
 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;
  }
20
Nick Rolando

Si vous retourniez un DataTable en tant que fonction, vous pourriez:

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();
9
samneric

Le PO, MAW74656 , a initialement publié cette réponse dans le corps de la question en réponse à la réponse acceptée , comme expliqué dans ce commentaire :

J'ai utilisé cela et écrit une méthode publique pour appeler le code et renvoyer le booléen.

La réponse du PO:

Code utilisé:

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;
}
5
JDB

Essayez d'utiliser 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")})

Consultez cet article: Comparaison de DataSets avec LINQ

3
Pranay Rana

J'ai la solution pour Comment comparer 2 dataTables, c'est

http://microsoftdotnetsolutions.blogspot.in/2012/12/compare-two-datatables.html

2
sai

Si vous avez les tables dans une base de données, vous pouvez créer une jointure externe complète pour obtenir les différences. Exemple:

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

Tous les enregistrements identiques sont filtrés. Il existe des données dans les deux premiers ou les deux derniers champs, en fonction de la table d'origine de l'enregistrement.

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

Il n'y a rien là-bas qui va faire cela pour vous; le seul moyen d'y parvenir est de parcourir toutes les lignes/colonnes et de les comparer.

0
CodingGorilla

ou cela, je n'ai pas implémenté la comparaison de tableaux, vous aurez donc du plaisir aussi

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
}
0
Davide Piras

Eh bien, si vous utilisez un DataTable, alors plutôt que de comparer deux 'DataTables', vous pouvez simplement comparer le DataTable qui va avoir des modifications avec les données d'origine lorsqu'il a été chargé AKA DataTable.GetChanges, méthode (DataRowState)

0
Coops