Как найти различия между двумя таблицами данных - PullRequest
0 голосов
/ 05 февраля 2019

Как получить разницу между двумя таблицами данных?

Глядя на это: Как сравнить 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...