【问题标题】:Getting Run-time error '3159': Not a valid bookmark while pulling SQL recordset获取运行时错误“3159”:提取 SQL 记录集时不是有效的书签
【发布时间】:2020-11-20 06:30:17
【问题描述】:

我正在尝试使用基于 frmPackingSlipHeader.JOB.REL 控件的记录填充 frmPanelUnitEntryHeader.txtJOB_NUMBER.txtRELEASE_NUMBER。在frmPackingSlipHeader 上导航记录时,.JOB.REL 被提交到gtxtCurrentJobNumbergtxtCurrentJobRelease 全局变量。我遇到了rs.FindFirst 方法,但需要大约一分钟或更长时间才能返回有效记录;找到正确的记录并按预期显示。在用.FindFirst 抱怨搜索了漫长的等待之后,我遇到了OpenRecordset 方法并使用strSQL 提取记录,但在Me.Bookmark = rs.Bookmark 上收到运行时错误“3159”消息。 frmPanelUnitEntryHeader 不是子源。

Private Sub txtJOB_NUMBER_GotFocus()

    'Used to bring up existing jobs in SUB table
    Dim rs      As Object
    Dim strSQL  As String

'    Set rs = Me.RecordsetClone
    strSQL = "SELECT * FROM MAIN_SUB WHERE [JOB_NUMBER] = '" & gtxtCurrentJobNumber & "' And RELEASE_NUMBER = '" & gtxtCurrentJobRelease & "';"
    
    Set rs = CurrentDb.OpenRecordset(strSQL)
    
    With rs
        If .RecordCount = 0 Then
            DoCmd.GoToRecord , , acNewRec
        Else
            Me.Bookmark = .Bookmark
        End If
    End With

    Set rs = Nothing
            

'    With rs
'        .FindFirst "JOB_NUMBER='" & gtxtCurrentJobNumber & "' And RELEASE_NUMBER='" & gtxtCurrentJobRelease & "'"
'        If .NoMatch Then
'            DoCmd.GoToRecord , , acNewRec
'        Else
'            Me.Bookmark = .Bookmark
'        End If
'    End With
'
'    Set rs = Nothing

End Sub

注释的行放在一起。

我在搜索错误时注意到许多网站诉诸数据库损坏和修复,但我不认为这里是这种情况。 .FindFirst 有效,但速度很慢。为什么书签在这两种方法之间的工作方式似乎不同?这与我在txtJOB_NUMBER_GotFocus() 上执行此操作有关吗? TIA。

【问题讨论】:

  • 警告,这是开放注入。您需要对查询进行参数化。#
  • ADO 允许使用参数化查询。
  • 为什么我得到一个-1?
  • 对问题投反对票的目的是表明投反对票的人认为您的问题没有帮助或缺乏研究,@Tim。我无法评论他们认为哪些是真实的(只有投反对票的人可以告诉你,他们不需要评论投反对票)。

标签: sql-server vba ms-access ms-access-forms


【解决方案1】:

如果您仔细阅读 Form.Bookmark 上的文档,它会说:

因为当打开表单时,Access 会为表单记录集中的每条记录创建一个唯一的书签,所以即使两个记录集基于相同的表、查询或 SQL 语句,一个表单的书签也不会在另一个记录集中起作用。

所以每个记录集都有不同的书签,你只能使用同一个记录集中的书签。

.RecordsetClone 是相同的记录集,但游标不同,这就是为什么 Me.Bookmark = rs.BookmarkrsMe.Recordset 的克隆时有效(如果不像 rs = CurrentDb.OpenRecordset(strSQL) 则失败)。

您可以尝试直接使用以下方法过滤记录集:

Private Sub txtJOB_NUMBER_GotFocus()
    With CurrentDb.CreateQueryDef(vbNullString) 'Temporary QueryDef to use parameters
        .SQL = "SELECT * FROM MAIN_SUB  WHERE [JOB_NUMBER] = [CurrentJobNumberParameter] And RELEASE_NUMBER = [CurrentJobReleaseParameter];"
        .Parameters("CurrentJobNumberParameter") = gtxtCurrentJobNumber
        .Parameters("CurrentJobReleaseParameter") = gtxtCurrentJobRelease
        With .OpenRecordset
            If .RecordCount = 0 Then
                Me.Recordset.NewRecord
            Else
                Set Me.Recordset = .Parent.Recordsets(.Name) ' equvalent to Set Me.Recordset = rs, but without the need of variables declaration
            End If
        End With
    End With
End Sub

此代码还展示了如何避免在 DAO 上使用参数进行注入。阅读Bobby Tables 及其Microsoft Access 部分!

【讨论】:

  • 感谢 ComputerVersteher,已实现。然而,在操作时,会提示用户输入这两个参数。这是设计使然吗?
  • OK... 不知道为什么会提示。当我在第一个 With 上使用断点单步执行时,代码会单步执行并返回预期的记录集而不会出现提示。当我不通过时,提示都会出现。哦,顺便说一下 ComputerVersteher,代码是即时的,当它没有提示时,非常感谢。
  • 您的函数gtxtCurrentJobNumbergtxtCurrentJobRelease 中可能存在问题?用静态值替换它们。如果没有提示,则显示相关代码。
  • 您的代码很慢,因为您首先从 sql server 获取大量数据,然后在 ms 访问客户端上对其进行过滤,而无法使用索引。我的代码在 sql server 上过滤,只获取小的结果数据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-04
  • 2017-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多