Dynamic Query in a MS-Access form - ms-access

I have a form in Microsoft Access (2016) where I have a dropdown list named KID. When the dropdown list looses Focus I want to run a query that would look like this:
SELECT max(Cnt)
FROM Table
WHERE KID = ValueOfDropdownList
The result of this query should be usable in a variable in the VB Code of the Event.
Unfortuantly I am restricted to Access at the Moment. Am I even using Access the right way (Choose from dropdown in form -> Event -> SQL Query in VB -> Display in form) or are there better ways to do that?
Thanks for your help in advance!

Firstly I would use the AfterUpdate event of the combo box, otherwise it will fire even if someone just tabs through the control.
Secondly if this is just to set a variable you would probably be better to use a Domain function in this case a DMax()
iVariable = DMax("Cnt","Table","[KID] = " & Me.YourComboControlName )
This assumes KID is a number field. If KID is text you would need to delimit the criteria like this;
iVariable = DMax("Cnt","Table","[KID] = '" & Me.YourComboControlName & "'" )
Lastly if you want this to update as you scroll through records you would need to add the same code to the OnCurrent event of the form. That fires when the record changes.
If it is for display purposes you can't use the same technique on a continuous form if this is setting an Unbound control, you would need to pull this in to the underlying forms recordset.

You can use DMax:
YourVariable = DMax("[Cnt]", "[Table]", "[KID] = " & Me!DropdownListName.Value & "")
In case KID is text, apply quotes:
YourVariable = DMax("[Cnt]", "[Table]", "[KID] = '" & Me!DropdownListName.Value & "'")

