Customizing an access query based on values of various checkboxes - sql

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.

Related

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.

Subform issue ms access 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.

combobox.column property returns invalid use of null in vba

I am a database//Access noob, so bear with me. I have a database set up to keep track of Consultants and their Vendors for a tech consulting company. Some consultants are their own vendors, and some have third-party vendors that handle their contracting. In the case where a consultant is also their own vendor, the contact information is the same for both. Contact Info is stored in a separate table, with primary key ContactID and foreign key fields for ConsultantID (primary key in ConsultantT) and VendorID (primary key in VendorT).
In the case that the relevant Contact Info has already been entered on one of the forms, I want to be able to select the already existing Contact Info record and tell the database to add the other foreign key ID field to the existing record based on the record on the main form. So, for example, if I have already entered Contact Info for Consultant A via the Consultant form, when I open the Vendor form to add Consultant A's vendor I want the option to select "Consultant A" from a combo box and have their info populate VendorsF's Contact Info form while adding the VendorID to the already existing Contact Info record for Consultant A.
I think I've almost worked it out, but am stuck on one last thing. Right now I have a popup form (ChooseConsultantInfoF) for selecting an existing ContactInfo record. On that form I have a search combobox (SelectConsultantCombo) to select the existing record, and a command button (SaveConsultantbtn) which I've tried to code to Update the ContactInfoT and add the VendorID from the current record on the VendorsF to the existing record in ContactInfoT. Here is the all of the code for the popup form:
Option Compare Database
Option Explicit
Private Sub SaveConsultantbtn_Click()
Dim stupid As Long
stupid = SelectConsultantCombo.Column(0)
DoCmd.RunSQL "UPDATE ContactInfoT SET VendorID = (Forms!VendorsF!VendorID) Where ContactInfoID = " & stupid & ";"
End Sub
Private Sub SelectConsultantCombo_AfterUpdate()
Dim rst As DAO.Recordset
Set rst = Me.RecordsetClone
rst.FindFirst "ContactInfoID = " & Me!SelectConsultantCombo
Me.Bookmark = rst.Bookmark
leave:
Me!SelectConsultantCombo = Null
If Not rst Is Nothing Then Set rst = Nothing
Exit Sub
End Sub
When I try to put it into action, I get Error 94: Invalid use of Null and it pulls up
stupid = SelectConsultantCombo.Column(0)
I know the code block works apart from that--I tried the Click event once with a numeric value instead of the variable:
Private Sub SaveConsultantbtn_Click()
DoCmd.RunSQL "UPDATE ContactInfoT SET VendorID = (Forms!VendorsF!VendorID) Where ContactInfoID = 1 ;"
End Sub
without any trouble, so the issue must be in calling the combobox's column.
I also tried defining the variable with Nz to allow Null:
stupid = Nz(Me.SelectConsultantCombo.Column(0), 0)
and that gets the code working also, but still doesn't save my VendorID to the record in ContactInfoT. None of the columns in the combobox contain Null values (none that I can find, anyway). Dunno if this is useful, but the Row Source of the combobox is:
SELECT ContactInfoT.ContactInfoID, ConsultantT.ConsultantID, ConsultantT.FirstName, ConsultantT.LastName FROM ConsultantT INNER JOIN ContactInfoT ON ConsultantT.ConsultantID = ContactInfoT.ConsultantID ORDER BY ConsultantT.[LastName], ConsultantT.[FirstName];
Does anyone know why Access doesn't recognize my combobox.column property? Or is there another way to write this up in VBA to avoid this error?
First try stupid = Me.SelectConsultantCombo.Column(0) (you are missing the Me. part).
But what you should really do is make sure your bound column on the combo box is set correctly and just use stupid = Me.SelectConsultantCombo
I took Me!SelectConsultantCombo = Null out of the combo's afterupdate and it works perfectly now! Of course if I have the combo set to null somewhere in the code it's going to pull up null somewhere else, d'oh!

