You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VBA中DLookup返回2950保留错误的问题求助

Access DLookup错误2950问题解决

问题描述

使用Excel 2016和Access 2016,此前在家运行正常的代码,在办公室及后续在家环境中,以下DLookup语句返回2950错误:

varX = DLookup("[Código]", "Campanha", "[Cod Produto] = " & EntradaBD.Fields("Cod Produto").Value)

仅通过程序ADODB连接数据库时出错,手动打开Access数据库后错误消失,其他数据库操作函数在数据库关闭时可正常工作,完整代码如下:

Private Sub cbgrupo_Change()
Dim fonteBD As String
Dim varX As Variant

Set EntradaBD = New ADODB.Recordset

ConectaAccess

If Me.cbgrupo.Value = "TODOS" Then
    fonteBD = "Select * FROM [BancoDados] WHERE [Grupo] is not null ORDER BY [Cod Produto]"
Else
    fonteBD = "Select * FROM [BancoDados] WHERE [Grupo] = '" & Me.cbgrupo.Value & "' ORDER BY [Cod Produto]"
End If
EntradaBD.Open fonteBD, conectabd, adOpenKeyset, adLockReadOnly

If Not (EntradaBD.EOF And EntradaBD.BOF) Then
    EntradaBD.MoveFirst 
    
    Do Until EntradaBD.EOF = True
    varX = DLookup("[Código]", "Campanha", "[Cod Produto] = " & EntradaBD.Fields("Cod Produto").Value)
    If IsNull(varX) Then
        Me.ListBox1.AddItem EntradaBD.Fields("Cod Produto").Value
        Me.ListBox1.List(Me.ListBox1.ListCount - 1, 1) = EntradaBD.Fields("Produto").Value
    End If

    EntradaBD.MoveNext
    Loop
    
End If

If Not EntradaBD Is Nothing Then EntradaBD.Close


'fecha a conexão com o BD
DesconectaAccess

错误原因

DLookup是Access VBA的内置函数,它依赖Access应用程序实例的运行上下文。当仅通过ADODB连接数据库时,并没有启动Access实例,DLookup无法定位到目标数据库的环境,因此抛出2950错误。手动打开Access时,Access实例已运行并加载了数据库,上下文存在,所以DLookup能正常工作。

解决方案

方法1:用ADODB查询替代DLookup(推荐)

直接通过已有的ADODB连接执行查询,获取需要的[Código]值,无需依赖Access实例。修改循环内的代码如下:

Do Until EntradaBD.EOF = True
    Dim rsCampanha As New ADODB.Recordset
    Dim codProduto As Variant
    codProduto = EntradaBD.Fields("Cod Produto").Value
    
    ' 构建查询语句(注意如果Cod Produto是文本类型,需要加单引号)
    Dim sqlCampanha As String
    If IsNumeric(codProduto) Then
        sqlCampanha = "SELECT [Código] FROM [Campanha] WHERE [Cod Produto] = " & codProduto
    Else
        sqlCampanha = "SELECT [Código] FROM [Campanha] WHERE [Cod Produto] = '" & Replace(codProduto, "'", "''") & "'"
    End If
    
    rsCampanha.Open sqlCampanha, conectabd, adOpenForwardOnly, adLockReadOnly
    If rsCampanha.EOF Then
        varX = Null
    Else
        varX = rsCampanha.Fields("[Código]").Value
    End If
    rsCampanha.Close
    Set rsCampanha = Nothing
    
    If IsNull(varX) Then
        Me.ListBox1.AddItem EntradaBD.Fields("Cod Produto").Value
        Me.ListBox1.List(Me.ListBox1.ListCount - 1, 1) = EntradaBD.Fields("Produto").Value
    End If

    EntradaBD.MoveNext
Loop

注意:如果Cod Produto是文本类型,必须在值前后加单引号,并且要转义值内的单引号(用Replace函数替换为两个单引号),避免SQL语法错误和注入风险。

方法2:启动Access实例并打开数据库

如果一定要使用DLookup,可以在连接数据库前启动Access实例并打开目标数据库,确保上下文存在:

Private Sub cbgrupo_Change()
Dim fonteBD As String
Dim varX As Variant
Dim accessApp As Access.Application ' 声明Access实例

Set EntradaBD = New ADODB.Recordset
Set accessApp = New Access.Application
accessApp.OpenCurrentDatabase "你的Access数据库路径" ' 替换为实际路径

ConectaAccess

' 后续原有代码保持不变...

' 最后关闭Access实例
accessApp.CloseCurrentDatabase
Set accessApp = Nothing

DesconectaAccess

这种方法需要确保客户端机器安装了Access,且性能不如直接用ADODB查询高效。

额外建议

原代码中拼接Grupo条件的SQL语句存在SQL注入风险,建议改用参数化查询:

If Me.cbgrupo.Value = "TODOS" Then
    fonteBD = "Select * FROM [BancoDados] WHERE [Grupo] is not null ORDER BY [Cod Produto]"
Else
    fonteBD = "Select * FROM [BancoDados] WHERE [Grupo] = ? ORDER BY [Cod Produto]"
End If
EntradaBD.Open fonteBD, conectabd, adOpenKeyset, adLockReadOnly
EntradaBD.Parameters(0).Value = Me.cbgrupo.Value

内容的提问来源于stack exchange,提问作者Lucas Portela

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 11:01:19