creating a search tool for Access listbox - vba

I have a listbox with many fields in a form and I'm trying to create a search function that searches for partial strings inside it.
Private Sub SearchBox_Change()
Me.DataView.RowSource = "SELECT RowSrcString FROM MechDataFiltered WHERE " & _
"MechDataFiltered.* LIKE " & Chr(34) & Me.SearchBox.Text & "*" & Chr(34) & " "
End Sub
RowSrcString is a string of field names (from MechDataFiltered) that changes depending on other filters. I think my problem is in the 3rd line; MechDataFiltered.* is for "all" instead of "any". What should I change to make it search in each individual field?

You might take a look at some search criteria samples on Allen Brown's site. It's fairly advanced from a programming standpoint, but he is one of the experts in the industry and I have used tips from his site on numerous occasions.
Allen demonstrates how to use search criteria from multiple input fields to dynamically build a query (filter) expression that returns the results that I think you are looking for.
He has some sample databases you can download to try out the various techniques.
Hope that helps!

Related

Subform multi criteria query not working?

I have a form frmTagSearch which contains a textbox txtSearchTerm a search button btnSearch and a subform subfrmTagQuery.
The subform was created using the wizard from a pre-existing query qryStakeholderTag. The query itself has no criteria.
The aim is to use the value of txtSearchTerm to get the subform to show those records in qryStakeholderTag where the txtSearchTerm value appears in any of the Organisation, Role or Comms Notes fields.
The code I have for this is below (the Debug line is to check I have the right quote marks). In most cases this returns no records, although with one search term the query does return 3 records - not the 'right' number, but at least it appears to be doing something.
Can anyone advise what I'm getting wrong here? I pretty much copied the code from another forum where it was marked as an answer to a similar-sounding problem.
Private Sub btnSearch_Click()
If Me.txtSearchTerm = vbNullString Then Exit Sub
Me.subfrmTagQuery.Form.RecordSource = "SELECT * FROM qryStakeholderTag WHERE Organisation LIKE '*" & Me.txtSearchTerm & _
"*' OR qryStakeholderTag.Role LIKE '*" & Me.txtSearchTerm & _
"*' OR qryStakeholderTag.[Comms Notes] LIKE '*" & Me.txtSearchTerm & "*'"
Debug.Print Me.subfrmTagQuery.Form.RecordSource
Me.subfrmTagQuery.Requery
End Sub
I had the eureka/d'oh moment last night. The query on which the subform is based has two source tables, Stakeholders and Organisations. Stakeholders has a lookup field that links to Organisations!Organisation; I had pulled the Stakeholders!Organisation field into the query, so the RecordSource was trying to find a search string in a field that only included lookup ID indeces. My defence, apart from being a bit slow, is that of course the query displays the expected text.
Amending the query design to include the Organisations!Organisation field has fixed the issue. :)

Access VBA: How to filter a mainform by searching a subform in a one-to-many relationship?

