使用 vba 在访问查询中传递参数值

Posted

技术标签:

【中文标题】使用 vba 在访问查询中传递参数值【英文标题】:Passing Parameter Value in Access Query using vba 【发布时间】:2014-02-23 10:00:06 【问题描述】:

我们的要求 -

我们的供应商很少,我们希望生成每月每个供应商的采购报告并导出到 Excel。我认为解决方案是创建一个参数查询,我可以在其中传递供应商 ID、月份和年份的值。供应商列表不断变化并存储在单独的表中。 因此,基本上,我应该能够从该表中顺序读取供应商 ID,并将其作为参数传递给我的查询以生成该供应商的报告。

我为我的要求找到的最接近的解决方案是 on(本质上相似) -

Exporting Recordset to Spreadsheet

http://answers.microsoft.com/en-us/office/forum/office_2010-customize/filtering-a-query-used-by-docmdtransferspreadsheet/06d8a16c-cece-4f03-89dc-89d240436693

为什么我认为会有更好的解决方案 -

在建议的解决方案中,我们创建了多个查询并删除了这些查询。从概念上讲,我觉得应该有一种方法可以创建参数查询并使用 do while 循环将参数的值(上例中的 DeptName)顺序传递给查询并将结果导出到 excel。

如果我可以使用 vba 将值传递给参数查询,我应该能够实现这一点。那是我还没有弄清楚的。

2 月 24 日更新 -

以下是我写的代码 -

Private Sub Monthly_Supplier_Sales_Report_Click()
Dim strDirectoryPath As String
Dim DateFolderName As String
DateFolderName = Format$((DateSerial(year(Date), month(Date), 1) - 1), "YYYY MM")
strDirectoryPath = "C:\dropbox\Accounting\Sales Reports\" & DateFolderName
If Dir(strDirectoryPath, vbDirectory) = "" Then MkDir strDirectoryPath

Dim Filename As String
Dim strSQL1 As String
Dim strSQL2 As String
Dim DesignerCode As String
Dim month1 As String
Dim year1 As Integer
Dim Query1 As DAO.QueryDef
Dim query2 As DAO.QueryDef
Dim rsDesigner As DAO.Recordset

Set rsDesigner = CurrentDb.OpenRecordset("Designer Details Master")

Do While Not rsDesigner.EOF
DesignerCode = rsDesigner![Designer Code]
month1 = "Jan" 'right now hardcoded, will call this programatically
year1 = 2014   'right now hardcoded, will call this programatically

strSQL1 = "SELECT * FROM [Sales Report Generation Data] WHERE [designer code] = '" & DesignerCode & "' AND [Shipping Month]= '" & month1 & "' AND [Shipping Year]=" & year1

strSQL2 = "SELECT * FROM [Sales Report Generation - Monthwise Inventory Snapshot] WHERE [designer code] = '" & DesignerCode & "' AND [Snapshot Month]= '" & month1 & "' AND [Snapshot Year]= " & year1

Set Query1 = CurrentDb.CreateQueryDef(Name:="TempSalesQuery", SQLText:=strSQL1)
Set query2 = CurrentDb.CreateQueryDef(Name:="TempInventoryQuery", SQLText:=strSQL2)

Filename = strDirectoryPath & "\" & DesignerCode & Format$(Now(), " yyyy mm") & ".xls"
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, "TempSalesQuery", Filename, False, "Sales Report"
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, "TempInventoryQuery", Filename, False, "Inventory"

CurrentDb.QueryDefs.Delete "TempSalesQuery"
CurrentDb.QueryDefs.Delete "TempInventoryQuery"

rsDesigner.MoveNext
Loop

End Sub

相反,我要应用的逻辑是 -

Do While Not 
assign Value to Parameter 1 = rsDesigner![Designer Code]
assign Value to Parameter 2 = Month1
assign Value to Parameter 3 = Year1
Run the two Parameter queries, for which about three parameters are the input value and export to excel in respective sheets.
Loop

只是我还没有弄清楚 - 如何实现这一点。

【问题讨论】:

不确定您已经走了多远,或者您是否对发布的链接中列出的步骤感到满意,但这是我的建议。 (1) 用 (a) 一个 12 个月的列表框创建一个简单的表单; (b) 多年的列表框; (c) 供应商的列表框/组合框 ** 如果您总是想为所有供应商运行报告,请省略; (d) 提交报告的命令按钮; (e) 在按钮单击事件中添加 VBA 代码以从列表框/组合框中选择值以创建记录集过滤器,然后打开通过过滤器的报告。如果您对这种方法感兴趣,我可以添加有关如何完成的更多详细信息。 我已经能够按照两个链接中给出的解决方案编写代码并获得所需的结果。但只是我觉得应该有更好的解决方案。即使按照您的建议,我也想知道为什么我们必须创建表单来获取值,因为我的计划是使用它在每个月的 4 号 / 5 号运行一次,以获取所有供应商上个月的报告.因此,理想情况下,我们应该能够使用 vba 代码定义月份、年份和供应商的值。 当然,您可以让它自动运行——我只是想您可能希望灵活地在任何时候运行报告——如果您只需要某个选定的供应商,那么它也可以运行。如您附加的链接中所示,不需要删除查询 - 您可以使用查询“TransferSpreadsheet”(至少在 Office 2010 及更高版本中)。您应该让您的查询接受日期和供应商的参数(或函数)(除非您想要所有供应商),然后只需在 VBA 中设置参数。 编辑上面的问题 - 包括我根据给出的两个解决方案使用的代码。 【参考方案1】:

