Excel BOF或EOF为true,无法获取OLEObjects属性

Excel BOF或EOF为true,无法获取OLEObjects属性,excel,vba,Excel,Vba,我正在编写一个函数,它以起始行、结束行、列和字符串值作为输入。然后,该函数使用字符串值查询数据库,以获得与以下查询匹配的结果列表。从这里开始,从开始到最后的每一行都将添加一个组合框,并填充结果查询数据 当我试着运行这段代码时,它会以以下几种方式之一失败。以下是我的错误: 运行时错误'1021:BOF或EOF为真,或者当前记录已被删除。请求的操作需要当前记录。 或 无法获取工作表类的OLEObjects属性。 它有时适用于添加组合的第一列,只在第二列中途失败 调用函数: For i = 0 To

我正在编写一个函数,它以起始行、结束行、列和字符串值作为输入。然后,该函数使用字符串值查询数据库,以获得与以下查询匹配的结果列表。从这里开始,从开始到最后的每一行都将添加一个组合框,并填充结果查询数据

当我试着运行这段代码时,它会以以下几种方式之一失败。以下是我的错误:

运行时错误'1021:BOF或EOF为真,或者当前记录已被删除。请求的操作需要当前记录。

无法获取工作表类的OLEObjects属性。

它有时适用于添加组合的第一列,只在第二列中途失败

调用函数:

For i = 0 To numMembers - 1
    For j = 0 To UBound(toolNames) - 1
        Call AddCombos(5 + j * 5, 9 + j * 5, 5 + i * 5, Cells(5 + j * 5, 1).value)
    Next j
Next i
Function AddCombos(ByVal startRow As Integer, ByVal LastRow As Integer, ByVal columnNum As Integer, ByVal Tool As String)
    Dim MyLeft As Double
    Dim MyTop As Double
    Dim MyHeight As Double
    Dim MyWidth As Double
    Dim cnn As New ADODB.Connection
    Dim rst As New ADODB.Recordset
    Dim curcombo As Object
    Dim StrDBPath As String

    strSQL = "SELECT qryCurrent.txtLevel AS [Current], [qrylstNames-LPMi].strFullName as [Full Name], tblWCMTools.txtWCMTool" & vbNewLine & _
             "FROM (((tblPeopleWCMSkillsByYear" & vbNewLine & _
             "LEFT JOIN tblSkillLevels AS qryCurrent ON tblPeopleWCMSkillsByYear.bytCurrentID = qryCurrent.atnSkillLevelID)" & vbNewLine & _
             "INNER JOIN [qrylstNames-LPMi] ON tblPeopleWCMSkillsByYear.intPeopleID = [qrylstNames-LPMi].atnPeopleRecID)" & vbNewLine & _
             "INNER JOIN tblWCMTools ON tblPeopleWCMSkillsByYear.intWCMSkillID = tblWCMTools.atnWCMToolID)" & vbNewLine & _
             "WHERE (((tblPeopleWCMSkillsByYear.bytYearID)=Year(Date())-2012) AND qryCurrent.txtLevel >='4' AND tblWCMTools.txtWCMTool = '" & Tool & "') ORDER BY strFullName;"

    'database path
    StrDBPath = "C:\Users\T6050R0\Desktop\WCMDB_be.accdb"
    'open database
    cnn.Open "Provider=Microsoft.Ace.OLEDB.12.0;" & _
                             "Data Source=" & StrDBPath & ";" & _
                             "Jet OLEDB:Engine Type=5;" & _
                             "Persist Security Info=False;"
    rst.Open strSQL, cnn, adOpenStatic
    'Iterate through each row
    For i = startRow To LastRow
    'If it's empty, than add a checkbox
        If IsEmpty(Cells(i, columnNum)) Then
            If (Cells(i, columnNum).ColumnWidth <> 20) Then
                Cells(i, columnNum).ColumnWidth = 20
            End If
            'set position of checkbox (compared with cell that will be linked)
            MyLeft = Cells(i, columnNum).Left
            MyTop = Cells(i, columnNum).Top + 2.75
            'set size of checkbox (compared with cell that will be linked)
            MyHeight = Cells(i, columnNum).Height - 5
            MyWidth = Cells(i, columnNum).Width
            'add checkbox
            Set curcombo = ActiveSheet.OLEObjects.Add(ClassType:="Forms.ComboBox.1", Link:=True, _
                            DisplayAsIcon:=False, Left:=MyLeft, Top:=MyTop, Width:=MyWidth, Height _
                            :=MyHeight + 1.5)
            'Add a blank option first
            curcombo.Object.AddItem ""
            With Worksheets("Sheet1").OLEObjects(curcombo.Name)
                .LinkedCell = Cells(i, columnNum).Address
                'Move to first record in set
                If (i > startRow) Then
                MsgBox "yay"
                    rst.MoveFirst
                End If
                'add choices to dropdown
                For k = 1 To rst.RecordCount

                    If rst.EOF Then
                        GoTo EndForLoop
                    End If
                    .Object.AddItem rst![Full Name]
                    If Not rst.EOF Then
                        rst.MoveNext
                    Else
                        GoTo EndForLoop
                    End If
                Next k
