Re: Wanting help regarding dynamic queries in MS-Access

From: Mike Sorel <msorel_at_ozemail.com.au>
Date: 1996/11/12
Message-ID: <01bbd091$34e6d900$39a30fcb_at_dialup.ozemail.com.au>


The best way to do this is to build the SQL string on the fly. The following example is from VB4 but is still applicable (sorry it's a bit complex but it's the only example I had on hand).

This example takes parameters from a grid and places them in an array for further processing then builds the SQL string, including creating multiple table joins and where conditions.

Sub cmdResults_Click()
On Error GoTo Err_cmdResults_Click

    Dim strSQL As String
    Dim i As Integer
    Dim bytNumQuals As Byte
    Dim audtMandCriteria() As SearchCriteria     Dim alngOptCriteria() As Long
    Dim bytNumMandQuals As Byte
    Dim bytNumOptQuals As Byte     

    Dim snpSkillSearchResults As Recordset     Dim lngQualID As Long
    Dim intRatingTemp As Integer     

    Dim lngPersonID As Long
    Dim strName As String
    Dim strCompany As String
    Dim strMandScore As String
    Dim strOptScore As String
'Dim strTotalScore As String

    Dim strReqd As String

    Dim fMand As Boolean
    Dim fOpt As Boolean
    Dim intMandScore As Integer
    Dim intMandScoreReqd As Integer
    Dim intOptScore As Integer       

'clear the grid of any existing results
    lstResult.Clear     

'read the selected qualification into an array for further processing
'find the total number of qualifications selected
    bytNumQuals = frmSkillSearch.sdgQualifications.Rows        

'load data from the grid into the array
    For i = 0 To bytNumQuals - 1

        frmSkillSearch.sdgQualifications.Row = i
        'is this a Mandatory criteria
        If frmSkillSearch.sdgQualifications.Columns(3).Value Then
            'resize the Mandatory counter and array (NB 1 based)
            bytNumMandQuals = bytNumMandQuals + 1
            ReDim Preserve audtMandCriteria(1 To bytNumMandQuals)
            audtMandCriteria(bytNumMandQuals).QualID =
frmSkillSearch.sdgQualifications.Columns(7).Value
            audtMandCriteria(bytNumMandQuals).Rating =
frmSkillSearch.sdgQualifications.Columns(8).Value
            audtMandCriteria(bytNumMandQuals).Years =
Val(frmSkillSearch.sdgQualifications.Columns(4).Value)
        Else
            'resize the Optional counter and array (NB 1 based)
            bytNumOptQuals = bytNumOptQuals + 1
            ReDim Preserve alngOptCriteria(1 To bytNumOptQuals)
            alngOptCriteria(bytNumOptQuals) =
frmSkillSearch.sdgQualifications.Columns(7).Value
        End If
    Next i
        

'there must be at least one Mandatory qualification
    If bytNumMandQuals <= 0 Then

        MsgBox "You must select at least one Mandatory Qualification.", 48, "Select Mandatory Qualification"

        Exit Sub
    End If         

'fields to be selected and start of FROM clause
    strSQL = "SELECT DISTINCTROW People.PersonID, People.FirstName, People.Surname, Companies.CompanyName, CompaniesDepartments.Department, People.RateHourly, People.RateAnnual, PeopleQualifications.QualificationID, PeopleQualifications.Rating FROM (Companies INNER JOIN CompaniesDepartments ON Companies.CompanyID = CompaniesDepartments.CompanyID) INNER JOIN "

'add opening brackets for each additional join
'add one PeopleQualifications table to show results and one for
selection criteria

    strSQL = strSQL & String$(bytNumMandQuals + 1, "(") & "People INNER JOIN PeopleQualifications ON People.PersonID = PeopleQualifications.PersonID) INNER JOIN PeopleQualifications AS PeopleQualifications_1 ON People.PersonID = PeopleQualifications_1.PersonID"

