【问题标题】:Access 2007 VBA & SQL - Update a Subform pointed at a dynamically created queryAccess 2007 VBA & SQL - 更新指向动态创建查询的子表单
【发布时间】:2010-05-25 20:03:40
【问题描述】:

摘要: 每次用户从下拉菜单中选择 3 个选项之一时,我都使用 VB 重新创建查询,如果他们从组合框中选择了任何内容,则会附加 WHERE 子句。然后,我试图让表单上显示的信息刷新,从而根据用户输入过滤表中显示的内容。

1) 使用 VB 动态创建查询。

Private Sub BuildQuery()
' This sub routine will redefine the subQryAllJobsQuery based on input from
' the user on the Management tab.

Dim strQryName As String
Dim strSql As String            ' Main SQL SELECT statement
Dim strWhere As String          ' Optional WHERE clause
Dim qryDef As DAO.QueryDef
Dim dbs As DAO.Database

strQryName = "qryAllOpenJobs"
strSql = "SELECT * FROM tblOpenJobs"
Set dbs = CurrentDb

' In case the query already exists we should deleted it
' so that we can rebuild it.  The ObjectExists() function
' calls a public function in GlobalVariables module.
If ObjectExists("Query", strQryName) Then
    DoCmd.DeleteObject acQuery, strQryName
End If

' Check to see if anything was selected from the Shift
' Drop down menu.  If so, begin the where clause.
If Not IsNull(Me.cboShift.Value) Then
    strWhere = "WHERE tblOpenJobs.[Shift] = '" & Me.cboShift.Value & "'"
End If

' Check to see if anything was selected from the Department
' drop down menu.  If so, append or begin the where clause.
If Not IsNull(Me.cboDepartment.Value) Then
    If IsNull(strWhere) Then
        strWhere = strWhere & " AND tblOpenJobs.[Department] = '" & Me.cboDepartment.Value & "'"
    Else
        strWhere = "WHERE tblOpenJobs.[Department] = '" & Me.cboDepartment.Value & "'"
    End If
End If

' Check to see if anything was selected from the Date
' field.  If so, append or begin the Where clause.
If Not IsNull(Me.txtDate.Value) Then
    If Not IsNull(strWhere) Then
        strWhere = strWhere & " AND tblOpenJobs.[Date] = '" & Me.txtDate.Value & "'"
    Else
        strWhere = "WHERE tblOpenJobs.[Date] = '" & Me.txtDate.Value & "'"
    End If
End If

' Concatenate the Select and the Where clause together
' unless all three parameters are null, in which case return
' just the plain select statement.
If IsNull(Me.cboShift.Value) And IsNull(Me.cboDepartment.Value) And IsNull(Me.txtDate.Value) Then
    Set qryDef = dbs.CreateQueryDef(strQryName, strSql)
Else
    strSql = strSql & " " & strWhere
    Set qryDef = dbs.CreateQueryDef(strQryName, strSql)
End If

结束子

2) 用户从组合框中选择项目的主窗体。

主窗体和子窗体的图片 http://i48.tinypic.com/25pjw2a.png

3) 指向在步骤 1 中创建的查询的子表单。

事件链: 1) 用户从主窗体的下拉列表中选择项目。 2)删除旧查询,生成新查询(同名)。 3) 指向查询的子表单不会更新,但如果您自己打开查询,则会显示正确的结果。

查询名称:qryAllOpenJobs 子窗体的名称:subQryAllOpenJobs 此外, subQryAllOpenJobs = qryAllOpenJobs 的行源 主窗体名称:frmManagement

【问题讨论】:

  • 您在更改保存的QueryDef 后是否重新查询了子表单?编辑 QueryDefs 通常不是一个好主意(除非你必须这样做),而且在我看来你应该能够直接设置子表单 Recordsource (自动重新查询)。
  • 我试图在子窗体上使用 .requery 过程,但它没有更新,我认为你是对的......这是因为我搞砸了 QueryDef。我一直在寻找记录源操作如何工作的示例,因为这听起来像是我需要的……但我还没有在网上找到任何可靠的示例来帮助我理解它。
  • 您是否尝试过将表单的记录源设置为新的 SQL 字符串?根本不需要处理表单的 .Recordset 属性(在 Access 中可用的 10 年里,我从未这样做过)。
  • 是的,我现在想通了,我知道 SQL 我只是不太了解 Access(这与大多数人学习的方式有点倒退)。我通过更集中地研究 RecordSource 属性及其出色的工作解决了我的问题。