EndForLoop:
            End With
        End If
    Next i
End Function
添加组合功能:

For i = 0 To numMembers - 1
    For j = 0 To UBound(toolNames) - 1
        Call AddCombos(5 + j * 5, 9 + j * 5, 5 + i * 5, Cells(5 + j * 5, 1).value)
    Next j
Next i
Function AddCombos(ByVal startRow As Integer, ByVal LastRow As Integer, ByVal columnNum As Integer, ByVal Tool As String)
    Dim MyLeft As Double
    Dim MyTop As Double
    Dim MyHeight As Double
    Dim MyWidth As Double
    Dim cnn As New ADODB.Connection
    Dim rst As New ADODB.Recordset
    Dim curcombo As Object
    Dim StrDBPath As String

    strSQL = "SELECT qryCurrent.txtLevel AS [Current], [qrylstNames-LPMi].strFullName as [Full Name], tblWCMTools.txtWCMTool" & vbNewLine & _
             "FROM (((tblPeopleWCMSkillsByYear" & vbNewLine & _
             "LEFT JOIN tblSkillLevels AS qryCurrent ON tblPeopleWCMSkillsByYear.bytCurrentID = qryCurrent.atnSkillLevelID)" & vbNewLine & _
             "INNER JOIN [qrylstNames-LPMi] ON tblPeopleWCMSkillsByYear.intPeopleID = [qrylstNames-LPMi].atnPeopleRecID)" & vbNewLine & _
             "INNER JOIN tblWCMTools ON tblPeopleWCMSkillsByYear.intWCMSkillID = tblWCMTools.atnWCMToolID)" & vbNewLine & _
             "WHERE (((tblPeopleWCMSkillsByYear.bytYearID)=Year(Date())-2012) AND qryCurrent.txtLevel >='4' AND tblWCMTools.txtWCMTool = '" & Tool & "') ORDER BY strFullName;"

    'database path
    StrDBPath = "C:\Users\T6050R0\Desktop\WCMDB_be.accdb"
    'open database
    cnn.Open "Provider=Microsoft.Ace.OLEDB.12.0;" & _
                             "Data Source=" & StrDBPath & ";" & _
                             "Jet OLEDB:Engine Type=5;" & _
                             "Persist Security Info=False;"
    rst.Open strSQL, cnn, adOpenStatic
    'Iterate through each row
    For i = startRow To LastRow
    'If it's empty, than add a checkbox
        If IsEmpty(Cells(i, columnNum)) Then
            If (Cells(i, columnNum).ColumnWidth <> 20) Then
                Cells(i, columnNum).ColumnWidth = 20
            End If
            'set position of checkbox (compared with cell that will be linked)
            MyLeft = Cells(i, columnNum).Left
            MyTop = Cells(i, columnNum).Top + 2.75
            'set size of checkbox (compared with cell that will be linked)
            MyHeight = Cells(i, columnNum).Height - 5
            MyWidth = Cells(i, columnNum).Width
            'add checkbox
            Set curcombo = ActiveSheet.OLEObjects.Add(ClassType:="Forms.ComboBox.1", Link:=True, _
                            DisplayAsIcon:=False, Left:=MyLeft, Top:=MyTop, Width:=MyWidth, Height _
                            :=MyHeight + 1.5)
            'Add a blank option first
            curcombo.Object.AddItem ""
            With Worksheets("Sheet1").OLEObjects(curcombo.Name)
                .LinkedCell = Cells(i, columnNum).Address
                'Move to first record in set
                If (i > startRow) Then
                MsgBox "yay"
                    rst.MoveFirst
                End If
                'add choices to dropdown
                For k = 1 To rst.RecordCount

                    If rst.EOF Then
                        GoTo EndForLoop
                    End If
                    .Object.AddItem rst![Full Name]
                    If Not rst.EOF Then
                        rst.MoveNext
                    Else
                        GoTo EndForLoop
                    End If
                Next k
