Как получить разницу между двумя таблицами данных?
Глядя на это: Как сравнить 2 таблицы данных
Я пробовал это:
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();
но получил это:
"Public member 'Any' on type '<ExceptIterator>d__73(Of DataRow)' not found."
Глядя на это: Как получить разницу между двумя таблицами данных
Я пробовал это:
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();
Но получите это:
?DifferenceDataSet
Nothing
Я знаю, что есть разница, потому что я положил это туда.
Я не хочу связывать таблицы, потому что приложение позволяет любому серверу и любой базе данных бытьпо сравнению.Это позволяет нам легко просматривать данные из производства, тестирования и разработки по мере необходимости.
Также обратите внимание, что таблица данных построена с использованием «SELECT *», но в конечном итоге ее можно будет изменить для выбора определенныхfields.
Да, я мог бы перебирать строки и столбцы, но это потребовало бы сортировки.И поскольку можно использовать любую таблицу, мне нужно будет извлечь данные PK с сервера SQL, добавить их в sql.Хотя это не невозможно, я надеюсь, что есть лучший способ.
Я не хочу использовать LINQ, но не прекращаю публиковать решения LINQ, поскольку они могут помочь другим.
Мой код:
Public Function GetTable(ByVal strTable As String, ByVal strServer As String, ByVal strDatabase As String, ByVal strUser As String, ByVal strPassword As String) As DataTable
Dim DT As DataTable
Using Conn As New SqlConnection
Conn.ConnectionString = [String].Format(mconSQLConnectString, strServer, strDatabase, strUser, strPassword, strDatabase)
Conn.Open()
DT = New DataTable
Using cmd As SqlCommand = New SqlCommand("SELECT * FROM " & strTable, Conn)
DT.Load(cmd.ExecuteReader(CommandBehavior.KeyInfo))
DT.Load(cmd.ExecuteReader())
End Using
End Using
Return DT
End Function
Private Sub Diff()
Dim DT As DataTable
Dim DTS As DataTable
Dim DTT As DataTable
Dim strTableName As String
Dim TableNode As TreeNode
mdictSource = New Dictionary(Of String, DataTable)
mdictTarget = New Dictionary(Of String, DataTable)
For Each TableNode In treSource.Nodes
strTableName = TableNode.Text
If TableNode.Checked Then
DTS = DA.GetTable(strTableName, cboServerSource.Text, cboDatabaseSource.Text, txtUserSource.Text, txtPasswordSource.Text)
mdictSource.Add(strTableName, DT)
DTT = DA.GetTable(strTableName, cboServerTarget.Text, cboDatabaseTarget.Text, txtUserTarget.Text, txtPasswordTarget.Text)
mdictTarget.Add(strTableName, DT)
'''''''''''''''''''''''''''''''''''''
'Method 1
Dim differences
differences = DTS.AsEnumerable().Except(DTT.AsEnumerable(), DataRowComparer.Default)
If differences.Any() Then 'Public member 'Any' on type '<ExceptIterator>d__73(Of DataRow)' not found.
DT = differences.CopyToDataTable
End If
'''''''''''''''''''''''''''''''''''''
'Method 2
Dim finalDsData = New DataSet
Dim DifferenceDataSet As DataSet
finalDsData.Merge(DTS)
finalDsData.AcceptChanges()
finalDsData.Merge(DTT)
DifferenceDataSet = finalDsData.GetChanges()
End If
Next
End Sub
Я знаю, что есть разница, потому что я его создал:
?DTt.rows(11).Item(2)
"RFQs Issued" {String}
String: "RFQs Issued"
?DTs.rows(11).Item(2)
"RFQs Issued!" {String}
String: "RFQs Issued!"
Мне все равно, как я получаю результаты, какПока я получаю таблицу, ключ и поле
РЕДАКТИРОВАТЬ: Решение для поиска несовпадающих первичных ключей.По-прежнему нужно проверять типы данных, но когда эта логика будет завершена, будет легко включить столбцы без первичного ключа:
Private Sub Diff()
Dim DGV As DataGridView
Dim DT As DataTable = Nothing
Dim DTS As DataTable
Dim DTT As DataTable
Dim strMessage As String
Dim TP As TabPage
Dim strTableName As String
Dim TableNode As TreeNode
mdictSource = New Dictionary(Of String, DataTable)
mdictTarget = New Dictionary(Of String, DataTable)
For Each TableNode In treSource.Nodes
If TableNode.Checked Then
strTableName = TableNode.Text
DGV = New DataGridView
DGV.AllowUserToAddRows = False
DGV.Dock = DockStyle.Fill
DGV.Name = "dgv" & strTableName
DGV.Visible = True
TP = New TabPage
TP.Name = "tp" & strTableName
TP.Text = strTableName
TP.Controls.Add(DGV)
tcTableResults.TabPages.Add(TP)
DTS = DA.GetTable(strTableName, cboServerSource.Text, cboDatabaseSource.Text, txtUserSource.Text, txtPasswordSource.Text)
mdictSource.Add(strTableName, DT)
DTT = DA.GetTable(strTableName, cboServerTarget.Text, cboDatabaseTarget.Text, txtUserTarget.Text, txtPasswordTarget.Text)
mdictTarget.Add(strTableName, DT)
If PrimarykeyCountMatches(DTS, DTT) Then
If PrimarykeysMatch(DGV, DTS, DTT) Then
If ColumnCountMatches(DTS, DTT) Then
If ColumnsMatch(DTS, DTT) Then
strMessage &= strTableName & " matches." & Environment.NewLine
Else
End If
Else
DisplayDiffPrimarykeys(DGV, DTS, DTT)
End If
End If
Else
DisplayDiffPrimarykeys(DGV, DTS, DTT)
End If
End If
Next
If strMessage <> String.Empty Then
MessageBox.Show(strMessage, "Results")
End If
End Sub
Private Sub DisplayDiffColumns(DGV As DataGridView, DTS As DataTable, DTT As DataTable)
End Sub
Private Sub DisplayDiffPrimarykeys(DGV As DataGridView, DTS As DataTable, DTT As DataTable)
Dim DC As DataGridViewColumn
Dim DR As DataGridViewRow
Dim intNewRow As Integer
Dim intOffset As Integer
Dim r As Integer
For r = 0 To DTS.PrimaryKey.Length - 1
DC = New DataGridViewTextBoxColumn
DC.HeaderText = "Source: PKey" & (r + 1).ToString
DC.ReadOnly = True
DGV.Columns.Add(DC)
Next
For r = 0 To DTT.PrimaryKey.Length - 1
DC = New DataGridViewTextBoxColumn
DC.HeaderText = "Target: PKey" & (r + 1).ToString
DC.ReadOnly = True
DGV.Columns.Add(DC)
Next
intNewRow = DGV.Rows.Add()
DR = DGV.Rows(intNewRow)
DR.HeaderCell.Value = "PKeys"
For r = 0 To DTS.PrimaryKey.Length - 1
DR.Cells(r).Value = DTS.PrimaryKey(r)
Next
intOffset = r
For r = 0 To DTT.PrimaryKey.Length - 1
DR.Cells(r + intOffset).Value = DTT.PrimaryKey(r)
Next
End Sub
Private Function PrimarykeyCountMatches(DTS As DataTable, DTT As DataTable) As Boolean
Return DTS.PrimaryKey.Length = DTT.PrimaryKey.Length
End Function
Private Function PrimarykeysMatch(DGV As DataGridView, DTS As DataTable, DTT As DataTable) As Boolean
Dim DC As DataGridViewColumn
Dim lisDiffSource As List(Of Integer)
Dim lisDiffTarget As List(Of Integer)
Dim DR As DataGridViewRow
Dim intIndex As Integer
Dim bMatch As Boolean = False
Dim intNewRow As Integer
Dim PKeysSource As String()
Dim PKeysTarget As String()
Dim s As IOrderedEnumerable(Of DataColumn)
Dim strSCaption As String
Dim intSIndex As Integer
Dim t As IOrderedEnumerable(Of DataColumn)
Dim strTCaption As String
Dim intTIndex As Integer
s = DTS.PrimaryKey.OrderBy(Function(c) c.Caption)
t = DTT.PrimaryKey.OrderBy(Function(c) c.Caption)
lisDiffSource = New List(Of Integer)
lisDiffTarget = New List(Of Integer)
Do
strSCaption = s(intSIndex).Caption.ToLower
strTCaption = t(intTIndex).Caption.ToLower
If strSCaption = strTCaption Then
intSIndex += 1
intTIndex += 1
Else
If strSCaption > strTCaption Then
lisDiffTarget.Add(intTIndex)
intTIndex += 1
Else 'strSCaption < strTCaption
lisDiffSource.Add(intSIndex)
intSIndex += 1
End If
End If
Loop While intSIndex < s.Count And intTIndex < t.Count
While intSIndex < s.Count
lisDiffSource.Add(intSIndex)
intSIndex += 1
End While
While intTIndex < t.Count
lisDiffTarget.Add(intTIndex)
intTIndex += 1
End While
If lisDiffSource.Count = 0 And lisDiffTarget.Count = 0 Then
bMatch = True
Else
DC = New DataGridViewTextBoxColumn
DC.HeaderText = "Table"
DC.ReadOnly = True
DGV.Columns.Add(DC)
DC = New DataGridViewTextBoxColumn
DC.HeaderText = "Column"
DC.ReadOnly = True
DGV.Columns.Add(DC)
DC = New DataGridViewTextBoxColumn
DC.HeaderText = "Status"
DC.ReadOnly = True
DGV.Columns.Add(DC)
For Each intIndex In lisDiffSource
intNewRow = DGV.Rows.Add()
DR = DGV.Rows(intNewRow)
DR.Cells(0).Value = "Source"
DR.Cells(1).Value = s(intIndex).Caption
DR.Cells(2).Value = "Missing from Target"
Next
For Each intIndex In lisDiffTarget
intNewRow = DGV.Rows.Add()
DR = DGV.Rows(intNewRow)
DR.Cells(0).Value = "Target"
DR.Cells(1).Value = t(intIndex).Caption
DR.Cells(2).Value = "Missing from Source"
Next
End If
Return bMatch
End Function
Private Function ColumnCountMatches(DTS As DataTable, DTT As DataTable) As Boolean
Return DTS.Columns.Count = DTT.Columns.Count
End Function
Private Function ColumnsMatch(DTS As DataTable, DTT As DataTable) As Boolean
Return True
End Function