我在MS Office应用程序(用于自动化和ETL过程)中有多年的VBA经验,但直到最近才需要在MS Access中弄乱表单。我正在为我设计的数据库设计一些简单的数据提取表单,并挂在一个看似简单的任务上。
目标:我需要一个数据表子表单来显示从主窗体上的控件动态生成的SQL语句返回的记录。
在我的主窗体上,我有一个按钮,当用户单击它时,按钮会将用户在其他用户窗体控件中指定的信息编译成SQL查询,然后运行该查询,以便子窗体显示结果记录。
无论我做什么,我都无法让它发挥作用。我一直得到(大部分时间)微软视觉基本运行时错误“'2467':你输入的表达式是指一个已关闭或不存在的对象。”这是我用下面显示的代码得到的错误。我无法弄清楚我是否需要在任何代码运行或什么时候立即启动子表单。我已经尝试了其他代码论坛中也没有用过的其他代码变体,但我似乎找到了一些论坛帖子,其中包括一些关于Stack Overflow的论坛帖子,建议我下面的代码应该有效。
附图显示了基本主要表单的外观。我已经标记了用户单击的按钮(btnDisplaySWData)来编译从尚未包含的控件创建的SQL,但这不是问题。我只是对代码片段中显示的SQL语句进行了硬编码,试图弄清楚这个问题。如前所述,我希望记录显示在名为dataDisplaySubform的子表单中。 “JUNK”是Access数据库中的一个表,我可以使用下面的SQL代码合法地查询,我只是用于测试目的,直到我弄清楚这一点。显示的数据表单中的所有代码(名为frmDataExtract)都包含在下面的代码窗口中。
Option Compare Database
Option Explicit
Public Sub btnDisplaySWData_Click()
Dim pSQL As String
pSQL = "SELECT JUNK.agency_ID, JUNK.agency_desc FROM JUNK"
Me.dataDisplaySubform.Form.RecordSource = pSQL
End Sub
表单名为dataDisplaySubform,如下面选中子窗体的属性屏幕截图所示。
这就是整体表单布局的样子
我已经搜索了几个论坛网站,并且已经尝试了搜索Stack Overflow的每个术语变体,以找到我的问题的潜在解决方案,但是即使原始帖子被发布者标记为已解决,也没有任何工作。我花了太多时间,大约2个工作日,试图弄清楚我做错了什么,但还没有。
我感谢任何能帮助我指引正确方向的人,这让我很生气。
感谢, --TB
解决方案由TURKISHGOLD编辑
嗯,我认为我自己想出来了虽然HansUp帮助我走上了路径,提到子表单源Source Object没有分配任何东西。在我的情况下,将源对象分配给表单并不是HansUp建议的正确解决方案。相反,保存的查询似乎可以让它做我想做的事。
不确定是否有更好的方法可以执行此操作,但似乎您需要设置一个虚拟的,几乎占位符查询,因此您可以在VBA中将子表单源对象设置为它。 像这样的占位符查询:
SELECT * FROM JUNK WHERE JUNK.agency_ID ="_";
上述Access查询保存为名称“TESTQUERY”。它不显示任何内容,但满足了将Source Object分配给某些东西的需要,实质上是在窗体视图中查看主窗体时实例化子窗体。因此,使用占位符保存的查询,然后您可以通过主窗体上的用户界面控件将RecordSource重新分配给任何SQL String放在一起,如下所示:
Public Sub btnDisplaySWData_Click()
Dim pSQL As String
pSQL = "SELECT JUNK.agency_ID, JUNK.agency_desc FROM JUNK"
Me.dataDisplaySubform.SourceObject = "Query.TESTQUERY"
Me.dataDisplaySubform.Form.RecordSource = pSQL
Me.dataDisplaySubform.Requery
End Sub
当表单处于生产状态时,存储在pSQL字符串变量中的所示硬编码SQL语句将通过主表单上的控件上的用户输入放在一起。
现在,当点击btnDisplaySWData时,它会执行我尝试执行的操作并显示记录。
答案 0 :(得分:1)
如果Me.dataDisplaySubform.Form.RecordSource
行上出现“对象已关闭或不存在”错误,则您的子表单控件可能未命名为< EM> dataDisplaySubform
您可以通过对代码的临时更改来检查所有表单子表单控件的名称......
'Me.dataDisplaySubform.Form.RecordSource = pSQL
Dim ctl As Control
For Each ctl In Me.Controls
If TypeName(ctl) = "SubForm" Then
Debug.Print ctl.Name, TypeName(ctl)
End If
Next
Stop
Stop
语句将触发调试(中断)模式,并转到立即窗口,您可以在其中查看表单子窗体控件的名称。
您添加到问题的屏幕截图确认您正在使用子窗体控件的正确名称。但是,该子表单的源对象属性中没有任何内容。由于那里没有表单,错误消息的第二部分“不存在”适用。 Me.dataDisplaySubform.Form
答案 1 :(得分:0)
其他读者的一些澄清点:
详细视图子表单的sourceObject属性确定显示哪些列/字段。因此,您可以将其设置为表或查询,然后可选地使用过滤器不返回任何记录(如果您希望记录集最初为空),或者作为使用recordSource进行自定义SQL的替代方法。
recordSource可以是任何表,查询或SQL,但子表单只显示名称与sourceObject的字段匹配的字段。例如,如果将sourceObject设置为表,然后将recordSource设置为具有部分重叠字段名称的查询(Access将显示所有列,但只有重叠的列将包含数据),这可能会造成混淆。
要拥有一个显示任意SELECT语句的表单或允许用户选择要选择哪个表的表单,可以将其输入保存为新查询(或者将现有的名称保存为覆盖),然后设置sourceObject到那个(表单必须关闭然后重新打开才能显示新列,所以你可能想打开一个弹出窗口或新标签来显示结果。)
答案 2 :(得分:0)
使用CreateQueryDef
然后再使用
Me.dataDisplaySubform.SourceObject = "Query.NewqueryName"
NewQueryName
是使用createQueryDef
答案 3 :(得分:0)
Private Sub btnRunSQL_Click()
'my subform is called datasheet, i know -- dumb name.
'a dynamic sql needs to be saved in a temporoary query. I called my qtemp
Dim sql As String
sql = "select * from client order by casename asc"
'in case there is something kicking around, remove it first, otherwise we can't delete the temp query if it is still open
Me!Datasheet.SourceObject = ""
'delete our temporary query. Note, add some err checking in case it doesn't exist, you can do that on your own.
DoCmd.DeleteObject acQuery, "qtemp"
'lets create a new temporary query
Dim qdf As QueryDef
Set qdf = CurrentDb.CreateQueryDef("qtemp", sql)
'set the subform source object
Me!Datasheet.SourceObject = "query.qtemp"
'and it should work.
End Sub