EndForLoop:
            End With
        End If
    Next i
End Function
函数AddCombos(ByVal startRow为整数,ByVal LastRow为整数,ByVal columnNum为整数,ByVal Tool为字符串)
将我的左半身变暗为双半身
将我的上衣调暗为双色
我的身高是双倍
将MyWidth设置为双精度
将cnn设置为新的ADODB.连接
将rst设置为新ADODB.Recordset
Dim curcombo作为对象
作为字符串的Dim StrDBPath
strSQL=“选择qryCurrent.txtLevel作为[Current],[qrylstNames LPMi].strFullName作为[Full Name],tblWCMTools.txtWCMTool”&vbNewLine&_
“FROM”((TBLPeopelewcmskillsbyyear)和vbNewLine&_
“在tblPeopleWCMSkillsByYear.bytCurrentID=qryCurrent.atnSkillLevelID上将TblSkillLevel作为qryCurrent左连接”&vbNewLine&_
“tblPeopleWCMSkillsByYear.intPeopleID=[qrylstNames LPMi].atnPeopleRecID]上的内部联接[qrylstNames LPMi]”&vbNewLine&_
“TblPeoplewcmsskillsbyyear.intWCMSkillID=tblWCMTools.atnWCMToolID上的内部联接tblWCMTools”&vbNewLine&_
“其中((tblpeoplewcsmskillsbyyear.bytYearID)=年(日期())-2012)和qryCurrent.txtLevel>='4'和tblwcmtool.txtWCMTool='”&Tool&“)按strFullName排序;”
'数据库路径
StrDBPath=“C:\Users\T6050R0\Desktop\WCMDB_be.accdb”
"开放数据库",
cnn.Open“Provider=Microsoft.Ace.OLEDB.12.0;”_
“数据源=”&StrDBPath&“;”&_
“喷气式OLEDB:发动机类型=5;”和_
“持久化安全信息=False;”
rst.打开strSQL、cnn、adOpenStatic
'遍历每一行
对于i=开始到最后一行
'如果为空,则添加复选框
如果是空的(单元格(i,columnNum)),那么
如果(单元格(i,columnNum).ColumnWidth 20),则
单元格(i,columnNum)。ColumnWidth=20
如果结束
'设置复选框的位置(与将链接的单元格进行比较)
MyLeft=单元格(i,columnNum).Left
MyTop=单元格(i,columnNum).Top+2.75
'设置复选框的大小(与将链接的单元格相比)
MyHeight=单元格(i,columnNum)。高度-5
MyWidth=单元格(i,columnNum).Width
'添加复选框
设置curcombo=ActiveSheet.OLEObjects.Add(类类型:=“Forms.ComboBox.1”,链接:=True_
DisplayAsIcon:=False,左:=MyLeft,Top:=MyTop,Width:=MyWidth,Height_
:=我的身高+1.5)
'首先添加一个空白选项
curcombo.Object.AddItem“”
带有工作表(“Sheet1”).OLEObjects(curcombo.Name)
.LinkedCell=单元格(i,columnNum).Address
'移动到集合中的第一条记录
如果(i>startRow)那么
MsgBox“耶”
rst.MoveFirst
如果结束
'将选项添加到下拉列表
对于k=1到rst.RecordCount
如果rst.EOF,则
转到EndForLoop
如果结束
.Object.AddItem rst![全名]
如果不是rst.EOF,则
rst.MoveNext
其他的
转到EndForLoop
如果结束
下一个k
EndForLoop:
以
如果结束
接下来我
端函数

希望这能比我的评论解释得更多:
GetDatabaseReference函数只返回对数据库的引用-它将根据Excel版本更改引用

TestDatabaseConnection过程的重要一点是打开记录集后的代码——它会在遍历记录然后关闭记录集之前检查一切是否正常

