Subform multi criteria query not working? - vba

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. :)

Related

Access: dynamically query tables

I built an Access database to contain information regarding parts that we use to create schematics. There is one table that contain "basic" information, like "unique part ID" ("TUPID"), links to datasheets and so on - and the "Partition" further information is stored.
Furthermore there are several tables (this is "Partition") that contain information on the part itself: one table for resistors, one for connectors, one for power-ICs and so on. Each table has many fields different from other tables, but there are fields that exist on each table, eg. "Manufacturer", "Symbol", "Package" and "Height".
Now I have a split form ("10_Change_BaseInformation") that shows the "basic information", so when I select one row in the database-part of the form, the data is loaded into textboxes and can be edited. Additionally I want to see the information from the "Partition"-table in this form, so I wrote this:
Private Sub Form_Click()
Dim SelectedPartition As String: SelectedPartition = Forms![10_Change_BaseInformation]![Text25]
'Field "Text25" contains the TUPID
Dim SQLStatement As String
SQLStatement = "SELECT " & SelectedPartition & ".TUPID, " & SelectedPartition & ".[Mfg]" & vbCr & _
"FROM " & SelectedPartition & vbCr & _
"WHERE (((" & SelectedPartition & ".TUPID)=[Forms]![10_Change_BaseInformation]![TUPID]));"
DoCmd.RunSQL SQLStatement
' SQLStatement = "SELECT Resistor.TUPID, Resistor.[Hersteller] FROM ResistorWHERE (((Resistor.TUPID)=[Forms]![10_Change_BaseInformation]![TUPID]));"
End Sub
First of all, I get runtime-error "2342", but I can't make any sense of that; so: how do I have to modify my code, to get a valid result?
Second, how can I get the values from the query to the form?
Thanks in advance for your help!
I can't speak to the reason of your error, as we would need more information such as the types of your fields in your table.
I'm guessing that your Resistor.TUPID field is a string.
If so, you need to modify your code as below:
WHERE (((" & SelectedPartition & ".TUPID)='" & [Forms]![10_Change_BaseInformation]![TUPID] & "'));
If it is of Type number then
WHERE (((" & SelectedPartition & ".TUPID)=" & [Forms]![10_Change_BaseInformation]![TUPID] & "));
As to the form...
Generally speaking, you can design a form without a record source, but with controls that are named the same as your select query fields.
When designing each Control on the form, you have to explicitly specify the Control Source (i.e. The field names that are returned from your select query), otherwise they will be Unbound and never update automatically based on Record Source.
Then assign your SQL query string to the Recordsource of the form.
MyForm.Recordsource = MySQLString
Then run the Requery method of the form.
MyForm.Requery

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.

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

VBA syntax in Access 2010: How to open form to specific record with composite primary key

edited following andshrew's answer
I'm just finding my feet in VBA scripting and am a bit stumped with this rather simple bit of code. I suspect it is because I'm not getting the syntax of the Where statement right. The code below should open a form to the one record that matches both filter expressions but instead it opens to a blank record. If I only use one filter expression, it works as desired and opens the form to the correct subset of records. From what I found elsewhere it should be possible to combine multiple filter criteria with an AND, so I'm at a loss why this isn't working.
See below the code for a more extensive description of what I'm trying to do, in case this isn't a simple syntax issue after all.
Private Sub lsPrevObs_DblClick(Cancel As Integer)
Dim Microchip As String
Dim ObsDate As Date
Microchip = Me.Text24
ObsDate = Me.lsPrevObs
DoCmd.OpenForm "frmObservationsEdit", acNormal, , "ObsMicrochip ='" & Microchip & "' AND TrappingDate = #" & ObsDate & "#", acFormEdit
End Sub
Context for this sub:
I have a table containing basic information about individual animals with their microchip number (despite the name it does contain letters and is therefore a string, not an integer) as primary key. Then I have a table of observations, which uses the Microchip number and the observation date as a composite primary key.
I have a form linked to the first table. A text box (Text24) displays the microchip number of the current record and a list box (lsPrevObs) shows the dates of observations for the animal for which there already are records in the observation table. I want to tie some VBA code to the double click event of the list box so that when the user double clicks a date, a new form opens (frmObservationsEdit, DataEntry=No) and allows for that observation record to be edited.
Thanks for looking at this.
Unless the code in your example is incorrect, you're currently using the VBA 'and' command rather than sending a SQL 'and' as part of the Where string.
Simply changing your code as follows to make sure the and is within the quotes should make it work.
DoCmd.OpenForm "frmObservationsEdit", acNormal, , "ObsMicrochip ='" & Microchip & "' and TrappingDate = #" & ObsDate & "#", acFormEdit