标签: sql ms-access ms-access-2007 vba


【解决方案1】:

我认为您对部门下拉检查的逻辑是向后的。

你让它检查 strWhere 是否为空,如果是,你将 strWhere 与 cboDepartment 的值连接起来。

你应该为 Date 做你该做的事。

' Check to see if anything was selected from the Department
' drop down menu.  If so, append or begin the where clause.
If Not IsNull(Me.cboDepartment.Value) Then
    If Not IsNull(strWhere) Then
        strWhere = strWhere & " AND tblOpenJobs.[Department] = '" & Me.cboDepartment.Value & "'"
    Else
        strWhere = "WHERE tblOpenJobs.[Department] = '" & Me.cboDepartment.Value & "'"
    End If
End If

您可能还想这样做:

If Nz(strWhere,"") = "" then

而不是仅仅执行 IsNull 以便您捕获零长度字符串以及 null 变量。

至于设置记录源,使用类似的东西

Me.sfrmJobs.Form.RecordSource = strSQL

其中 sfrmJobs 是您的子表单的名称。

【讨论】:

  • 我还没有 15 名声望给你投票,但你的回答很有用。您对 strWhere 字符串变量 IsNull 测试是正确的。我已经打开了 Option Explicit 并且已经解决了这个问题。 Nz() 函数并不是真正需要的,它就像我测试 strWhere 是否为空字符串一样容易,使用 If strWhere = "" 但我很欣赏输入。
  • 我刚刚养成了在查找空/NULL 值时使用该测试的习惯,因为它适用于字符串和其他数据类型。
【解决方案2】:

空字符串与 Null 不同。当你声明一个这样的字符串变量时:

Dim strWhere As String

strWhere 被初始化为一个空字符串(或“零长度字符串”)。该值有时被称为空字符串,甚至还有一个 VBA 常量 vbNullString,它表示空字符串。但是,无论您使用哪个名称,空字符串变量都不是 Null。此外,VBA 字符串变量永远不会为 Null。例如,此代码将导致错误 94,'Invalid use of Null':

Dim strWhere As String
strWhere = Null

我之所以强调这一点是因为您的代码测试 strWhere 是否为 Null。这是一个逻辑缺陷,因为 strWhere 永远不会为 Null。例如,我不相信这个条件永远是真的:

If IsNull(strWhere) Then

如果您想通过测试确定 strWhere 何时没有分配值(它仍然是一个空字符串),请使用 Len 函数:

If Len(strWhere) = 0 Then

这是 BuildQuery 的另一种方法。它假定您的 [Date] 字段的数据类型是字符串(正如您的原始代码所建议的那样)。如果 [Date] 实际上是 Date/Time 数据类型,则此代码将不起作用。另外,请注意 Date 是保留字(请参阅Problem names and reserved words in Access)。我将字段名称括在方括号中以避免歧义。如果它是我自己的数据库,我会改为更改字段名称。

Private Sub BuildQuery()
'* Update subform RecordSource based on input from *'
'* the user on the Management tab. *'

Dim strSql As String        ' Main SQL SELECT statement '
Dim strWhere As String      ' Optional WHERE clause '
Dim i As Integer
Dim strControl As String
Dim strField As String

strSql = "SELECT * FROM tblOpenJobs AS oj"

strWhere = vbNullString
For i = 1 To 3
    Select Case i
    Case 1
        strControl = "cboShift"
        strField = "Shift"
    Case 2
        strControl = "cboDepartment"
        strField = "Department"
    Case 3
        strControl = "txtDate"
        strField = "[Date]"
    End Select
    If Not IsNull(Me.Controls(strControl).Value) Then
        strWhere = strWhere & _
            IIf(Len(strWhere) > 0, " AND ", "") & _
            "oj." & strField & " = '" & _
            Me.Controls(strControl).Value & "'"
    End If
Next i

If Len(strWhere) > 0 Then
    strSql = strSql & " WHERE " & strWhere
End If
'* use the name of the subform CONTROL for sfrmJobs *'
'* (may not be the name of the subform) *'
Me.sfrmJobs.Form.RecordSource = strSql