Sub TestDatabaseConnection()

    Dim oDB As Object
    Dim rstMyRecordSet As Object

    'Just a reference so my SQL will work.
    Dim sName As String
    sName = "Darren"

    'This is the first time the reference runs, so it creates the reference.
    Set oDB = GetDatabaseReference(oDB)

    'oDB already holds a value now, so it's not created again - just passed straight back.
    'No need to add this line - just an example.  Usually oDB would be a global variable.
    Set oDB = GetDatabaseReference(oDB)

    Set rstMyRecordSet = CreateObject("ADODB.RecordSet")
    rstMyRecordSet.CursorType = 2
    rstMyRecordSet.Open "SELECT ID FROM tbl_TeamMembers WHERE User_Name = '" & sName & "' AND IsActive = TRUE", oDB

    'This is the important bit - check you've got records.
    If Not rstMyRecordSet Is Nothing Then
        With rstMyRecordSet
            If Not .EOF And Not .BOF Then
                .MoveFirst
                Do While Not .EOF
                    Debug.Print .Fields("User_Name")
                    .MoveNext
                Loop
            End If
        End With
    End If
    rstMyRecordSet.Close
    Set rstMyRecordSet = Nothing

End Sub

'----------------------------------------------------------------------------------
' Procedure : GetDatabaseReference
' Author    : Darren Bartrup-Cook
' Date      : 28/05/2015
' Purpose   : Sets a reference to the Outlook database.
'-----------------------------------------------------------------------------------
Public Function GetDatabaseReference(ExistingConnection As Object) As Object

    Dim cn As Object

    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    'Only set a reference to the database if it doesn't already exist. '
    ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    If ExistingConnection Is Nothing Then
        Set cn = CreateObject("ADODB.Connection")

        Select Case Val(Application.Version)
            Case 11
                'Access 2003
                cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
                    "Data Source=S:\Database\Outlook.mdb"
            Case 14
                'Access 2010
                cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
                    "Data Source=S:\Database\Outlook.mdb;" & _
                    "Persist Security Info=False;"
        End Select


        If Not cn Is Nothing Then
            Set GetDatabaseReference = cn
        End If
    Else

        ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        'oDB already has a reference, so ensure it's maintained. '
        ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        Set GetDatabaseReference = ExistingConnection
    End If

End Function

虽然在这种情况下这可能对您没有帮助,但这里有一个关于格式化SQL的建议

Public Sub aa(ByRef a As String, ByVal b As String)

    a = a & vbCrLf & b

End Sub

a = ""
aa a, "    SELECT CUR.txtLevel      AS [Current]  "
aa a, "         , NLPMi.strFullName AS [Full Name]  "
aa a, "         , TOOLS.txtWCMTool "
aa a, "      FROM ( ( ( tblPeopleWCMSKILLSByYear AS SKILLS"
aa a, "                 LEFT JOIN tblSkillLevels AS CUR  "
aa a, "                        ON SKILLS.bytCurrentID = CUR.atnSkillLevelID
aa a, "               ) "
aa a, "              INNER JOIN [qrylstNames-LPMi] AS NLPMi  "
aa a, "                      ON SKILLS.intPeopleID = NLPMi.atnPeopleRecID
aa a, "             )"
aa a, "            INNER JOIN tblWCMTools AS TOOLS "
aa a, "                    ON SKILLS.intWCMSkillID = TOOLS.atnWCMToolID"
aa a, "           ) "
aa a, "     WHERE ( ( (SKILLS.bytYearID) = YEAR(DATE())-2012 )  "
aa a, "           AND CUR.txtLevel   >= '4'  "
aa a, "           AND TOOLS.txtWCMTool = 'Tool'"
aa a, "           )  "
aa a, "  ORDER BY NLPMi.strFullName"
aa a, "  ;"

PS我在中使用实用程序将查询生成器中的SQL格式化为这种格式,请指出哪些代码行产生了错误。@MatthewD它没有说明,也没有在后面突出显示这些行。我可以看到几件事-第一件事是在SQL字符串中使用vbNewLine,每行末尾没有空格。例如,我会将SQL中的FROM行更改为“FROM”((tblPeopleWCMSkillsByYear)&\-注意结尾处的空格,没有vbNewLine。我看到的第二件事是,您没有检查是否返回了任何记录-在
rst之后。打开
行添加一个检查-
如果不是rst.BOF而不是rst.EOF,那么…如果
,则继续代码结尾的其余部分。第三项-'1到rst.RecordCount'并不总是返回正确的记录ct计数。使用
DO而不是rst.EOF
循环。@DarrenBartrup Cook感谢您的反馈!我将看看这会如何改变errors@DarrenBartrup-Cook修复了一个错误,但不是
无法获取OLEObjects属性….
我明白你关于验证那里是否有记录的意思。这部分解决了我的问题,其他问题r部分问题由Excel开发人员解决,注释:
尝试将“替换为工作表(“Sheet1”).OLEObjects(curcombo.Name)”替换为“替换为curcombo.Objec”