【问题标题】:Either EOF or BOF is true (recordset comes empty) - ADO connection Excel VBA / ACCESSEOF 或 BOF 为真(记录集为空) - ADO 连接 Excel VBA / ACCESS
【发布时间】:2015-11-30 09:00:30
【问题描述】:

所以我有一个包含多个表的访问数据库,用于存储公司的数据。我在 Access 中设计了几个查询来提取一些信息。

从 Excel VBA,我使用 ADO 连接连接到 Access 数据库并提取存储的查询。我已经这样做了好几次了,而且效果很好。但我的一个查询没有返回任何结果:记录集返回“EOF 或 BOF 为真”。

当我在 ACCESS 中打开查询时,ACCESS 会提示我输入参数“GICS_SUB_INDUSTRY_NAME”,如果我输入参数,它会返回一个包含值的表。所以查询在 ACCESS 中运行良好,但在 Excel VBA 中却不行。

查询的SQL语句如下:

PARAMETERS GICS_SUB_INDUSTRY_NAME Text ( 255 );
SELECT STOCK_STATIC.NAME, Focus_MAXHistoryDate.MaxOfHistory_Date, Focus_MAXHistoryDate.Isin, STOCK_DYNAMIC.CUR_MKT_CAP, STOCK_HIST_IS_BS_CF.BS_TOT_LIAB2, STOCK_HIST_IS_BS_CF.PREFERRED_EQUITY__MINORITY_INT, STOCK_HIST_IS_BS_CF.BS_CASH_NEAR_CASH_ITEM, STOCK_STATIC.GICS_SUB_INDUSTRY_NAME
FROM ((Focus_MAXHistoryDate INNER JOIN STOCK_HIST_IS_BS_CF ON (Focus_MAXHistoryDate.Isin = STOCK_HIST_IS_BS_CF.Isin) AND (Focus_MAXHistoryDate.MaxOfHistory_Date = STOCK_HIST_IS_BS_CF.History_Date)) INNER JOIN STOCK_STATIC ON Focus_MAXHistoryDate.Isin = STOCK_STATIC.ISIN) INNER JOIN STOCK_DYNAMIC ON Focus_MAXHistoryDate.Isin = STOCK_DYNAMIC.Isin
WHERE (((STOCK_STATIC.GICS_SUB_INDUSTRY_NAME)=[GICS_SUB_INDUSTRY_NAME]));

这是我在 Excel VBA 中的代码:

Sub Pull_Stock_Peers_Leverage()

'define general variables
Dim Connection As ADODB.Connection
Dim Command As ADODB.Command
Dim GICS_SUB_INDUSTRY_NAME As ADODB.Parameter
Dim RecordSetL As ADODB.RecordSet
Dim iField As Integer
Dim Workbook As Excel.Workbook
Set Workbook = Excel.ActiveWorkbook
Dim Start As Excel.Worksheet
Set Start = ActiveWorkbook.Sheets("Start")
Dim GICS4_Range As Excel.Range
Set GICS4_Range = Excel.Range("GICS4_LookUp")

'Open connection to the AMSIR database
Set Connection = New ADODB.Connection
With Connection
    .Provider = "Microsoft.ACE.OLEDB.12.0"
    .Open "N:\Switzerland\Others\_AMSIR_Company_Database\AMSIR_Company_Database.accdb"
End With

'Open command object and pass a parameter (criteria) to the query
'The parameter name should match the parameter clause in the SQL statement?
Set Command = New ADODB.Command
With Command
    .ActiveConnection = Connection
    .CommandText = "Pull_Peers_Leverage"
    .CommandType = adCmdStoredProc
    .Parameters.Append .CreateParameter("GICS_SUB_INDUSTRY_NAME", adVarWChar, adParamInput, Len(GICS4_Range))
    .Parameters("GICS_SUB_INDUSTRY_NAME") = GICS4_Range
End With

'Create recordset by executing the command
Set RecordSetL = New ADODB.RecordSet
RecordSetL.CursorLocation = adUseClient
RecordSetL.CursorType = adOpenStatic
RecordSetL.Open Command

'Write fields from record set
Dim TargetRangeL As Excel.Range
Set TargetRangeL = Start.Range("PEERS_LEVERAGE")
Dim FieldCount As Integer
Dim i, j As Integer

FieldCount = RecordSetL.Fields.Count
i = 28
j = 37
For iField = 1 To FieldCount
    Start.Cells(i + iField, j).Value = RecordSetL.Fields(iField - 1).Name
Next

'Transpose recordset values and paste into array
Dim recArray As Variant
Dim recCount As Long

recArray = RecordSetL.GetRows
recCount = UBound(recArray, 2) + 1

TargetRangeP.Resize(FieldCount, recCount).Value = recArray

Connection.Close

End Sub

所以我确实在代码中获取了记录集,我实际上可以循环进入记录集并提取字段名称,但这些字段没有值,并且出现“BOF 或 EOF 为真或当前记录已被删除”。

我的所有其他查询都有此代码,但仅对于此查询,记录集为空。它是我唯一拥有的那种类型的查询(它确实与带有内部连接的查询和表相匹配)。

编辑:

我想知道问题是 ADO 还是我传递参数的方式,所以我决定只将 SQL 语句传递给 ACCESS,而不输入任何参数;所以我通常应该得到一个包含所有可用值的记录集。

我试过了:

Sub Test1()