'add other PeopleQualifications tables for additional criteria
    For i = 2 To bytNumMandQuals

        strSQL = strSQL & ") INNER JOIN PeopleQualifications AS PeopleQualifications_" & i & " ON People.PersonID = PeopleQualifications_" & i & ".PersonID"

    Next i
'finish off the FROM clause

    strSQL = strSQL & ") ON CompaniesDepartments.DepartmentID = People.DepartmentID"

'start the WHERE clause and add criteria for first QualificationID
    strSQL = strSQL & " WHERE (((PeopleQualifications_1.QualificationID)=" & audtMandCriteria(1).QualID & ")"

'add criteria for first Rating and Year only if value > 0
    If audtMandCriteria(1).Rating > 0 Then

        strSQL = strSQL & " AND ((PeopleQualifications_1.Rating)>=" & audtMandCriteria(1).Rating & ")"

    End If
    If audtMandCriteria(1).Years > 0 Then

        strSQL = strSQL & " AND ((PeopleQualifications_1.Years)>=" & audtMandCriteria(1).Years & ")"

    End If     

    For i = 2 To bytNumMandQuals

        'add criteria for other QualificationID's
        strSQL = strSQL & " AND ((PeopleQualifications_" & i &
".QualificationID)=" & audtMandCriteria(i).QualID & ")"
        'add criteria for first Rating and Year only if value > 0
        If audtMandCriteria(i).Rating > 0 Then
            strSQL = strSQL & " AND ((PeopleQualifications_" & i &
".Rating)>=" & audtMandCriteria(i).Rating & ")"
        End If
        If audtMandCriteria(i).Years > 0 Then
            strSQL = strSQL & " AND ((PeopleQualifications_" & i &
".Years)>=" & audtMandCriteria(i).Years & ")"
        End If

    Next i     

'add closing bracket for WHERE clause, ORDER BY clause and closing ;
for SQL

    strSQL = strSQL & ") ORDER BY People.PersonID;"        

'open the results recordset

    Set snpSkillSearchResults = gDB.OpenRecordset(strSQL, dbOpenSnapshot)     

'check that at least one record was found
    If snpSkillSearchResults.EOF And snpSkillSearchResults.BOF Then

        MsgBox "No candidates were found for the Qualifications requested. Reduce the some of the Ratings and try again.", 48, "No Candidates Found"

        Exit Sub
    End If         

'find the minimum score required for the mandatory requests
    For i = 1 To bytNumMandQuals

        If audtMandCriteria(i).Rating > 0 Then
            intMandScoreReqd = intMandScoreReqd +
audtMandCriteria(i).Rating
        Else
            intMandScoreReqd = intMandScoreReqd + 3
        End If

    Next i     

'calculate the percentages for each person and fill list
'load temporary variables

    lngPersonID = snpSkillSearchResults!PersonID     strName = snpSkillSearchResults!Surname & ", " & snpSkillSearchResults!FirstName

    strCompany = snpSkillSearchResults!CompanyName & ", " + snpSkillSearchResults!Department

    strReqd = Format$(0 & snpSkillSearchResults!RateAnnual, "$#,###;;-")     

    Do Until snpSkillSearchResults.EOF

        'if this is a new person then add the previous person's results to the list view

        If lngPersonID <> snpSkillSearchResults!PersonID Then
            strMandScore = Format$(intMandScore / intMandScoreReqd, "#%")
            strOptScore = Format$(intOptScore)
            'strTotalScore = Format$(intMandScore + intOptScore)
            'add person to results form
            AddResult lngPersonID, strMandScore, strName, strCompany,
strOptScore, strReqd
            
            'reset variables for this person
            lngPersonID = snpSkillSearchResults!PersonID
            strName = snpSkillSearchResults!Surname & ", " &
snpSkillSearchResults!FirstName
            strCompany = snpSkillSearchResults!CompanyName & ", " +