FYI there is another option. As the data source of your combo,
use a query returning 2 columns, like select KID, max(cnt) from table1 group by KID.
Then in your text box, retrieve your value using =combo1.columns(1).
For this to work you need to specify in the combo properties that it has 2 columns. In the formula, don't forget that those combo columns are 0 based.
This is the most efficient solution when you need to retrieve several values linked to the combo (and you don't have millions of records).

Related

Filter subform table with textbox

I am trying to filter a subform with a textbox.
I have a query to show table records in the subform and I have the criteria to filter the table, but when I type in the textbox to filter the sub form it only shows me one record with that name. I need it to show me all the names.
The criteria for my query is below.
Like "*" & [Forms]![frmPlanningForecast]![FETextbox].[Text] & "*"
I then have an OnChange event on the textbox to requery the subform.
As mentioned above I need it to show me all the records matching what i have typed, not just one.
When I use the filter option within the table itself(Dropdown box on the field header) and select the filter from there, it works great. But I need it to be typed into a textbox.
The picture attached will show you what I mean, I have "EQ" typed in the text box but it has only returned 1 record when their are 15 called "EQ" on the table.
First of all add single quotes around Like parameter:
Like "'*" & [Forms]![frmPlanningForecast]![FETextbox] & "*'"
and second - Access has an old bug: if you refer in the query to form field like you did, it doesn't renew the value, used for criteria during Requery, you always will receive the same results. Workaround - replace reference to field by global function, which returns textbox value or use dynamic generating of RecordSource for subform.
Global function example:
Public Function GetFE() As Variable
GetFE = [Forms]![frmPlanningForecast]![FETextbox]
End Function
Place it in any standard VBA module. Then your Like will look like this:
Like "'*" & GetFE() & "*'"
I found an easier method and just wanted to let others know.
Instead of using criteria I used the following vba code.
DoCmd.ApplyFilter , (FETextbox = qryPlannedHours.LeadFE), SubFormPF
In older versions of Access, didn't there used to be an option in the query to use the sum field something like this:
[Formnane].[TextField]
I know that's very simplistic and I don't fully recall how to use it but it was something like that, simple and straight forward if you're not a VB user. Forgive my lack of conviction, I've used it before but it was 20 years ago.

Possible to change MS Access subform fields through VBA?

I can find plenty of examples of how to return specific records in a subform through altering the underlying source query in code and re-querying, but I'm struggling to use the same principle to alter the fields that are returned.
I have the following situation:
Combobox to select 1 of 5 fields. Subform is supposed to show the selected field plus a couple of static fields, lets call them fields 6 and 7
So in the case the user selects field 1 from the dropdown, subform should show fields 1, 6 and 7. In the case they pick field 4, subform should show fields 4, 6 and 7 etc.
This is what (amongst other things) I've tried:
Set the subform up through the wizard with a query (select field1, field6, field7) as source, amend said query after combobox selection is made:
Set qd = CurrentDb.QueryDefs("myqueryname")
qd.SQL = "Select " & mycomboboxselection & ",field6,field7 from mytablename"
Form_mymainformname.mysubformname.Requery
The query itself updates fine if I run that standalone after the change, but the subform within the main form doesn't change and when I click on the subform itself from the navigation window it seems to be stuck looking for field 1 as it asks me to input a parameter value
Can anyone help with how to achieve this please?
Set the RecordSource of the subform to the SQL:
Dim SQL As String
SQL = "Select " & mycomboboxselection & ",field6,field7 from mytablename"
Me!YourSubformControl.Form.RecordSource = SQL
It will force a requery of the subform.
Ok I found a solution after a few more hours searching and trial and error.
There are two seperate problems here. Firstly creating the subform uses the newly created form as the source object rather than directly using the query, and it seems that no matter how you try to manipulate the record source of said form, it doesn't like changing the fields it was built with.
So, create the subform, change the source object from the form to your query (and delete the now pointless newly created form), then you can use the code I started with:
Set qd = CurrentDb.QueryDefs("myqueryname")
qd.SQL = "Select " & mycomboboxselection & ",field6,field7 from mytablename"
Which works! sort of....
You have to close and reopen the form every time to see the actual updates though, which obviously isn't what we're going for
The other line does nothing:
Form_mymainformname.mysubformname.Requery
It works fine for a change of records, but apparently not for a change of fields. I suspect this is a bit of a ms quirk
The below, however, works, even though I feel like it should do exactly the same as the code line above:
Form_MyForm.MySubForm.SourceObject = Form_MyForm.MySubForm.SourceObject

Best practice for working with long texts in ms-access

I would be very thankful if somebody resolves my problem.
I'm new in working with Ms Access and I still gain experience on its basic functionality.
I have a table MyItems. 2 of its fields are: ItemCode and ItemName. ItemName is a very long text (Memo type). I have also a query and a form with many fields. The form's record source also consists of many fields. All these things (associated with 1 field) have the same or similar names so I can't differentiate them quite well.
What I want is when I set the value of ItemCode (in a not bound Combobox or Listbox with name ItemCode) the value of ItemName to be displayed in a control - maybe TextBox.
I can display its value in a ListBox (by sql query in its row source), I have no problems with this, I have no problems with managing events, but the text is very long and is cut. I understood that unfortunately ListBoxes don't have multiline property. So maybe the most appropriate control to deal with is a TextBox. And maybe the most appropriate way to display the value is using DLookUp function in the TextBox's control source. But in this sea of items with similar or the same names I just can't deal with its syntax, I was trying again and again for a very long time. So I have 2 questions:
Are the TextBox control and DLookUp function in its control source the best way to extract long texts from a table without binding or there are more suitable controls (which directly work with sql query)?
What is the right syntax of DLookUp? - where exactly are there ' ', " ", [ ], .Value, =, &, where must I write the path to the table or the form and where it would be mistake? If I just write [ItemCode] what it would be associated with - the form record source, the table, the form control or anything else? I would be grateful if someone writes the correct syntax for my case or if he shares a link with plenty of examples for using DLookUp. Those that I found didn't satisfy me.
Either a bound control, or an unbound one. If unbound, you need to load the text with VBA code or with DLookup in the control source. There are no other options.
Personally I'd rather use the AfterUpdate event of ItemCode, and call DLookup there, but that's a matter of preference.
2.
It's not that complicated. You basically have the SELECT, FROM, WHERE parts of an SQL query in the 3 arguments. [] are needed for all identifiers containing spaces or other special characters, and when refering to form controls.
=DLookup("ItemName", "[my Table]", "ItemCode = '" & [ItemCode] & "'")
The single quotes '' are needed if ItemCode is text, not when it is a number.
You could also use doubled (escaped) double quotes, but that is much less readable.
=DLookup("ItemName", "[my Table]", "ItemCode = """ & [ItemCode] & """")
Now where does [ItemCode] come from?
Access first looks for a control on the form with the name ItemCode.
If there isn't one, it looks for a field ItemCode in the form's RecordSource.
These are the only ways [ItemCode] can be evaluated. To avoid confusion, it is recommended to name bound controls with the same name as their source field.
The syntax above is only valid if everything is on the same form. If [ItemCode] is on a different form, or you refer to it from a query, you use
=DLookup("ItemName", "[my Table]", "ItemCode = '" & Forms![my Form]![ItemCode] & "'")
For more complicated cases with subforms, see Refer to Form and Subform properties and controls
And to use it in VBA (in ItemCode_AfterUpdate):
Me!ItemName = DLookup("ItemName", "[my Table]", "ItemCode = '" & Me![ItemCode] & "'")

LinkChildFields and LinkMasterFields being automatically set when changing recordsource

In Access Properties for a subform, I have "LinkChildFields = '' " and ""LinkMasterFields = '' " (i.e. blank for both, this is what I want: no link)
When I change the Recordsource of the subform, and requery the subform, (in VBA) they are both automatically being set to a field, in my case "CaseID" (resulting in no records being displayed)
This is my recordsource:
stSQL = "SELECT qryCasesAndCards1.CaseID, qryCasesAndCards1.CaseStatusID, qryCasesAndCards1.Status, qryCasesAndCards1.CompanyName, qryCasesAndCards1.NumberOfCards, qryCasesAndCards1.FullName, qryCasesAndCards1.CaseCreatedDate, qryCasesAndCards1.CaseClosedDate, qryCasesAndCards1.CreatedBy" & _
" FROM qryCasesAndCards1 where not caseID = " & Me.CaseID & " and cardnumber in (select qryCasesAndCards1.cardnumber from qrycasesandcards1 where qryCasesAndCards1.caseID = " & Me.CaseID & ")"
I've tried substituting a simpler query "select * from qryCases1" and the problem still occurs.
In VBA, right after the requery, I am debug.print'ing ".linkchildfields" and ".linkmasterfields" and this is how I can see they are both being automatically set to "CaseID"
I have tried changing both values in Access form properties to nonsense value, resaving, changing again, resaving etc, and still no joy.
I can workaround problem by setting both those values right after the recordsource runs, but there is an unacceptable delay when doing this (about 5 seconds for each value)
One thing I'm just wondering now, is wether my form filter is being propagated to the subform? (am opening it via "docmd.open ... caseid = x" )
CaseID might have at ONE stage some long time ago been entered in to those link fields... but it's definitely not now. It's like they're locked in an Access vault somewhere and it's thinking "golly gee i'm pretty sure he wants CaseID in there gee whiz I'll get right on that!"
I've found MSAccess: Change in subform recordsource causes loss of LinkChildFields binding and I've found Linking SubReports Without LinkChild/LinkMaster but I can't get any help from them.
Thanks for any help offered: I'm tearing my hair out :)
To keep Access from automatically updating the LinkChildFields and LinkMasterFields on a subform...
Ensure that the RecordSource queries do not have matching key fieldnames.
Ensure that the Link Child Fields and Link Master Fields are blank on the SubForm object's Property Sheet.
DO NOT set the LinkChildFields and LinkMasterFields properties in code (i.e. remove any previous code like MySubForm.LinkChildFields = ""), otherwise the negative side effects may not be resolved.
If the form and/or subform are bound directly to tables, simply update one of them to query the table and add an alias for one of the key fields. For existing queries, it is possible to add an alias for one of the key field names without negative consequences in probably most cases. In my case, I only had to add "AS Acct" to a single field in the SELECT part of the subform's RecordSource SQL--no other change was necessary in the FROM, WHERE or ORDER BY clauses even though the original [Account] fieldname is referenced in each of those clauses.
SELECT Actions.[Account] As Acct, ...
Of course, this required an update to the ControlSource property for the relevant control on the form.
These changes eliminated the extra few-second lag when changing both the parent record and when switching records on the subform! Likewise, it eliminated redundant events during record navigation!
I found no other setting that keeps Access from automatically re-binding the subform via the LinkChildFields and LinkMasterFields properties. As already pointed out in the comments, it also doesn't help by resetting the link fields (e.g. LinkChildFields = "") after setting RecordSource, primarily because Access takes time to reset the fields, much of that time spent in events fired both upon the automatic assignment of the link fields and again when they are reset to blank. (e.g., Form_Current is called at least twice for each new record navigation.)
Years passed... as even on Microsoft Access 2019, changing subform .RecordSource always alters original .LinkChildFields and .LinkMasterFields, reassigning good fields will cost us 5s time for each property, we have no way to avoid this.
As a workarround, we can use always the same query, for example, qrySelTmp, as .RecordSource for the subform, at the design time
Mainform.subform.Form.RecordSource = "qrySelTmp"
When we must change .RecordSource content, we change only the definition of the Query, like this
CurrentDb.QueryDefs("qrySelTmp").SQL = "SELECT qryCasesAndCards1.CaseID, qryCasesAndCards1.CaseStatusID, qryCasesAndCards1.Status, qryCasesAndCards1.CompanyName, qryCasesAndCards1.NumberOfCards, qryCasesAndCards1.FullName, qryCasesAndCards1.CaseCreatedDate, qryCasesAndCards1.CaseClosedDate, qryCasesAndCards1.CreatedBy" & _
" FROM qryCasesAndCards1 where not caseID = " & Me.CaseID & " and cardnumber in (select qryCasesAndCards1.cardnumber from qrycasesandcards1 where qryCasesAndCards1.caseID = " & Me.CaseID & ")"
If(Mainform.subform.Form.RecordSource = "qrySelTmp") then
Mainform.subform.Form.Requery
else
Mainform.subform.Form.RecordSource = "qrySelTmp"
End if
As shown in the code, we do only a subform .Requery instead of assigning a new .RecordSource.
As Subform.Form.Requery does not alter subform properties .LinkChildFields and .LinkMasterFields, we gain about 8s for each real change of .RecordSource.
In my case with 1 Customer - Many Orders diagram, I've a gain of time at the proportion of 2s over 20s.
What I done in the past is simply REMOVE the link child/master settings.
Then in code I SET the child critera. So in the following, the link master/child SHOULD filter by tour_id, but I simply INCLUDED the criteria in the SQL and then HAMMER OUT the settings.
Dim strSql As String
' load sub-form to this tour....
strSql = "select * from qryGuidesForTour2 where Tour_id = " & Me!ID
Me.subGuides.Form.RecordSource = strSql
Me.subGuides.LinkChildFields = ""
Me.subGuides.LinkMasterFields = ""
The above was a fix and fixed any performance issues. I suppose it really depends on "how" the main form record is set, but if you are setting up the "main" form record via code, then as above simply stuff in the child forms recordset directly with the critera you need. And while in above I did blank out the master/child settings, if you ARE going to allow adding of reocrds in the sub form, then likely in above you should set the master/child fields as opposed blanking them out.

MS Access forms using a variable to run a query

Can you pass a variable to a query which will populate a combo box? If so, how?
You can set the row source of a combobox in a number of ways. For example, you could include the following in the current event:
Me.ComboX.RowSource = _
"SELECT ID, Description FROM Table WHERE AText='" & MyVar & "'"
Alternatively, you can refer to a form in code or in design view:
SELECT ID, Description FROM Table WHERE AText=Forms!AnOpenForm!AControl
You may also wish to consider cascading comboboxes : Is there a simple way of populating dropdown in this Access Database schema?