I've got a form for entering contacts which contains several subforms, many of which represent many-to-many relationships. I wish for users to be able to search contacts by values in their subforms.
Ironically, I actually have a good, functional solution for searching those subforms which represent many-to-many relationships-- usually, those are the ones that give me the most trouble! The problem is, the solution I'm using uses comboboxes, and therefore allows users to only search by the exact values available in the drop-down. Here's what I mean:
Private Sub cboSourceSearch_AfterUpdate()
Dim strSQL As String
If IsNull(Me.cboSourceSearch) Then
Me.Parent.RecordSource = "people"
Else
strSQL = "SELECT DISTINCTROW people.* FROM people " & "INNER JOIN people_has_sourceref ON " & "people.personID = people_has_sourceref.people_personID " & "WHERE people_has_sourceref.sourceref_sourceID = " & Me.cboSourceSearch & ";"
Me.Parent.RecordSource = strSQL
End If
End Sub
(Adapted from http://allenbrowne.com/ser-28.html)
Essentially this VBA is setting the RecordSource of the main form from the value in the combo-box, whose row source is the "sourceref" table-- the third in the many-to-many relationship. This works great, but what if I want to search by a note left on a contact? The table is called "Notes", and is in a many-to-one relationship with People (contacts). It's a free form block of text for entering notes relating to the contact.
I've got a general idea of how this would work, and theoretically it should be easier than the above method: Just set the RecordSource of the main form based on an SQL query which searches the Notes table with wildcard characters on either side. Yet, I can't put together a solution. This is essentially due to my lack of VBA knowledge, but I'm learning.
After typing this, I realized I did in fact have the VBA and SQL know-how to put together a solution, but I thought I'd post this anyway for posterity.
Private Sub NoteSearch_AfterUpdate()
Dim strSQL As String
If IsNull(Me.NoteSearch) Then
Me.Parent.RecordSource = "people"
Else
strSQL = "SELECT DISTINCTROW people.* FROM people INNER JOIN notes ON people.personID = notes.people_personID WHERE notes.note LIKE '%" & Me.NoteSearch & "%'"
Me.Parent.RecordSource = strSQL
End If
End Sub
Please note: I have explicitly included the % wildcard on either side of the text in the code since I consider that to be a more common use-case than explicitly searching for a note whose exact text matches that in the search field. I suppose you could exclude the wildcard and teach the users how to include it themselves, which may be preferable.

How to build proper Access SQL LIKE operator expression?

I'm attempting to have a user search through a table in Microsoft Access 2010, but the SQL command isn't working. The command that loads and refreshes the table is this:
SELECT Equipment.equipmentID, Equipment.equipmentName, Equipment.model,
Equipment.make, Equipment.equipmentLocation FROM Equipment ORDER BY Equipment.equipmentName;
This works, but when I try to use a variable (or any normal criteria):
searchItem = Me.searchBox.Value
Me.List64.RowSource = "SELECT Equipment.equipmentID, Equipment.equipmentName,
Equipment.model, Equipment.make, Equipment.equipmentLocation FROM Equipment
WHERE Equipment.equipmentName LIKE '%searchItem%' ORDER BY Equipment.equipmentName;"
I've also tried something like "%10%" instead of the searchItem variable, but the command has the table come up blank with no errors. I suspect the problem is with the Equipment.eqiupmentName as the column name, but I can't quite figure out what's wrong here.
Here's a quick look at what the table looks like:
Try this:
Me.List64.RowSource = & _
"SELECT Equipment.equipmentID, Equipment.equipmentName," & _
" Equipment.model, Equipment.make, Equipment.equipmentLocation FROM Equipment" & _
" WHERE Equipment.equipmentName LIKE '*" & searchItem & "*'" & _
" ORDER BY Equipment.equipmentName;"
User rjt011000 has a valid solution, but I recommend using & for string concatenation in VBA (and Access). For an explanation of + and & see this thread.
Access will not recognize or substitute VBA variables inside an SQL statement. Furthermore, the LIKE operator is fed an SQL string value in this case (inside single quotes... which are inside the double quotes), so even if a VBA variable could be referenced directly inside SQL, Access does not interpret any such thing inside a string value.
Regarding the Access SQL LIKE operator, the multi-character matching pattern is * rather than %. Access also recognizes the operator ALIKE which does indeed honor the ANSI pattern %. See LIKE operator docs and this thread regarding ALIKE.
To be more thorough, the string delimiters and LIKE pattern-matching character should be escaped if you don't want the user inadvertently injecting invalid characters that cause errors in the SQL. Following is an example of escaping a couple of them. There are more elegant ways to handle this for all special characters, but the code and technique are beyond the scope of this answer.
...'" & Replace(Replace(searchItem, "*", "[*]"), "'", "''") & "'...
For the record, although Access SQL will not substitute a VBA variable, it will recognize and call a public VBA function. Normally such a public function must be defined in a normal module, but in context of a form's Record Source query, a form-module method can sometimes be called.
One last technique... It is possible to reference a form control's value directly in SQL. This can be very convenient and reduce extra code, but there are a couple caveats:
The form must of course be open, otherwise Access will interpret the reference as an unknown parameter and display a prompt. This will of course not be a problem if the SQL is always in context of the same form.
Access will sometimes automatically refresh the query when such a referenced control is changed, but it is not always guaranteed. The "timing" of automatic refreshes might not be immediately intuitive. You can call the Refresh method on the control or subform from various form events to force the query to refresh after the value is changed.
Notice that in the following example, the string concatenation is inside the VBA string, so that the concatenation actually happens in context of SQL and not beforehand like in the first code snippet. There is no problem with this, just something to consider since this entire answer revolves around proper string interpretation and concatenation.
But really, the same concern exists for un-escaped pattern-matching characters in the user text. Rather than making the SQL text long and ugly with calls to Replace(), instead create a custom function (e.g. EscapePattern()) that does this for any text and then wrap the control reference with that function. The example does this, although I don't include the code for the special function. Such a function could also be used in the first VBA code snippet to simplify building the SQL text.
Me.List64.RowSource = & _
"SELECT Equipment.equipmentID, Equipment.equipmentName," & _
" Equipment.model, Equipment.make, Equipment.equipmentLocation FROM Equipment" & _
" WHERE Equipment.equipmentName LIKE ('*' & EscapePattern(Forms![Form Name]![Control Name]) & '*')" & _
" ORDER BY Equipment.equipmentName;"
There is always more! Did you see the VBA line continuation in my example? It makes the SQL text much easier to view within VBA editor.
I suspect you are not setting your searchItem variable correctly in the SQL string. I am not too familiar with access string concatenation but try separate the searchItem out of the SQL string and then checking if your RowSource has the value you suspect.
Me.List64.RowSource = "SELECT Equipment.equipmentID, Equipment.equipmentName,
Equipment.model, Equipment.make, Equipment.equipmentLocation FROM Equipment
WHERE Equipment.equipmentName LIKE '%" + searchItem + "%' ORDER BY Equipment.equipmentName;"

Passing a query a parameter [Access 2016]

To make a longer story shorter:
I'm an Access noob, doing a quick-and-dirty conversion of a massive Excel spreadsheet into an Access database. Part of the requirements are to mimic some of the functionality of Excel, specifically, pulling data from a certain table and doing some basic calculations on it (sums, averages, etc.).
I've written a chain of queries to pull the data, count/sum it, etc., and have been testing them by using a manually-entered Parameter (i.e., the kind where the input box pops up and asks you to type a response). Now that I'm ready to drop these queries into a (sub)form, though, I have no idea how to automatically pass that parameter from a box in the form into the subform into the query.
Every query I've written uses a manually-entered Parameter named "MATCHNAME," which holds the name of an individual. In manual testing, if I enter this parameter on one query, all the queries it calls also get that value. So, I think I just need to figure out how to tell the top query what MATCHNAME actually is, and that'll take care of it.
Problem is, I don't know how to do that in Access. If it was any other programming language, I'd do something like "queryXYZ(MATCHNAME);", but I don't think I can do that in Access. Plus, since the values queryXYZ returns are all calculated, I'm not sure how to add an extra MATCHNAME field, nor how to actually make sure that gets read by the queries, nor how to make sure it gets passed down the chain. I've even tried creating a Parameter in design view, then trying to set up Link Master Fields, but the Parameter doesn't appear in that window.
I'd also like to re-run these queries whenever a new record is pulled up, but I'm not sure how to do that either--i.e., the numbers should be current for whatever record I'm looking at.
And, before we go there--I feel like a Relationship is out of the question, as the data itself is auto-generated, and is in rough enough shape to where I can't guarantee that any given key is wholly unique, and large enough (20k+) that, outside of writing a magical script, I can't assign a numerical key. However, I don't know much about Relationships in Access, so please prove me wrong.
(Is this all making sense?)
Do you have any suggestions for me--for how to make a subform read a field on the main form to run its queries on? Alternately, is there an easier way to do this, i.e., to bed SQL calls inside a form?
Thanks very much for your help...
You can use SQL as the recordsource of the subform in the property tab and use the afterupdate event of your matchname field to change yourform.recordsource = "Select * from table where filteredfieldname = & me.matchname & ";" . You can also use sql as the control source of form fields. To pass criteria to filter the subform using the whole table as the recordsource, add an event procedure to your field's after update event like this
`In the declarataions at the top
Global mtchnmfltr as string
Private Sub MATCHNAME_AfterUpdate()
'use the same procedure for Private Sub yourmainform_Current()
mtchnmfltr = "[yourfilterfield] = " & Chr(34) & me.matchname & Chr(34)
'if matchname is not text then just = "[yourfilterfield] = " & me.matchname
with me.subformname.form
.filter = mtchnmfltr
.filteron = true
end with
'Build your sql as a string for your sum avg fields etc. using mtchnmfltr in the where clause
me.yoursumfield.controlsource = "Select...where " & mtchnmfltr & ";"
'etc.
end sub
Or you could throw Matchname into a sql recordsource of the subform and add the function fields to the subform on the same on current and after update events
if me.newrecord = true then
me.dirty = false
end if
me.subform.form.recordsource = "Select Table.Matchname, sum(yourfield) as sumalias, _
(etc.) from yourtable where table.matchname = " & chr(34) & me.matchname & _
chr(34) & Group By table.matchname"
If you are storing your sums etc in a table you need to do it a bit different, since your controls controlsource are bound to fields.
dim strsqlsumfld as string
dim rs as dao.recordset
strsqlsumfld= "Select SUM.....AS sumfldalias where " & mtchnmfltr & ";"
set rs = currentdb.openrecordset(strsqlsumfld)
me.yoursumfield = rs("sumfldalias")
rs.close

Creating Multiple Links in an Access Textbox

I have a form in Access 2016 with a textbox in which I need to have multiple, semi-colon delimited hyperlinks (which will be dynamically created). What I've decided to do is create a "hyperlink construction string" in VBA, then assign them to the value of the textbox. So, something like:
Me.Field.Value = {link: www.google.com : "Google"} & "; " & {link: www.yahoo.com : "Yahoo"}
...would result in this being in the text box:
Google; Yahoo
My problem is, I can't seem to figure out the syntax to create an individual link in the textbox without making the entire textbox a single hyperlink, which isn't gonna work.
I was working with a few solutions that I've found. I read that this would create the link in the way I need, but it just comes through as literal text with the pound signs:
"Google # www.google.com # Some Argument"
I also tried setting the textbox to rich text, then setting the value to include rich text code for a hyperlink... but that's not working:
"{\field{\*\fldinst HYPERLINK ""http://www.google.com/""}{\fldrslt http://www.google.com}}"
I also thought about designing a Query that will return the hyperlinks. But, I kind of wanted to make it a VBA thing, because I'll have more flexibility in how I create the value. Does anyone have any ideas?
Note: I understand that multiple values should be in a 1:M relational database. They are. But, the requirements of the task are to get all the M values for a 1 entity, then list them out in semi-colon, delimited fashion, which all serve as links to a Details table for the M entity.
Regular textboxes (text only) don't support this.
It is possible with Rich text textboxes. In contrast to the name, they actually use a subset of HTML, not RTF.
With ideas from here I got this working:
Private Sub cmdInsertHyperlinks_Click()
Dim url1 As String, url2 As String
url1 = "D:\tmp\test.jpg"
url2 = "D:\tmp\test space.txt"
Me.rText.Value = "<div>" & _
"file://" & url1 & "" & _
" other text between hyperlinks " & _
"file://" & url2 & "" & _
"</div>"
End Sub
Note: the linked thread says you must URL-encode the links (space to %20 etc), but at least for my simple test, that wasn't necessary.
Note 2: You can't have a different display text and link url, at least I didn't get that to work.