snpSkillSearchResults!Department
            strReqd = Format$(0 & snpSkillSearchResults!RateAnnual,
"$#,###;;-")
            intMandScore = 0
            intOptScore = 0
        
        End If
        
        lngQualID = snpSkillSearchResults!QualificationID
        intRatingTemp = 0 & snpSkillSearchResults!Rating
        If intRatingTemp = 0 Then intRatingTemp = 3
        
        'is this a mandatory skill
        fMand = False
        For i = 1 To bytNumMandQuals
            If lngQualID = audtMandCriteria(i).QualID Then
                fMand = True
                Exit For
            End If
        Next i
        If fMand = False Then
            'is this an optional skill
            fOpt = False
            For i = 1 To bytNumOptQuals
                If lngQualID = alngOptCriteria(i) Then
                    fOpt = True
                    Exit For
                End If
            Next i
        End If
        If fMand Then
            intMandScore = intMandScore + intRatingTemp
        ElseIf fOpt Then
            intOptScore = intOptScore + intRatingTemp
        End If
        snpSkillSearchResults.MoveNext

    Loop
'add the last person to results form
    strMandScore = Format$(intMandScore / intMandScoreReqd, "#%")     strOptScore = Format$(intOptScore)
'strTotalScore = Format$(intMandScore + intOptScore)
    AddResult lngPersonID, strMandScore, strName, strCompany, strOptScore, strReqd     

'show the results list

    sdgQualifications.Visible = False
    lstResult.Visible = True
    For i = 0 To 4

        lblResult(i).Visible = True
    Next i
    lstResult.SetFocus
    cmdQualifications.Visible = True
    cmdResults.Visible = False     

Exit_cmdResults_Click:

    Exit Sub

Err_cmdResults_Click:

    Call frmError.ShowDialog("frmSkillSearch", "cmdResults_Click", Err, Now())

    Resume Exit_cmdResults_Click

End Sub

E. Rijk <egonrijk_at_concepts.nl> wrote in article <01bbcf52$0b240b00$b40786c2_at_egonrijk>...

> I want some help regarding dynamic queries in MS-Access.
> I want to make a query where people can use one or more parameters as a
> criterium for the query. The parameters are entered in a form showing the
> several fields. If just one parameter is entered in a field, then the
> query should be limited to this field. If more than one field is filled
> in, then the query should consider these fields using the 'AND' operator.
> The problem is that the query is not allowed to look at the fields that
> are left blank. I solved it with the following construction (see later),
> which works well.
> 
> This subroutine evaluates the contents of each field and assigns then a
> value to the several parameters. These are then summoned. This sum is
 then
