比较两个记录集变量给出类型不匹配

Posted

技术标签:

【中文标题】比较两个记录集变量给出类型不匹配【英文标题】:Compare two recordset variables gives type mismatch 【发布时间】:2013-11-23 12:07:18 【问题描述】:

我有一个包含多个子表单的绑定表单。其中一些子表单可以有 0 条或更多条记录,而另一些则有 1 条或更多条记录。 该表单始终以只读方式打开,并且上面有一个“编辑”和一个“关闭”按钮。 当用户单击编辑按钮时,我将当前记录的内容与子表单的所有记录一起保存,以便当他/她单击关闭按钮时,我可以询问是否保存,如果没有,则丢弃更改从保存的记录中恢复。 到目前为止,这是编辑按钮的代码(其中GclnAllCnts 是字典类型的全局变量):

Private Sub EditLibroBtn_Click()
    On Error GoTo Err_EditLibroBtn_Click
    Dim lngID         As Long
    Dim ctlCnt        As Control
    Dim rs            As Recordset
    lngID = Me.ID
    Set GclnAllCnts = New Dictionary
    GclnAllCnts.Add Me.Name, Me.RecordsetClone
    For Each ctlCnt In Me.Controls
        If (ctlCnt.ControlType = acSubform) Then
            Set rs = ctlCnt.Form.RecordsetClone
            If rs.RecordCount > 0 Then
                GclnAllCnts.Add ctlCnt.Name, ctlCnt.Form.RecordsetClone
            Else
                GclnAllCnts.Add ctlCnt.Name, Null
            End If
        End If
    Next
    DoCmd.Close acForm, Me.Name
    DoCmd.OpenForm GCstMainFrmName, , , "ID = " & lngID, acFormEdit, acDialog

Exit_EditLibroBtn_Click:
    Set ctlCnt = Nothing
    Set rs = Nothing
    Exit Sub

Err_EditLibroBtn_Click:
    MsgBox err.Description & vbNewLine & "Error number: " & err.Number, vbCritical, "Errore"
    Resume Exit_EditLibroBtn_Click
End Sub

这是关闭按钮的代码:

Private Sub ChiudiBtn_Click()
    On Error GoTo Err_ChiudiBtn_Click
    Dim intBoxAwr   As Integer
    Dim stSQL       As String
    Dim vKey        As Variant
    Dim ctlCnt      As Control
    Dim clnAllCnts  As Dictionary
    Dim bSaveNeeded As Boolean
    bSaveNeeded = False
    If (Me.AllowEdits And Me.ID <> "" And Not IsNull(Me.ID)) Then
        Set clnAllCnts = New Dictionary
        clnAllCnts.Add Me.Name, Me.RecordsetClone
        For Each ctlCnt In Me.Controls
            If (ctlCnt.ControlType = acSubform) Then
                Set rs = ctlCnt.Form.RecordsetClone
                If rs.RecordCount > 0 Then
                    clnAllCnts.Add ctlCnt.Name, ctlCnt.Form.RecordsetClone
                Else
                    clnAllCnts.Add ctlCnt.Name, Null
                End If
            End If
        Next
       If clnAllCnts.Count <> GclnAllCnts.Count Then
            bSaveNeeded = True
        Else
            For Each vKey In clnAllCnts.keys()
                If Not GclnAllCnts.Exists(vKey) Then
                    bSaveNeeded = True
                    Exit For
                Else
'*********** Next Gives error **********
                    If clnAllCnts.Item(vKey) <> GclnAllCnts.Item(vKey) Then
                        bSaveNeeded = True
                        Exit For
                    End If
                End If
            Next
        End If
        If bSaveNeeded Then
            intBoxAwr = MsgBox("Salvare le modifiche al libro?", vbYesNo + vbQuestion, "Salvare")
            If intBoxAwr = vbYes Then
        'etc., omitting code
End Sub

我得到的错误是 Type mismatch (nr. 13),它由 &lt;&gt; 比较给出(我可以 Debug.print IsNull(clnAllCnts.Item(vKey))IsNull(GclnAllCnts.Item(vKey))如何比较两个记录集变量?

【问题讨论】:

【参考方案1】:

通过简单地说If rst1 &lt;&gt; rst2 来比较两个Recordset 对象无论如何都可能是冒险的,因为这到底意味着什么?如果rst1rst2 真的 是不同的对象(即使它们属于相同的对象类型),这样的表达式每次都可以很好地返回True

您似乎对两个 Recordset 的 内容 是否相同感兴趣。在这种情况下,我倾向于序列化记录集数据并存储生成的String,而不是存储Recordset 对象本身。

在这种情况下,以下 VBA 函数可能会有所帮助。它遍历记录集对象并生成包含当前记录集数据的类似 JSON 的字符串。

(请注意,该函数不一定会生成有效的 JSON。它不会转义非打印字符,如 vbCrvbLf。它不会转义反斜杠 (\)。它将所有值存储为“字符串”或null。换句话说,在其当前形式下,它并非旨在生成稍后可以反序列化的字符串。)

Private Function rstSerialize(ByVal rst As DAO.Recordset)
    ' loop through the recordset and generate a JSON-like string
    '     NB: This code will NOT necessarily produce valid JSON!
    '
    Dim s As String, fld As DAO.Field, rowCount As Long, fldCount As Long

    s = ""
    If Not (rst.BOF And rst.EOF) Then
        rst.MoveFirst
        rowCount = 0
        Do Until rst.EOF
            If rowCount > 0 Then
                s = s & ", "
            End If
            s = s & """row"": "
            fldCount = 0
            For Each fld In rst.Fields
                If fldCount > 0 Then
                    s = s & ", "
                End If
                s = s & """" & fld.Name & """: " & IIf(IsNull(fld.Value), "null", """" & fld.Value & """")
                fldCount = fldCount + 1
            Next
            s = s & ""
            rowCount = rowCount + 1
            rst.MoveNext
        Loop
    End If
    s = s & ""
    rstSerialize = s
End Function

数据示例:如果记录集包含

DonorID  Amount
-------  ------
      1      10
      2      20

函数会返回字符串

"row": "DonorID": "1", "Amount": "10", "row": "DonorID": "2", "Amount": "20"

用法示例:在包含子表单的表单上,主表单上的按钮可以执行以下操作

Private Sub Command3_Click()
    Dim rst As DAO.Recordset, originalState As String
    Set rst = Me.MemberDonationsSubform.Form.RecordsetClone
    originalState = rstSerialize(rst)
    rst.MoveFirst
    rst.Edit
    rst!Amount = rst!Amount + 1
    rst.Update
    Debug.Print "(Recordset updated.)"
    If rstSerialize(rst) = originalState Then
        Debug.Print "Recordset does not appear to have changed."
    Else
        Debug.Print "Recordset appears to have changed."
    End If
End Sub

这将在 VBA 即时窗口中打印以下内容

(Recordset updated.)
Recordset appears to have changed.

【讨论】:

以上是关于比较两个记录集变量给出类型不匹配的主要内容,如果未能解决你的问题,请参考以下文章

如何比较 Oracle 中的记录集或记录组?

根据某些匹配变量分离数据集

Excel VBA - 搜索范围和连接的 SQL ADODB 记录集以在列中匹配写入结果集

asp中怎么把取得的记录集的内容赋值给一个变量或者数组

SQL中两个记录集的区别

应该在 bigquery 中提取不匹配的记录