如何获取两个数据表之间的差异?
正在查看:How to compare 2 dataTables
我尝试过:
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."
正在查看:How to get difference between two DataTables
我尝试过:
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 *”构建的,但最终将可以更改为选择某些字段。
是的,我可以遍历行和列,但这需要进行排序。并且由于可以使用任何表,因此我必须从SQL服务器提取PK数据,然后将其附加到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!"
只要获得表,pkey和字段,我都不在乎如何获得结果
编辑:查找不匹配的主键的解决方案。仍然需要检查数据类型,但是当此逻辑完成后,应该很容易地包含非主键列:
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