这是一种解决方案。请注意,我创建了两个查询将使用的函数。 只需创建两个查询并保存它们(请参阅下面的示例 SQL),添加代码以选择日期,一切都会好起来的。

Option Compare Database
Option Explicit

Dim fvShipMonth     As String
Dim fvShipYear      As Integer
Dim fvDesignerCode  As String

Public Function fShipMonth() As String
    fShipMonth = fvShipMonth
End Function

Public Function fShipYear() As Integer
    fShipYear = fvShipYear
End Function

Public Function fDesignerCode() As String
    fDesignerCode = fvDesignerCode
End Function

Private Sub Monthly_Supplier_Sales_Report_Click()
Dim Filename    As String
Dim strSQL1     As String
Dim strSQL2     As String
Dim DesignerCode As String
Dim month1      As String
Dim year1       As Integer
Dim rsDesigner  As DAO.Recordset

'SAMPLE SQL
'SELECT * FROM [Sales Report Generation Data] " & _
'WHERE [designer code] = '" & fDesignerCode() & "' AND [Shipping Month]= '" & fShipMonth() & "' AND [Shipping Year]=" & fShipYear()

    fvShipMonth = "Jan"
    fvShipYear = 2014
    Set rsDesigner = CurrentDb.OpenRecordset("Designer Details Master")
    Do While Not rsDesigner.EOF
        fvDesignerCode = rsDesigner![Designer Code]
        Filename = strDirectoryPath & "\" & DesignerCode & Format$(Now(), " yyyy mm") & ".xls"
        DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, "<your Query 1>", Filename, False, "Sales Report"
        DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, "<your Query 2>", Filename, False, "Inventory"
        rsDesigner.MoveNext
    Loop
    rsDesigner.Close
    Set rsDesigner = Nothing
End Sub

【讨论】:

您好,感谢您的解决方案。但这似乎对我不起作用。实际上,我花了一些时间来弄清楚公共函数等的概念。但是这些函数似乎没有返回任何值。我插入了一个 msgbox 并验证函数返回空白/零。可能是什么原因?我做错了吗? 我不知道您是如何实现我的建议的 - 您是否复制了所有代码?您的 msgbox 在哪里 - 在“Sub Monthly_Supplier_Sales_Report_Click”内?请注意,我在 22 小时前编辑了我的代码,因为我忘记了 SQL 中函数名称后面的 ()。还要小心,因为变量名与函数名相似!!以下是使用上述方法进行测试的方法: (1) 在您设置 fvShipMonth & fvShipYear 之后放置以下 msgbox: MsgBox "Mo: " & fvShipMonth & vbTab & "Yr: " & fvShipYear & vbTab & "fMo: " & fShipMonth( ) & vbTab & "fYr:" & fShipYear() 1.复制模块中的公共函数,2. 修改参数查询以设置三个参数的值等于 fshipmonth() 等等,3. 复制粘贴您的代码,4. 更新 transferspreadsheat 方法中的查询名称。这创建了 excel 文件,但都是空的。因此,在循环中创建了一个消息框 - MsgBox (fDesignerCode() & ", " & fShipMonth() & ", " & fShipYear()) this returned , ,0 我刚刚运行了你的 msgbox 并得到了 |, Jan, 2014|这意味着您设置错误。请用两行手动覆盖 msgbox 之前的值:fvShipMonth = "Jan" 和 fvShipYear = 2014 然后看看你的 msgbox 产生了什么。 还是没有运气!我认为该功能的设置方式有问题,我无法弄清楚。但无论如何,我喜欢你提供的解决方案,我学到了一些新东西。非常感谢!【参考方案2】:
    打开您的数据库 创建一个新模块 粘贴以下代码 将光标放在函数 TEST_MY_CODE() 中 按 F5

    将即时窗口中的结果粘贴到您的回复中。

    Option Compare Database
    Option Explicit
    
    Dim fvShipMonth     As String
    Dim fvShipYear      As Integer
    Dim fvDesignerCode  As String
    
    Public Function fShipMonth() As String
        fShipMonth = fvShipMonth
    End Function
    
    Public Function fShipYear() As Integer
        fShipYear = fvShipYear
    End Function
    
    Public Function fDesignerCode() As String
        fDesignerCode = fvDesignerCode
    End Function
    
    Function TEST_MY_CODE()
        My_Click_EVENT      ' Test the code I provided
    End Function
    
    Private Sub My_Click_EVENT()
    Dim month1      As String
    Dim year1       As Integer
    
    fvShipMonth = "Jan"
    fvShipYear = 2014
    Debug.Print "**** START TEST ****"
    Debug.Print "fvShipMonth = " & fvShipMonth
    Debug.Print "fvShipYear = " & fvShipYear
    Debug.Print "fShipMonth() = " & fShipMonth()
    Debug.Print "fShipYear() = " & fShipYear()
    Debug.Print "**** END TEST ****"
    
    End Sub
    

【讨论】:

以上是关于使用 vba 在访问查询中传递参数值的主要内容,如果未能解决你的问题,请参考以下文章

VB中过程调用时有几种参数传递方式,说明其区别

为 VBA 记录集传递参数

VBA的有参过程定义,形参用啥说明

访问报表传递参数到子报表查询

VBA Object对象的函数参数传递

访问:从表单传递参数到查询