过滤表单的更有效方法

时间:2012-09-29 08:08:08

标签: access-vba ms-access-2003

我有以下代码:

Public Function BuildSQL(stQueryName As String, stWhereClause As String) As String
    On Error GoTo Err_BuildSQL

    Dim SQLcmd  As String
    Dim intPos  As Integer
    Dim db      As Database
    Dim qryOrig As QueryDef

    Set db = CurrentDb()
    Set qryOrig = db.QueryDefs(stQueryName)

    SQLcmd = qryOrig.SQL

    intPos = InStr(SQLcmd, "WHERE")
    If intPos > 0 Then
        SQLcmd = Left(SQLcmd, intPos - 1)
    End If

    intPos = InStr(SQLcmd, ";")
    If intPos > 0 Then
        SQLcmd = Left(SQLcmd, intPos - 1)
    End If

    If Not (stWhereClause = "") Then
        SQLcmd = Trim(SQLcmd) & " WHERE " & stWhereClause & ";"
    Else
        SQLcmd = Trim(SQLcmd) & ";"
    End If

    BuildSQL = SQLcmd

Exit_BuildSQL:
    Set qryOrig = Nothing
    Set db = Nothing
    Exit Function

Err_BuildSQL:
    MsgBox Err.Description
    Resume Exit_BuildSQL

End Function

Private Sub SandBox_Click()
    On Error GoTo Err_SandBox_Click

    Dim db         As Database
    Dim rs         As Recordset
    Dim stSQL      As String
    Dim stFrmName  As String
    Dim stQryName  As String
    Dim stSQLWhere As String
    Dim stIDList   As String

    stFrmName = "Libri"
    stQryName = "Libri_All_Query"

    'Define WHERE clause
    stSQLWhere = ""
    If Not (IsNull([Forms]![Libreria]![Editore]) Or [Forms]![Libreria]![Editore] = "") Then
        stSQLWhere = stSQLWhere & "Libri_Editori.Editore = '" & [Forms]![Libreria]![Editore] & "'"
    End If
    If Not (IsNull([Forms]![Libreria]![CognomeAutore]) Or [Forms]![Libreria]![CognomeAutore] = "") Then
        If (stSQLWhere = "") Then
            stSQLWhere = stSQLWhere & "Autori.Cognome = '" & [Forms]![Libreria]![CognomeAutore] & "'"
        Else
            stSQLWhere = stSQLWhere & " AND Autori.Cognome = '" & [Forms]![Libreria]![CognomeAutore] & "'"
        End If
    End If

    'Here several more fields of the search form will be checked and added

    stSQL = BuildSQL(stQryName, stSQLWhere)

    '*** Code in question!
    Set db = CurrentDb()
    Set rs = db.OpenRecordset(stSQL)
    If Not (rs.EOF And rs.BOF) Then
        stIDList = "("
        rs.MoveFirst
        Do Until rs.EOF = True
            If (stIDList = "(") Then
                stIDList = stIDList & rs.Fields(0)
            Else
                stIDList = stIDList & ", " & rs.Fields(0)
            End If
            rs.MoveNext
        Loop
        stIDList = stIDList & ")"
    Else
        Err.Description = "Errore! Recordset vuoto."
        Resume Err_SandBox_Click
    End If
    DoCmd.OpenForm stFrmName, , , , acFormReadOnly
    Access.Forms(stFrmName).RecordSource = "SELECT * FROM Libri WHERE Libri.ID IN " & stIDList
    '**** End code in question

Exit_SandBox_Click:
    Set db = Nothing
    Set rs = Nothing
    Exit Sub

Err_SandBox_Click:
    MsgBox Err.Description
    Resume Exit_SandBox_Click
End Sub

这段代码按照我的意愿运行,但即使使用每个表中只有少量记录的测试数据库,“看起来”也很慢。 我相信在评论之间的循环中花费了时间(我怎样才能检查这是否属实?) 是否有一种更基本,明显和有效的方法来过滤表单,而不是像我一样创建记录集并循环遍历它?
“Libri”形式是一个很大的形式,有几个子表格可以看到一本书的所有数据 查询“Libri_All_Query”是数据库中几乎所有表的连接,显示的代码是从我计划添加所有可能搜索字段的表单执行的。

1 个答案:

答案 0 :(得分:1)

表单有一个过滤属性:

stWhereClause = "Title Like '" & Me.txtSearch & "*'"
Me.Filter = stWhereClause 
Me.FilterOn = True

过滤器的构造方式应与WHERE语句类似。与Where相比有一些限制。您可能希望与DCount核实将返回记录。

修改

如果你想要一组子窗体只包含某些记录的记录,你需要在这些行上提供一些东西:

SELECT b.Title
FROM Books b 
WHERE b.ID IN (
   SELECT j.BookID FROM BooksAuthorJunction j 
   INNER JOIN  Authors a ON j.AuthorID = a.ID
   WHERE a.Author Like "Arn*")

建立更多的形式,书籍作为主要形式,作者作为子形式,然后作为主要形式,书籍作为子形式,有一些优点。用户通常会更容易。