【问题标题】:ADO Recordset exits VBA Function when writing to excel but works as a SubADO 记录集在写入 excel 时退出 VBA 函数但作为子工作
【发布时间】:2018-08-24 09:13:58
【问题描述】:

将 Excel 2016 64 位与 Access DB 结合使用。我创建了一个从数据库中获取历史数据的函数。它在调试窗口中运行并填充记录集。但是,一旦我尝试将数据写入 Excel 工作表,VBA 就会直接退出而不会出现错误。

我尝试了几种将数据填充到 excel 中的不同方法,包括 .copyfromrecordset、将数据转换为字符串、传递给临时变量。没运气。如果我运行与 Sub 相同的代码(根据需要进行调整),它会完美运行。如果我尝试先将值传递给 sub,然后再传递给工作表,它也会失败。只要涉及功能,它就会失败。我已经搜索了答案,但找不到任何东西。有任何想法吗?

Function DAM_DD(Type_input As String, Tenor_input As String, Field_output As String, Optional Date_input As String, Optional Date_input2 As String, Optional target_cell As Range) As Variant
  Dim rst As ADODB.Recordset
  Dim cnt As ADODB.Connection
  Dim stQuery As String, tbl_input As String, tenor_coupon As String

'<<< Bunch of code to fill in sql variables >>>

stQuery = "Select " & Field_output & " From " & tbl_input & " Where (" & 
Date_input & " and Type=""" & Type_input & """ and " & tenor_coupon & ");"

'Execute query and return to a recordset
    Call DAM_DB_Connection(stQuery, rst, cnt)

'Return results to excel
    If rst.RecordCount <= 1 Then
       DAM_DD = rst.Fields(0).Value
    Else: Call Get_DAM_Hist(rst, target_cell)
    End If

'Close database connection and clean up
    Call Close_DB(rst, cnt)
End Function

Sub DAM_DB_Connection(stQuery As String, rst As ADODB.Recordset, cnt As ADODB.Connection)
  Dim cmd As ADODB.Command
  Dim stcon As String 'SQL Connection string

  Set cnt = New ADODB.Connection
  Set rst = New ADODB.Recordset
  Set cmd = New ADODB.Command

'Define database connection string
    stcon = "Provider=Microsoft.ACE.OLEDB.16.0;"    
    stcon = stcon + "Data Source='C:\Users\DAM_DB.accdb';"

'Open database connection
    cnt.ConnectionString = stcon
    cnt.Open
    cmd.CommandType = adCmdText
    cmd.ActiveConnection = cnt 'Set the command connection string
    cmd.CommandText = stQuery 

'Execute query and return to a recordset
    rst.CursorLocation = adUseClient 'Needed for recordset count
    rst.CursorType = adOpenKeyset
    rst.Open stQuery, cnt, adOpenDynamic, adLockOptimistic, adCmdText
    rst.MoveFirst

'Close connection in separate Sub Close_DB
End Sub

Sub Get_DAM_Hist(rst As ADODB.Recordset, target_cell As Range)
  Dim ws As Worksheet
  Dim Rw As Long, Col As Long, rst_end As Long, counter As Long
  Dim rst_array As Variant, target_array As Variant

  Set ws = Worksheets("Sheet1")
  rst_end = rst.RecordCount
  ReDim rst_array(0 To rst_end, 0 To rst_end)

  rst_array = rst.GetRows(rst.RecordCount)
  PrintArray rst_array, target_cell 

'    counter = 1
'    Do While rst.EOF = False
'            ws.Cells(counter, 8) = rst.Fields(0) <- Alternate version that fails Here
'            ws.Cells(counter, 9) = rst.Fields(1)
'            counter = counter + 1
'            rst.MoveNext
'    Loop
End Sub

Sub PrintArray(Data As Variant, target_cell As Range)
  Dim Rw As Integer, Cl As Integer, i As Integer, j As Integer
  Dim out_string As String

Rw = Range(target_cell).Row
Cl = Range(target_cell).Column

For i = LBound(Data, 1) To UBound(Data, 1)
    For j = LBound(Data, 1) To UBound(Data, 1)
        out_string = Trim(CStr(Data(i, j)))
        Activesheet.Cells(Rw, Cl) = out_string    '<--------- Fails here
        Cl = Cl + 1
    Next j
        Rw = Rw + 1
Next i

End Sub

【问题讨论】:

  • 感谢您的链接。评估命令对我有用。

标签: excel ms-access ado adodb


【解决方案1】:

如果我运行与 Sub 相同的代码(根据需要进行调整),它会完美运行。

VBA 中的 UDF(用户定义函数)有一些限制,这会阻止它改变环境,简而言之,您不能真正操作或写入未传递给函数的单元格或工作表,您不能输出到其他范围等。因此,函数不能将记录集(或其一部分)输出到工作表。函数不能将数组写入工作表,甚至不能将单个值写入不同的单元格。

你可以用一个非常基本的函数来最简单地观察这一点,如下所示,它总是会失败:

Option Explicit
Function myfunction(v)
    [A1].Value = v
    myfunction = 1
End Function

Via Microsoft, for a longer explanation:

工作表单元格中的公式调用的用户定义函数不能 更改 Microsoft Excel 的环境。这意味着这样一个 函数不能执行以下任何操作:

  • 在电子表格中插入、删除或格式化单元格。
  • 更改另一个单元格的值。向工作簿移动、重命名、删除或添加工作表。
  • 更改任何环境选项,例如计算模式或屏幕视图。
  • 为工作簿添加名称。
  • 设置属性或执行大多数方法。

目的 用户自定义函数是允许用户创建自定义的 附带的功能中未包含的功能 微软 Excel。 Microsoft Excel 中包含的功能也不能 改变环境。函数可以执行计算 将值或文本返回到输入它们的单元格。 任何环境变化都应通过使用视觉 基本子程序。

在计算过程中,Excel 会检查单元格的先例 包含用户定义的函数。如果不是所有的先例都是 计算过程中计算到目前为止,Excel最终 调用用户定义的函数并将 Null 或 Empty 单元格传递给 功能。 Excel 然后确保发生足够的计算传递 用于计算所有先例。在最终计算期间 传递,用户定义的函数被传递的当前值 细胞。这可能会导致用户定义的函数被调用更多 经常出乎意料,并且有意想不到的争论。所以, 用户定义的函数可能会返回意外的值。

为了正确计算,计算中使用的所有范围 应该作为参数传递给函数。如果你没有通过 计算范围作为参数,而不是引用范围 在函数的 VBA 代码中,Excel 无法解释它们 在计算引擎中。因此,Excel 可能无法充分 计算工作簿以确保计算所有先例 在计算用户定义函数之前。

TL;DR

您不能将其作为函数运行。将其作为子程序运行。

(从技术上讲,我相信有一些方法可以绕过这个限制,至少在某些情况下有效,但我通常不会推荐它们)

看这里:

Using a UDF in Excel to update the worksheet

这里:

UDF for array formulas created from macro

这里:

Excel: Change background color of a cell to RGB color written in that cell

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-18
    • 2017-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多