MS Access VBA - 在数据表子表单中显示动态构建的SQL结果

时间:2014-01-21 23:52:09

标签: ms-access access-vba

我在MS Office应用程序(用于自动化和ETL过程)中有多年的VBA经验,但直到最近才需要在MS Access中弄乱表单。我正在为我设计的数据库设计一些简单的数据提取表单,并挂在一个看似简单的任务上。

目标:我需要一个数据表子表单来显示从主窗体上的控件动态生成的SQL语句返回的记录。

在我的主窗体上,我有一个按钮,当用户单击它时,按钮会将用户在其他用户窗体控件中指定的信息编译成SQL查询,然后运行该查询,以便子窗体显示结果记录。

无论我做什么,我都无法让它发挥作用。我一直得到(大部分时间)微软视觉基本运行时错误“'2467':你输入的表达式是指一个已关闭或不存在的对象。”这是我用下面显示的代码得到的错误。我无法弄清楚我是否需​​要在任何代码运行或什么时候立即启动子表单。我已经尝试了其他代码论坛中也没有用过的其他代码变体,但我似乎找到了一些论坛帖子,其中包括一些关于Stack Overflow的论坛帖子,建议我下面的代码应该有效。

附图显示了基本主要表单的外观。我已经标记了用户单击的按钮(btnDisplaySWData)来编译从尚未包含的控件创建的SQL,但这不是问题。我只是对代码片段中显示的SQL语句进行了硬编码,试图弄清楚这个问题。如前所述,我希望记录显示在名为dataDisplaySubform的子表单中。 “JUNK”是Access数据库中的一个表,我可以使用下面的SQL代码合法地查询,我只是用于测试目的,直到我弄清楚这一点。显示的数据表单中的所有代码(名为frmDataExtract)都包含在下面的代码窗口中。 enter image description here

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,如下面选中子窗体的属性屏幕截图所示。

enter image description here

这就是整体表单布局的样子

enter image description here

我已经搜索了几个论坛网站,并且已经尝试了搜索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时,它会执行我尝试执行的操作并显示记录。 enter image description here

4 个答案:

答案 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)

短而甜蜜。下面是一个创建动态sql字符串的按钮的代码,关闭当前对象(以防它打开),删除一个临时查询定义(因为我们需要一个),用新的sql创建一个新的查询定义,更改记录源而鲍勃是你的叔叔。

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