Microsoft Access 2010 - Dynamic query

I have an access web database that several users will need to log in to. The database contains a table of products.
The challenge is, every user needs to only see a subset of these products and never see the whole list.
At the moment i have some code to modify an existing query based on the logged in user's details. As they log in, some tempvars are created and these are used to modify the query criteria.
This works well when the first user logs in, but the moment the next user logs in, the query is modified again and the product list refreshes and now his products are shown and not the first users! Im thinking i need to dynamically create a permanent query for each user on log in?
Or is a better way to accomplish what im trying ? im quite new to access and struggling. Can anyone assist please?
Here is my code so far:
Button on login form has the following code that collects the user's details
Private Sub cmdLoginMine_Click()
Dim ID as long, strEmpName as string,strZondsc as string,strgrpdsc as string
ID = DLookup("ID", "Employees", "Login='" & Me.txtUser.Value & "'")
strEmpName = DLookup("FullName", "Employees", "Login='" & Me.txtUser.Value & "'")
strgrpdsc = DLookup("MyGrpdscs", "Employees", "Login='" & Me.txtUser.Value & "'")
strzondsc = DLookup("MyZondscs", "Employees", "Login='" & Me.txtUser.Value & "'")
TempVars.Add "tmpEmployeeID", ID
TempVars.Add "tmpEmployeeName", txtUser.Value
I then call a function that modifies the existing query, populating it with this users details for the criteria
qryEdit strgrpdsc, strzondsc, ID
Sub qryEdit(strgrpdsc As String, strzondsc As String, ID As Long)
Dim qdf As DAO.QueryDef
Dim qdfOLD As String
Set qdf = CurrentDb.QueryDefs("InventoryQryforDS")
With qdf
.SQL = "SELECT Products.ProductCode, Products.ProductName, Products.GRPDSC, Categories.Category, Inventory.Available " & _
"FROM (Categories INNER JOIN Products ON Categories.ID = Products.CategoryID) INNER JOIN Inventory ON Products.ID = Inventory.ProductID " & _
"WHERE Products.GRPDSC in (" & strgrpdsc & ") and Categories.Category in (" & strzondsc & ") and products.ownersid =" & ID & _
" ORDER BY Products.ProductCode"
End With
Set qdf = Nothing
End Sub
The results of the query are shown on a form, which is what is currently requerying and showing the wrong data.
Thanks
EDIT - THe data is shown on a form, linked to one of the new style navigation buttons as shown.The recordsource property of the form is the query that's populated as described above.
I have a few suggestions/corrections to your approach to solving this issue.
When using DLookup, make sure they are enclosed within Nz() function, if the value you are looking for is not found you might be facing troubles of assigning a Null value to a Data Type that cannot handle Null. Anything other than Variant type will suffer.
You seem to do not one but four DLookup's on the table. This could be very expensive. This could be minimized by using a simple RecordSet Object.
I would not use TempVars much as they could be tricky to understand and implement.
Why are you editing the Query? This could again be a bit expensive in terms of memory. How are you showing the list of Products? In DataSheet or ComboBox or LsitBox? You could yet again change the RecordSource or RowSource of the Objects rather than editing the Query itself.
Finally, your users should all have a separate copy of the Front End file. Not one copy used by 20-30 people. If the files is restricted to be used by one person, then the code should work regardless of being modified. As the user will have access to the right data at all times.