Dim Connection As New ADODB.Connection
Dim Command As ADODB.Command
Dim RecordSetUF As New ADODB.RecordSet
Dim Workbook As Excel.Workbook
Set Workbook = Excel.ActiveWorkbook
Dim Start As Excel.Worksheet
Set Start = ActiveWorkbook.Sheets("Start")
Dim GICS4_Range As Excel.Range
Set GICS4_Range = Excel.Range("GICS4_LookUp")

'Open connection to the AMSIR database
Set Connection = New ADODB.Connection
With Connection
'    .Provider = "SQLOLEDB"
    .Provider = "Microsoft.ACE.OLEDB.12.0"
'    .Provider = "Microsoft.Jet.OLEDB.4.0"
    .Properties("Data Source") = "N:\Switzerland\Others\_AMSIR_Company_Database\AMSIR_Company_Database.accdb"
    .Open
End With

'Place sql statement and match it to newly created recordset
Set Command = New ADODB.Command
Command.ActiveConnection = Connection
Set RecordSetUF = New ADODB.RecordSet
Dim sql1 As String
'ACCESS accepts * for empty values but Excel VBA needs % as wild card in an SQL queryIf CompF.Text = "" Then CompF.Text = ""

sql1 = "SELECT STOCK_STATIC.NAME, Focus_MAXHistoryDate.MaxOfHistory_Date, Focus_MAXHistoryDate.Isin, STOCK_DYNAMIC.CUR_MKT_CAP, STOCK_HIST_IS_BS_CF.BS_TOT_LIAB2, STOCK_HIST_IS_BS_CF.PREFERRED_EQUITY__MINORITY_INT, STOCK_HIST_IS_BS_CF.BS_CASH_NEAR_CASH_ITEM, STOCK_STATIC.GICS_SUB_INDUSTRY_NAME FROM ((Focus_MAXHistoryDate INNER JOIN STOCK_HIST_IS_BS_CF ON (Focus_MAXHistoryDate.MaxOfHistory_Date = STOCK_HIST_IS_BS_CF.History_Date) AND (Focus_MAXHistoryDate.Isin = STOCK_HIST_IS_BS_CF.Isin)) INNER JOIN STOCK_STATIC ON Focus_MAXHistoryDate.Isin = STOCK_STATIC.ISIN) INNER JOIN STOCK_DYNAMIC ON Focus_MAXHistoryDate.Isin = STOCK_DYNAMIC.Isin;"

Command.CommandText = sql1
'Debug.Print sql1
'Debug.Print returns an SQL statement that works fine in Access!
Command.Execute

RecordSetUF.Open Command

所以基本上我有一个在 ACCESS 中可以正常工作的 sql 语句,但在 excel VBA 中却不行。

【问题讨论】:

  • 对于 Access 中的此类查询,我倾向于使用命令类型 adCmdTable 而不是 adCmdStoredProce。你可以试试看是否可行。
  • 是的,我已经尝试过了,但它不起作用。我现在尝试直接在 Excel 中编写 SQL 语句,这样做时我也得到了一个空记录集。我还简化了 SQL 语句以包含 NO 参数(这样记录集将返回数据库中的所有内容),但记录集为空(EOF 或 BOF 为真)。当我将 SQL 语句粘贴到 ACCESS 的 sql 视图中并执行它时,它工作正常,并且我以表格格式获取所有信息。
  • 我经常在数据中发现 NULL 的问题,所以我倾向于在我的查询中放置一个 IFNULL 测试并在这种情况下返回一个空白字符串“”。

标签: excel vba parameter-passing ado recordset


【解决方案1】:

您在 MS-Access 中工作,使用一种称为“Jet-SQL”的 SQL 方言。

您现在使用 Jet-SQL 在 Excel 中工作,而 MS-Access 主机应用程序为 Jet 所做的所有事情都不见了:

  • 您无权访问 VBA 本机函数(只有 Jet-SQL 本机函数,类似于 VBA 字符串的 some 和 类型转换函数)
  • 您无权访问 Access 编写的 VBA 函数 开发人员并在 MS-Access 数据库中全局声明;
  • 在 FROM 子句中声明的子查询最好是表,或者 也没有 VBA 的查询。
  • 星号通配符不会为您自动翻译成“%” (我认为你有)

这些事情无声无息地失败,或者带有误导性错误消息 - “BOF 或 EOF 为真或当前记录已被删除” - 而不是您期望的“缺少参数”或“不正确的列名”错误......

但是我开始寻找空记录集并且没有解释的地方是 FROM 子句:要么是明显的“无 MS-Access”问题之一,要么是涉及到 NULL 匹配失败的更微妙的问题或空字符串 - 很可能是 MS-Access 包装器在后台管理的另一个问题。

关于 Null 处理的快速说明:您没有 IFNULL 或 NZ,因此测试 IIF(tbl.[Field] IS NULL 是最好的选择。

【讨论】:

  • 谢谢尼罗河。我认为你的第三点是我的关键问题。我的 SQL 语句指的是我认为 MS-Access 未正确处理的子查询。我目前正在用一个字符串重写 SQL 语句,并将尝试像这样将其传递给 MS-Access。
  • 总是很乐意帮助@ZeLegend - 如果这回答了您的问题,请将其标记为“已回答”,我将继续使用 VBA 中的一个奇怪的“Stacker”。顺便说一句,'MS-Access 没有正确处理'让我担心:你的意思是'由 MS-Access 处理,但当我在 MS-Access 之外运行时不是由 MS-Jet 处理'?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多