2013-02-21 20 views
20

Mam te dwa pliki danych i chcę uzyskać różnicę między nimi. Oto przykład:Jak uzyskać różnicę między dwoma DataTables

Table1 
------------------------- 
ID | Name 
-------------------------- 
1 | A 
2 | B 
3 | C 
-------------------------- 

Table2 
------------------------- 
ID | Name 
-------------------------- 
1 | A 
2 | B 
-------------------------- 

Chcę tylko wynikiem danych, która jest w tabela1 a nie w tabela2 (tabela1-Tabela 2)

ResultTable 
------------------------- 
ID | Name 
-------------------------- 
3 | C 
-------------------------- 

Starałem się używać tych dwóch podobnych rozwiązań poprzez Linq ale zawsze zwraca tabelę1, a nie tabelę1-tabelę2. Oto pierwsze rozwiązanie:

DataTable table1= ds.Tables["table1"]; 
DataTable table2= ds.Tables["table2"]; 
var diff= table1.AsEnumerable().Except(table2.AsEnumerable(),DataRowComparer.Default); 

drugie rozwiązanie:

var dtOne = table1.AsEnumerable(); 
var dtTwo = table2.AsEnumerable(); 
var difference = dtOne.Except(dtTwo); 

Więc, gdzie jest błąd? Bardzo dziękuję za wszystkie twoje odpowiedzi. :)

+2

Oprócz kontroli, czy są one takie same, czy nie. Nie są jednak takie same ich właściwości. Możesz użyć przeciążenia, które akceptuje EqualityComparer lub możesz zbadać metodę rozszerzenia ExceptBy(), która jest zaimplementowana w różnych bibliotekach LINQ +, także w Jon Skeets MoreLinq (http://code.google.com/p/morelinq/) – Tormod

+2

@ Tormod, ale jaki jest pożytek z 'DataRowComparer' w swoim pierwszym rozwiązaniu? Nadpisuje 'public bool Equals (TRow leftRow, TRow rightRow)', aby porównać rzeczywiste wartości kolumn. – hometoast

+2

Czy możesz pokazać, jak odzyskujesz dane? Czy to możliwe, że dane są inne, niż się spodziewasz? Zrobiłem krótką próbkę w LINQPad i twoje pierwsze rozwiązanie wydaje się działać dobrze. – goric

Odpowiedz

7

Można spróbować następujący kod ...

table1.AsEnumerable().Where(
    r =>!table2.AsEnumerable().Select(x=>x["ID"]).ToList().Contains(r["ID"])).ToList(); 
1

Postaram się zrobić to na poziomie kolumny zamiast DataTable.

IEnumerable<int> id_table1 = table1.AsEnumerable().Select(val=> (int)val["ID"]); 
IEnumerable<int> id_table2 = table2.AsEnumerable().Select(val=> (int)val["ID"]); 
IEnumerable<int> id_notinTable1= id_table2.Except(id_table1); 

Wystarczy dodanie .Select() na odpowiedź ...

0

Spróbuj poniżej podejście:

Inicjalizacja:

var columnId = new DataColumn("ID", typeof (int)); 
var columnName = new DataColumn("Name", typeof (string)); 
var table1 = new DataTable(); 
table1.Columns.AddRange(new[] {columnId, columnName}); 
table1.PrimaryKey = new[] {columnId}; 
table1.Rows.Add(1, "A"); 
table1.Rows.Add(2, "B"); 
table1.Rows.Add(3, "C"); 

var table2 = table1.Clone(); 
table2.Rows.Add(1, "A"); 
table2.Rows.Add(2, "B"); 
table2.Rows.Add(4, "D"); 

Rozwiązanie:

var table3 = table1.Copy(); 
table3.AcceptChanges(); 
table3.Merge(table2); 

var distinctRows = from row in table3.AsEnumerable() 
        where row.RowState != DataRowState.Modified 
        select row; 

var distintTable = distinctRows.CopyToDataTable(); 

Przede Soluti on działa również wtedy, gdy w tabeli 2 znajdują się nowe wiersze, których nie ma w tabeli1.

distintTable constains C i D.

0

Spróbuj poniżej, to jest dość proste. Połącz dwa zestawy razem i uzyskaj różnicę. Jeśli zestawy nie są odpowiednio wyrównane, to nie zadziała.

DataSet firstDsData = new DataSet(); 
DataSet secondDsData = new DataSet(); 
DataSet finalDsData = new DataSet(); 
DataSet DifferenceDataSet = new DataSet(); 
finalDsData.Merge(firstDsData); 
finalDsData.AcceptChanges(); 
finalDsData.Merge(secondDsData); 
DifferenceDataSet = finalDsData.GetChanges(); 
5

Właśnie przeżyłem to i chciałem podzielić się moimi odkryciami. Dla mojej aplikacji jest to mechanizm synchronizacji danych, ale myślę, że zobaczysz, jak to dotyczy oryginalnego pytania.

W moim przypadku, miałem DataTable że reprezentowane danych mojego ostatni przesyłanie i kiedyś w przyszłości, trzeba uzyskać stan danych prąd i przesłać tylko różnice.

// get the Current state of the data 
DataTable dtCurrent = GetCurrentData(); 

// get the Last uploaded data 
DataTable dtLast = GetLastUploadData(); 
dtLast.AcceptChanges(); 

// the table meant to hold only the differences 
DataTable dtChanges = null; 

// merge the Current DataTable into the Last DataTable, 
// with preserve changes set to TRUE 
dtLast.Merge(dtCurrent, true); 

// invoke GetChanges() with DataRowState.Unchanged 
// !! this is the key !! 
// the rows with RowState == DataRowState.Unchanged 
// are the differences between the 2 tables 
dtChanges = dtLast.GetChanges(DataRowState.Unchanged); 

Mam nadzieję, że to pomoże.Walczyłem z tym przez kilka godzin, a znaleźć wiele fałszywie prowadzi na interwebz, a skończyło się na porównywaniu RowStates po połączeniu kilku różnych sposobów

+0

Kiedy próbuję tego wszystkiego, wydostaję się z GetChanges, to połączenie zestawów, a nie różnicy. –

1

Spróbuj

DataTable dtmismatch = Table1.AsEnumerable().Except(Table2.AsEnumerable(), DataRowComparer.Default).CopyToDataTable<DataRow>(); 
1

Spróbuj poniżej, jest dość podstawowy. Połącz dwa zestawy razem i uzyskaj różnicę. Jeśli zestawy nie są odpowiednio wyrównane, to nie zadziała. Próba przetestowania tego samego

DataSet firstDsData = new DataSet(); 
DataSet secondDsData = new DataSet(); 
DataSet finalDsData = new DataSet(); 
DataSet DifferenceDataSet = new DataSet(); 
finalDsData.Merge(firstDsData); 
finalDsData.AcceptChanges(); 
finalDsData.Merge(secondDsData); 
DifferenceDataSet = finalDsData.GetChanges(); 
Powiązane problemy