Subform issue ms access vba - vba

I am writing because I faced very time consuming issue I have not yet solved. It is connected with ms access query and form data exchange. To put it in a simple way. I have the following form:
Form
I have table with cars and inside it columns in the order as shown in the Q_Cars query. I have also subform which is updated using particular comboboxes (currently two assigned) which are updating query using VBA code (requery option). However it works only if I pick values for both comboboxes only.
Can you help me to find a way to put i a query criteria criterion which for an empty combobox will run query with all available data?
I tried to use e.g. the following structure inside criteria in query form:
IIf( Formularze![Form]![T_id] <>""; «Wyr» Formularze![Form]![T_id] ;>0)
Or other attempts with isempty, isnull function but without success.
Do you know how to solve this issue?
In my version due to language "," is replaced with ";" inside if structure.
Remaining code:
Private Sub btn_clear_Click()
Me.T_brand.Value = ""
Me.T_id.Value = ""
Me.T_color = ""
Me.T_seats = ""
Q_Cars_subform.Requery
End Sub
Private Sub T_brand_AfterUpdate()
Q_Cars_subform.Requery
End Sub
Private Sub T_id_AfterUpdate()
Q_Cars_subform.Requery
End Sub
and table
table
Regards,
Peter
Query code:
SELECT Cars.car_id, Cars.car_brand, Cars.car_color, Cars.car_seats
FROM Cars
WHERE (((Cars.car_id)=IIf(Formularze!Form!T_id<>"","«Wyr» Formularze![Form]![T_id] ",(Cars.car_id)>0)) And ((Cars.car_brand)=Formularze!Form!T_brand));

That IIF contains invalid code.
You can just use a logical OR statement in your WHERE criterium, no need for IIF.
Try the following:
SELECT Cars.car_id, Cars.car_brand, Cars.car_color, Cars.car_seats
FROM Cars
WHERE (Cars.car_id = Formularze![Form]![T_id] OR Nz(Formularze![Form]![T_id]) = "")
AND (Cars.car_brand = Formularze!Form!T_brand OR NZ(Formularze!Form!T_brand) = "");
Note that this will show everything if both are empty, I can adjust it to show nothing in that case if needed.

Related

MS Access 2019: Can't populate a form field using SQL query in VBA

I want to auto-populate a field in my form based on the results of an SQL query. I'm just not sure of the proper syntax to get it to properly read the query. This is what I've got, but it's not returning the value of the query, it's actually just returning the text of the query itself.
Private Sub PurchBatchNo_Enter()
Dim MostRecentPurchBatch As String
MostRecentPurchBatch = "SELECT Max(PurchaseBatchNo) FROM purchases"
Me.PurchBatchNo.Value = MostRecentPurchBatch
End Sub
I'm sure the issue has to do with the quotation marks, but it doesn't work without them either, and I'm not sure how to write it properly.
Thanks for being here for beginners like me!
All your code does is set a variable to a string of characters then attempts to set value of field with that string.
But why would you want to populate field with a value already used in a record? Most likely you need to increment by 1.
To use an SQL statement, would have to open a recordset object then reference field of recordset.
Private Sub PurchBatchNo_Enter()
Dim MostRecentPurchBatch As DAO.Recordset
If IsNull(Me.PurchBatchNo) Then
Set MostRecentPurchBatch = CurrentDb.OpenRecordset("SELECT Max(PurchaseBatchNo) AS MaxBatch FROM purchases")
Me.PurchBatchNo = MostRecentPurchBatch!MaxBatch + 1
End If
End Sub
However, pulling a single value from table is what domain aggregate functions are good for.
Private Sub PurchBatchNo_Enter()
If IsNull(Me.PurchBatchNo) Then Me.PurchBatchNo = DMax("PurchaseBatchNo", "purchases") + 1
End Sub
Instead of using VBA procedure, consider just setting DefaultValue property of textbox bound to PurchBatchNo field with the DMax() expression. As soon as record is initiated by input to another textbox, the PurchBatchNo will populate.
If user should not be able to edit this value, set textbox as Locked Yes and TabStop No and use a different event for the VBA code if you go with VBA.