Access Calculate Next Value (lookup value}?

I need to get a value from a textbox in a report's detail section which will give me multiple values. I need to get each of those values into VB to do some calculations... I can pull a value from forms with ChildID = Forms!FRM_Child!ChildID.Value, but when I put
Private Sub Report_Open(Cancel As Integer)
Dim ChildID as Integer
ChildID = Reports!RPT_Due_Date!ChildID.Value
End Sub
it crashes and says "Run-time error '2424': The expression you entered has a field, control, or property name that Microsoft Access can't find."
I've checked and double checked the names. The thing I figure is that somehow because it's in the detail section with multiple values it crashes. Any ideas?
ChildID Last_Asmt_Type Last_Asmt_Date Next_Asmt_Type Next_Asmt_Date
1 Initial Evaluation 1/5/15 Periodic Review 5/5/15
2 Periodic Review 2/5/15 Annual Review 6/1/15
3 Annual Review 3/5/15 Periodic Review 7/1/15
What I want to do is get the Last_Asmt_Type and then with if/then rules select the Next_Asmt_Type ie If Last_Asmt_Type is Periodic Then Next_Asmt_Type is Annual....
How would I do this with a lookup value?
In Report_Open(), the textbox exists as control, but it has no value yet.
Your code would work in Report_Load(), but as you already know, it would be pointless because you would only get the first value.
If you want to read all values, don't try to read them from the report textbox, open a recordset on the report's data source. Like this:
Dim RS As Recordset
Set RS = CurrentDb.OpenRecordset(Me.RecordSource)
Do While Not RS.EOF
Debug.Print RS!MMI
RS.MoveNext
Loop
RS.Close
But:
Most probably there is an entirely different and better way to do what you want. What kind of calculations are you doing?

Access VBA with custom function in SQL