> used to choose via a 'SELECT CASE' instruction the right query.
> Although this works well, the amount of code rapidly increases when the
> amount of fields is increased (2 to the power n, n being the amount of
> fields).
> 
> Surely, there must be another way to do this, BUT HOW??? 
> Any help is highly appreciated!
> --------------------------------------------------------------- 
> 
> Sub Knop17_Click ()
> On Error GoTo Err_Knop17_Click
> 
>     Dim DocName As String
>     Dim LinkCriteria As String
>     Dim BU As Integer
>     Dim PL As Integer
>     Dim PT As Integer
>     Dim PF As Integer
>     Dim Sum As Integer
> 
> 
>     DocName = "frm_PortfolioView"
> 
> 'The next four statements evaluate the contents
> 'of each field    
> 
>     If Not IsNull(Forms![frm_Zoek1]![BU]) Then
>         BU = 1
>     End If
>     If Not IsNull(Forms![frm_Zoek1]![Projekttype]) Then
>         PT = 2
>     End If
>     If Not IsNull(Forms![frm_Zoek1]![Projektleider]) Then
>         PL = 8
>     End If
>     If Not IsNull(Forms![frm_Zoek1]![Ontwikkelingsfase]) Then
>         PF = 4
>     End If
> 
> 'The result of the evaluation gives a unique sum
> 'for each of the possible combinations
> 
>     Sum = BU + PT + PL + PF
>     
> 'The sum is then used to choose from the right query
>         
>     Select Case Sum
>         Case 0
>         KnopMsgBox = MsgBox("You didn't enter any values!" & Chr$(13) &
> Chr$(10) & "All records will be shown." & Chr$(13) & Chr$(10) & "Is this
> what you want?", 1)
>          If KnopMsgBox = 2 Then
>             Exit Sub
>          End If
>         Case 1
>         LinkCriteria = "[BU-groep] = Forms![frm_Zoek1]![BU]"
>         Case 2
>         LinkCriteria = "[Projekttype] = Forms![frm_Zoek1]![Projekttype]"
>         Case 3
>         LinkCriteria = "[BU-groep] = Forms![frm_Zoek1]![BU] AND
> [Projekttype] = Forms![frm_Zoek1]![Projekttype]"
>         Case 4
>         LinkCriteria = "[Ontwikkelingsfase] =
> Forms![frm_Zoek1]![Ontwikkelingsfase]"
>         Case 5
>         LinkCriteria = "[BU-groep] = Forms![frm_Zoek1]![BU] AND
> [Ontwikkelingsfase] = Forms![frm_Zoek1]![Ontwikkelingsfase]"
>         Case 6
>         LinkCriteria = "[Projekttype] = Forms![frm_Zoek1]![Projekttype]
> AND [Ontwikkelingsfase] = Forms![frm_Zoek1]![Ontwikkelingsfase]"
>         Case 7
>         LinkCriteria = "[BU-groep] = Forms![frm_Zoek1]![BU] AND
> [Projekttype] = Forms![frm_Zoek1]![Projekttype] AND [Ontwikkelingsfase] =
> Forms![frm_Zoek1]![Ontwikkelingsfase]"
>         Case 8
>         LinkCriteria = "[Projektleider] =
> Forms![frm_Zoek1]![Projektleider]"
>         Case 9
>         LinkCriteria = "[BU-groep] = Forms![frm_Zoek1]![BU] AND
> [Projektleider] = Forms![frm_Zoek1]![Projektleider]"
>         Case 10
>         LinkCriteria = "[Projekttype] = Forms![frm_Zoek1]![Projekttype]
> AND [Projektleider] = Forms![frm_Zoek1]![Projektleider]"
>         Case 11
>         LinkCriteria = "[BU-groep] = Forms![frm_Zoek1]![BU] AND
> [Projekttype] = Forms![frm_Zoek1]![Projekttype]  AND [Projektleider] =
> Forms![frm_Zoek1]![Projektleider]"
>         Case 12
>         LinkCriteria = "[Ontwikkelingsfase] =
> Forms![frm_Zoek1]![Ontwikkelingsfase] AND [Projektleider] =
> Forms![frm_Zoek1]![Projektleider]"
>         Case 13
>         LinkCriteria = "[BU-groep] = Forms![frm_Zoek1]![BU] AND
> [Ontwikkelingsfase] = Forms![frm_Zoek1]![Ontwikkelingsfase] AND
> [Projektleider] = Forms![frm_Zoek1]![Projektleider]"
>         Case 14
>         LinkCriteria = "[Projekttype] = Forms![frm_Zoek1]![Projekttype]
> AND [Ontwikkelingsfase] = Forms![frm_Zoek1]![Ontwikkelingsfase] AND
> [Projektleider] = Forms![frm_Zoek1]![Projektleider]"
>         Case 15
>         LinkCriteria = "[BU-groep] = Forms![frm_Zoek1]![BU] AND
> [Projekttype] = Forms![frm_Zoek1]![Projekttype] AND [Ontwikkelingsfase] =
> Forms![frm_Zoek1]![Ontwikkelingsfase] AND [Projektleider] =
> Forms![frm_Zoek1]![Projektleider]"
>         End Select
>     
>     'linkcriteria = "[Projekttype] = Forms![frm_Zoek1]![Projekttype] and
> [BU-groep] = Forms![frm_Zoek1]![BU]"
>     DoCmd OpenForm DocName, , , LinkCriteria
> 
> Exit_Knop17_Click:
>     Exit Sub
> 
> Err_Knop17_Click:
>     MsgBox Error$
>     Resume Exit_Knop17_Click
>     
> End Sub
> -----------------------------------------------------
> 
> 
Received on Tue Nov 12 1996 - 00:00:00 CET

Original text of this message