Access button to open multiple reports depending on user input

I am new to access so this might be an easy task or I am just trying to tackle it wrongly. I have a report that has various columns, sample id, sample time, sample type, dry matter, moisture. I am trying to create a button that has an input box for the user to chose what column to sort the report by. So far I thought of creating various reports that have been sorted by each column, named the reports by the column that sorts them then I am trying to have the open report action have a parameter that opens the report linked to the column entered at the input box. Is this even possible or is there a workaround for this.
PS. I am avoiding creating various buttons since it will fill up the screen.
Okay, this is pretty generic and will require some tweaking but it shows the core of how to do this.
To start with you need a module (so not form/report code). This is where the globals will be assigned values:
Option Compare Database
Option Explicit
Global rptname As String
Global fldname As String
Sub setRptName(name As String)
rptname = "Report Sorted by: " & name
fldname = name
End Sub
You will call that code inside the Click() event of your command button on your form and then open the report after that. This will take a combo box value and pass that value to the module code, creating the two global variables.:
Private Sub cmd_report_Click()
mdl_Globals.setRptName Me.cmb_fields.Value
DoCmd.OpenReport "Report1", acViewPreview
End Sub
I'm unsure if this will work with non-preview views, but you probably want preview anyway.
Lastly in the report code behind, you need the Load() and open() events, you may be able to get it to work with both inside one or other but I know this one works.
So to set the caption:
Private Sub Report_Load()
Me.lbl_header.Caption = rptname
End Sub
And then to sort:
Private Sub report_open(Cancel As Integer)
Me.Report.OrderBy = "[" & fldname & "]"
Me.Report.OrderByOn = True
End Sub
If your entry box on the form does not have entries that exactly match the name(s) of the fields in the table you will get a parameter popup.

Form/Query couple stops working once embedded in another Form