I need to open a query or recordset or something (datasheet view) with some sql i build in my vba based on form control values. I have a "many to many" relationship in my data (kind of). Pretend we have a Person table, a Pet table and an ID Pet_Person table. I want to have a list of my People with a concatenated string of all their pets in one row of returned data. So....
Row Person Pets
1 Kim Lucius, Frodo, Cricket, Nemo
2 Bob Taco
And I googled and I found you can write functions in the VBA to be called from the SQL. So. Here's the problem. I have a lot of records and once opened, I cannot move around the datasheet view/query/whatever without that concatenation function being called everytime I click on a row. I only need it called once when the sql is initially ran... like a snapshot or something.
I'm not too well versed with Access and the possibilities. I've tried some things I found online that all had the same result... that concatenation function being called when I touched that resulting dataset at all.
Last thing I tried looks something like:
With db
Set qdf = .CreateQueryDef("Search Results", q)
DoCmd.OpenQuery "Search Results", , acReadOnly
.QueryDefs.Delete "Search Results"
End With
StackOverflow really never formats my stuff correctly. Probably user error.... oh, well.
Edit:
Oh Bart S. Thank you but you went away too soon for me to understand the answer if it is there. Thank you.
Oh Remou. Yes, I saw your post. I used your post. I've used many of your posts while working on this project. Why access doesn't support all SQL functions I am so used to with MySQL I have no idea. You're a great addition to this site. I should have linked to it with my question but the coffee hadn't kicked in yet.
I have my concatenation function and I am calling it within the sql. I was opening it with the docmd to open that recorset or query or whatever. But here is my issue (and I may be creating this myself by trying too many solutions at once or I might be overlooking something)... it keeps calling that function each time I touch the resulting dataset/query/thing and there's too much data for that to be happening; I am seeing the hourglass simply too much. I am positive this is because of the way I am opening it. This is intended to be the result of a search form screen thing. I'm thinking I need to just literally make another form in access and populate it with my resulting recordset. I think that is what you guys are telling me. I'm not sure. This is a weird example. But... you know with Excel, when you write an inline function of some kind to get some value for each row... and then you do a copy and paste special for just values (so not the function)... I need that. Because this function (not in Excel, obviously) must query and that takes to long to reapply each time a row is clicked on (I think it's actually requerying each row if a single row is clicked on, almost like it's rerunning the sql or something). Like the NIN/Depeche Mode song Dead Souls... It keeps calling me/it.
Here are a few thoughts and strategies for coping with the issue of constant data re-loading:
Make sure your query is set to snapshot. Same for the form.
This of course makes the data read-only, but it may help a bit.
Cache the result of your query into a local table, then show/bind that table instead of the query itself.
This will make the user wait a bit longer initially while the query is executed and saved into the local table, but it makes the interface much smoother afterwards since all data is local and doesn't need to be re-calculated.
Create a local table localPetResult (on the client side) that has all the fields matching those of the query.
Instead of binding the query itself to the datasheet form, bind the localPetResult to it, then in the form's VBA module handle the OnLoad event:
Private Sub Form_Load()
' Remove all previous data from the local cache table '
CurrentDb().Execute "DELETE FROM localPetResult"
' Define the original query '
Dim q as String
q = q & "SELECT Row, "
q = q & " Person, "
q = q & " Coalesce(""SELECT PetName FROM Pets WHERE Person='"" & [Person] & ""',"","") AS PetNames "
q = q & "FROM MyData"
' Wrap the query to insert its results into the local table '
q = "INSERT INTO localPetResult " & q
' Execute the query to cache the data '
CurrentDb().Execute q
End Sub
One you have it working, you can improve on this in many ways to make it nicer (freeze the screen and display the hourglass, dynamically bind the ersult table to the form after the data has been calculated, etc)
Cache the result of each call to the coalescing function.
I've used that to calculate the concatenation once for each record, then store the result in a Dictionary whose key is the ID of the record. Subsequent calculations for the same ID are just pulled from the Dictionary instead of re-calculated.
For instance, add the following to a VBA module. I'll assume that you use Remou's Coalesce function as well.
Option Compare Database
Option Explicit
' A Scripting.Dictionary object we'll use for caching '
Private dicCache As Object
' Call to initialise/reset the cache before/after using it '
Public Sub ResetCoalesceCache()
If Not (dicCache Is Nothing) Then
dicCache.RemoveAll
End If
End Sub
' Does the Same as Coalesce() from Remou, but attempts to '
' cache the result for faster retrieval later '
Public Function Coalesce2(key As Variant, _
sql As String, _
sep As String, _
ParamArray NameList() As Variant) As Variant
' Create the cache if it hasn't been initialised before '
If dicCache Is Nothing Then
Set dicCache = CreateObject("Scripting.Dictionary")
End If
If IsNull(key) Then
' The key is invalid, just run the normal coalesce '
Coalesce2 = Coalesce(sql, sep, NameList)
ElseIf dicCache.Exists(key) Then
' Hurray, the key exists in the cache! '
Coalesce2 = dicCache(key)
Else
' We need to calculate and then cache the data '
Coalesce2 = Coalesce(sql, sep, NameList)
dicCache.Add(key, Coalesce2)
End If
End Function
Then, to use it in your query:
' first clear the cache to make sure it doesn't contain old '
' data that could be returned by mistake '
ResetCoalesceCache
' Define the original query '
Dim q as String
q = q & "SELECT Row, "
q = q & " Person, "
q = q & " Coalesce2([Row], ""SELECT PetName FROM Pets WHERE Person='"" & [Person] & ""',"","") AS PetNames "
q = q & "FROM MyData"
' Bind to your form or whatever '
...
I always do it like this:
Dim strSql As String
strSql = "SELECT * FROM table WHERE field=something;"
Set rs = CurrentDb.OpenRecordSet(strSql)
Then use RS to perform actions. There may be better ways. You can, for example, create a query directly in Access and call it from VBA.
While looping the recordset, you can concatenate the string:
Dim strResult As String
While (Not rs.EOF)
strResult = strResult & rs!yourfield
WEnd