End Sub

【讨论】:

  • 我没有给你投票所需的 15 名声望,但这是一个有用的解决方案。我不打算在代码中实现别名,因为我希望它对其他人尽可能容易理解。我也很欣赏您对实现循环而不是菊花链 If 语句的看法,但我现在有一个可行的解决方案,并且一旦我完成了最初的开发,我将在未来考虑这个以进行优化。我现在有 Option Explicit 可以对那些 Null 测试进行排序。
【解决方案3】:

我的解决方案分为三个部分。 (1) 构建查询,(2) 主窗体,(3) 子窗体。 `私有子 OpenJobsQuery() ' 这个 sub 将在首页为用户构建查询 ' 基于他们是谁以及他们从上面的组合框中选择的内容 ' 通过重新定义子表单的行源进行过滤的表 ' subQryOpenJobs

Dim strSql As String            ' Main SQL SELECT statement
Dim strWhere As String          ' Where clause containing user specified parameters.

strSql = "SELECT * FROM tblOpenJobs"
strWhere = ""

' Check to see if anything was selected from the Shift
' combo box.  If so, begin the Where clause.
If Not IsNull(Me.cboOpenJobShift.Value) Then
    strWhere = "WHERE tblOpenJobs.[Shift] = '" & Me.cboOpenJobShift.Value & "'"
End If

' Check to see if anything was selected from the Department
' combo box.  If so, append or begin the where clause.
If Not IsNull(Me.cboOpenJobDepartment.Value) Then
    If strWhere = "" Then
        strWhere = "WHERE tblOpenJobs.[Department] = '" & Me.cboOpenJobDepartment.Value & "'"
    Else
        strWhere = strWhere & " AND tblOpenJobs.[Department] = '" & Me.cboOpenJobDepartment.Value & "'"
    End If
End If

' Check to see if anything was selected from the Date
' field.  If so, append or begin the Where clause.
If Not IsNull(Me.cboOpenJobDate.Value) Then
    If strWhere = "" Then
        strWhere = "WHERE tblOpenJobs.[JobDate] = #" & Me.cboOpenJobDate.Value & "#"
    Else
        strWhere = strWhere & " AND tblOpenJobs.[JobDate] = #" & Me.cboOpenJobDate.Value & "#"
    End If
Else
    ' If nothing was entered in the date field, make sure the user
    ' only sees future jobs.
    If strWhere = "" Then
        strWhere = "WHERE tblOpenJobs.[JobDate] > #" & FormatDateTime(Date, vbShortDate) & "#"
    Else
        strWhere = strWhere & " AND tblOpenJobs.[JobDate] > #" & FormatDateTime(Date, vbShortDate) & "#"
    End If
End If

' Always include as part of the where clause, a section that
' will narrow the results based on who the user is
If strWhere = "" Then
    strWhere = "WHERE tblOpenJobs.[OpenJobID] Not In " & _
               "(SELECT tblSignUps.[OpenJobID] FROM tblSignUps WHERE tblSignUps.[EUID] = '" & strEUID & "');"

Else
    strWhere = strWhere & " AND tblOpenJobs.[OpenJobID] Not In " & _
               "(SELECT tblSignUps.[OpenJobID] FROM tblSignUps WHERE tblSignUps.[EUID] = '" & strEUID & "');"
End If

' Concatenate the Select and the Where clause together
strSql = strSql & " " & strWhere

' Set the recordsource of the subform to the SQL query generated
' and refresh the form.
Me.subQryOpenJobs.Form.RecordSource = strSql

' In addition, synchronize the JobID's in the Edit Job box to match those
' filtered by this Build Query.
Me.cboSelectJOBID.RowSource = "SELECT tblOpenJobs.[OpenJobID] FROM tblOpenJobs" & " " & strWhere

Me.Refresh

结束子`

(2) 主要形式。 http://j.imagehost.org/view/0385/Form。 (3) 子表单被填充,如 BuildQuery() 子中所示,以根据用户从下拉过滤器和表单右侧的输入框中选择的内容构建查询。用户无法访问表中的数据,仅供参考。

【讨论】:

    猜你喜欢
    • 2011-05-09
    • 1970-01-01
    • 1970-01-01
    • 2012-09-26
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    相关资源
    最近更新 更多