[Working in MS Access 2019 Professional Plus 2019. Not that it matters though.]
My setup can be narrowed down to this hierarchy, which works perfectly fine on its own :
'------> Hierarchy of objects :
"myMainForm" contains :
"select_client" (ComboBox based on "client" table)
"select_status" (ComboBox based on "status" table)
' and some multi-select checkboxes that forbid use of Master/Child feature
"mySubForm"
"Source Object" : "myQuery" ' "mySubForm" not saved with an explicit name, local to "myMainForm"
"mQuery" filters the table "course" :
"client_ID" criteria : [Forms]![myMainForm]![select_client]
"status_ID" criteria : [Forms]![myMainForm]![select_status]
'------> "myMainForm" VBA to requery on change (could be performed with Macros) :
Private Sub select_client_Change()
Me!mySubForm.Requery
End Sub
Private Sub select_status_Change()
Me!mySubForm.Requery
End Sub
Then I try to embed "myMainForm" in a higher level form (let's say "myNavForm") :
"myNavForm" contains :
"myMainForm" contains :
' same as above from there
"mySubForm"
When I try to run "myNavForm", I get prompted for [Forms]![myMainForm]![select_client] and [Forms]![myMainForm]![select_status], and "myMainForm" stops working entirely.
I first thought the problem was related to the ComboBox values not being loaded yet when "myQuery" is triggered, so I added the following VBA to "myMainForm" :
Private Sub Form_Load()
Me!mySubForm.SourceObject = "Query.myQuery"
Me!mySubForm.Requery
End Sub
Private Sub Form_Unload(Cancel As Integer)
Me!mySubForm.SourceObject = ""
End Sub
But the problem remains the same. I guess it comes from a scope / path mistake on my side, but I can't figure it out. I tried absolute paths in "myQuery" as you can see above. I also tried using relative paths with .Parent but couldn't make "myMainForm" to work with it (without even embedding in "myNavForm").
Therefore, I am stuck and screwed and desperate and I want my Node/MongoDB environment back, but I have to do this in Access (don't ask !).
Any idea how to make it work with embedding ? As much as possible, I'd prefer sticking to that setup and avoid entering more complex VBA (the syntax gives me headaches), but I'm open to it if needed ;-)
Thx for any kind of help to free me from that nightmare !
[EDIT : SOLUTION IN MY USE CASE BASED ON ACCEPTED ANSWER (for future readers !)]
Thanks to #Olivier , here is the solution working flawlessly :
'------> Hierarchy of objects :
"myMainForm" contains :
"select_client" '(ComboBox based on "client" table)
"select_status" '(ComboBox based on "status" table)
"mySubForm"
"Source Object" : "myQuery" 'remove all criteria from the query !
' ------> Handle the rest in VBA :
'Lets write this only once...
Private Sub updateResult()
mySubForm.Form.Filter = "client_ID=" & select_client & " AND status_ID=" & select_status
mySubForm.Form.FilterOn = True
End Sub
'Apply filter with default values upon loading
Private Sub mySubForm_Current()
updateResult
End Sub
'Update filter whenever a control is updated
Private Sub select_client_AfterUpdate()
updateResult
End Sub
Private Sub select_status_AfterUpdate()
updateResult
End Sub
All in all, I finally have a nice framework to update any multi-criteria query on the fly after any control update and view the result immediately on the form, behaving just as any modern GUI should ! Thx again Olivier !
This is because then your select_client has another path. Now it is
[Forms]![myNavForm]![myMainForm].Form![select_status]
where myMainForm is now a subform-control. It may have a different name than the contained form.
Instead of including such paths into the query, try to filter the subform like this
mySubForm.Form.Filter = "client_ID=" & select_client & " AND status_ID=" & select_status
mySubForm.Form.FilterOn = True
You would do so in the after update events of these two fields and on the form OnCurrent event.

MS access check column value and change another

I have an ms access database with some yes/no columns I want to check and set the value of a third. The statement should be something like the following
if !col1 && !col2:
col3 = no
else:
col3= yes
I keep searching but don't really understand vba and can't find what I need .. Mostly a segment of an answer to something else that I cant make work. Currently trying to create it in the "module" section is that even right? Would be best if this could be done automatically as those columns are changed or maybe run once and do all rows. Please help me get on the right track, any help greatly appreciated.
Here is what I would do:
1- Create a form and add at least one command button on it. Name it cmdMyButton or cmdAnythingThatYouWant (cmd is the prefix used in examples from Microsoft for command buttons)
2- in the design view, double click the command button so to pop the code window
3- In the onClick() function, write the code that opens up a recordset for your table, loop through records and for each row, verify the value of those 2 columns and update if needed. (look at the documentation for DAO.recordset)
Let's say you have an Access table named Table1, with some Access fields:
The following Access SQL statement will update the value of col3 based on the values of col1 and col2, for every row in Table1:
UPDATE Table1
SET col3 = NOT col1 AND NOT col2
There are a number of ways to leverage this SQL statement:
You can paste it into the Query Designer in SQL view, and execute it via the Access UI
You can run it as part of an Access macro
You can execute it in VBA, using ADO or DAO
You can execute it in VBA, using the DoCmd.RunSQL method
Instead of VBA, you can use another Automation-supporting programming language
I would just create this on a calculated column in your DB table. See screen shot below:
Notice in the properties I set a formula to acquire the desired results based on the first 2 columns. The "Result type" is set to yes/no to mimic the yes/no field. Only difference is, the third column will display a -1 (True) or 0 (False). but when displaying this information on a form, you can have it display the information in a checkbox fashion. The calculated field is also ideal cause it will only update the third column when the target record is updated, not updating the whole table, very useful if the table size starts holding over 100k records.
If you want a VBA code, then you will need a trigger. I'm assuming its a button on the form, if not, you can always change the below code to match the event you want it triggered on. The below code is also a module that can be called/used for any trigger. The code is also assuming you have a primary key.
Public Sub UpdateThirdColumn(ByVal RecordPK As String) 'RecordPK is a passed variable
'that is the primary key identifier to find the
'record in the table
'Set variavble name for SQL statement, gives you one place to update instead of hunting through code
Dim strSQL As String
'Creates the SQL string in the variable assigned
strSQL = "UPDATE {YourTableNameHere} " & _
"SET {YourThirdFieldNAmeHere} = True " & _
"WHERE ((({YourFirstFieldNAmeHere}) = True AND ({YourSecondFieldNAmeHere}) = True AND ({YourPrimaryKeyFieldHere}) ='" & RecordPK & "'));"
'Executes the SQL statement, dbFailOnError will fail if problem exists in SQL statement
CurrentDb.Execute strSQL, dbFailOnError
End Sub
'Use this code if you have a button to trigger event
Private Sub YourButton_Click()
Call UpdateThirdColumn(Me.YourPrimaryKeyControlName)
End Sub
'Use the bottom 2 codes if you want the update for each check box to be checked and update
Private Sub FirstFieldName_AfterUpdate()
Call UpdateThirdColumn(Me.YourPrimaryKeyControlName)
End Sub
Private Sub SecondFieldName_AfterUpdate()
Call UpdateThirdColumn(Me.YourPrimaryKeyControlName)
End Sub
Let me know if you need more assistance or explanation and I will be glad to help.

Customizing an access query based on values of various checkboxes

I'm new to access, and I need to selectively query a database based on a set of checkboxes. For example, If a checkbox called basketball is checked, I'll want to find all records that have that in their Name field. If basketball and baseball are checked, I'll want to find records for both basketball and baseball. The current way we have of doing this is ugly and inefficient, and I'm thinking that this is a fairly common problem to have, so there must be a better way of solving it. I've seen similar things online, but these deal with only one checkbox (not 10 or so like in our form) and they simply aren't very helpful.
Thanks
I'll make a few assumptions, here. I'll assume you have 4 sports; Baseball, Basketball, Football and Hockey. You can add more if you like.
I'll assume you have 4 checkboxes; BaseballCheck, BasketballCheck, FootballCheck and HockeyCheck.
I'll assume you have a table called MyTable, with a field called Sport.
What you can do is add a button to your form. Call it btnSubmit. Add this VBA to your button:
Dim db as Database
Dim rec as Recordset
Dim MySQL as String
Set db = CurrentDB
MySQL = "SELECT * FROM MyTable WHERE 1 = 1"
If BaseballCheck = True then
MySQL = MySQL & " AND Sport = 'Baseball'"
EndIf
If HockeyCheck = True then
MySQL = MySQL & " AND Sport = 'Hockey'"
EndIf
If BasketballCheck = True then
MySQL = MySQL & " AND Sport = 'Basketball'"
EndIf
Etc...
Set rec = db.OpenRecordset(MySQL)
Instead of that last statement, you can use CreateQuerydef to create a permanent query that you can then use as the basis for a report. However, you would have to add some code at the beginning to delete that querydef if it exists, otherwise it will throw an error.
If you want something a little more elegant (and one that will allow for easier scalability) you could always loop through all the checkboxes on your form and dump the sports into an array, and then use that array as the subject of a "WHERE Sport IN (...)" statement.
As no reference information is provided, i use the following for this example;
Formname = Form1
Tablename = test
Checkfieldname = BaseballCheck
In the form property sheet, add the following vba for the BaseBallCheck, this will requery the form after the check has been enabled/disabled.
Private Sub BaseballCheck_AfterUpdate()
Me.Requery
End Sub
Then in the form Recordsource add the following
SELECT test.Baseball
FROM test
WHERE (((test.Baseball)=[forms]![Form1]![BaseballCheck]));
Now when the form refreshes only the values are shown where Baseball = checked or unchecked.