I have this requirement where I have to check the data based on data given in other fields. I have table with 'N' fields. I should allow user to select 4 fields which are from the table. And then I should get all other fields of that particular record and display it to the user so that he can verify that the data he entered into table is correct. Please help.
Thanks
I have a clearer understanding now of what you require - hopefully this is what you need:
Assume you have a table called 'Phones'
The phones table has three primary fields: Manufacturer, Operating System, and Carrier
In addition to these primary fields there are secondary "spec" fields. For now we have three: ScreenSize, Frequencies, and Price.
I create a form with three combo boxes: ManufacturerFilter, OperatingSystemFilter, and CarrierFilter.
Each combo box's row source is similar to:
SELECT Carrier FROM Phones GROUP BY Carrier ORDER BY Carrier;
Where Carrier is replaced by Manufacturer and [Operating System] respectively.
I then add in all of the secondary fields, each bound to their own respective field.
You can also add in a button called "Retrieve" for now leave the click code blank.
At this point you have a few options. I'll highlight two, but both options will require the following procedure:
Private Function FilterStr() As String
Dim myFilterStr As String
' Include each filter if they are entered
If Nz(Me.ManufacturerFilter, "") <> "" Then myFilterStr = myFilterStr & "[Manufacturer]='" & Me.ManufacturerFilter.Value & "' AND"
If Nz(Me.OperatingSystemFilter, "") <> "" Then myFilterStr = myFilterStr & "[Operating System]='" & Me.OperatingSystemFilter.Value & "' AND"
If Nz(Me.CarrierFilter, "") <> "" Then myFilterStr = myFilterStr & "[Carrier]='" & Me.CarrierFilter.Value & "' AND"
' Remove the last AND statement
If myFilterStr <> "" Then myFilterStr = Mid(myFilterStr, 1, Len(myFilterStr) - 4)
FilterStr = myFilterStr
End Function
This function returns a filter string, based on the combo box options selected.
Option #1: Filter the Recordset
What we want to occur, is when a primary field value is selected, the records are filtered to display only those matching the criteria. Add the following code to the OnClick event of your Retrieve button:
Private Sub RetreiveButton_Click()
Dim myFilterStr As String
myFilterStr = FilterStr
If myFilterStr <> "" Then
Me.Filter = myFilterStr
Me.FilterOn = True
Else
Me.Filter = ""
Me.FilterOn = False
End If
End Sub
So what happens when the button is clicked, is that a filter string is created based on the values selected, and then a filter is applied to the form. If no values are selected in the combo boxes, the filter is cleared and turned off.
Option #2: Find a Record based on the Value
What we want is to select the values in the comboboxes, and then move to the record that matches the criteria.
Add the following code to the onClick event of the retrieve button.
Private Sub RetreiveButton_Click()
Dim rst As DAO.Recordset
Dim myFilterStr As String
myFilterStr = FilterStr()
If myFilterStr = "" Then
MsgBox "No Filter Selected", vbOKOnly, "Error"
Exit Sub
End If
Set rst = Me.RecordsetClone
rst.FindFirst myFilterStr
If rst.NoMatch Then
MsgBox "No Matching Records were found", vbOKOnly, "No Data"
Else
Me.Bookmark = rst.Bookmark
End If
Set rst = Nothing
End Sub
This uses the the same FilterStr() function to return a search string, but uses the recordset's FindFirst method to locate a record. If found, it will move to the record.
Hope that answers your question. As I indicated, the exact behaviour will vary but the underlying principle remains the same.
Related
I have a (poorly designed) db that contains a table of Volunteers. Within this table are 70+ Yes/No fields. Each field represents a County that each Volunteer could elect to serve. Each Volunteer could select multiple Counties.
I have a report that must allow selection of multiple Counties. That list must then be compared to the Boolean fields selection by selection, retaining records with only True values.
If you check some of my recent questions, I've had similar problems, but the difference was displaying boolean selections as text on the report. Only just now discovered selection criteria code isn't doing what I thought ... Here's what's been done so far:
Dim s As Variant
Dim ctl As Control
Dim t As TCondition 'this is to compile multiple variables into one large "where" clause to run the report. 3 such variables are coded in this function.
Set ctl = Me.Counties
If ctl.ItemsSelected.Count <> 0 Then
If t.WhereCondition = "" Then
For Each s In ctl.ItemsSelected
t.WhereCondition = (ctl.ItemData(s) & " = -1")
Next s
Else
For Each s In ctl.ItemsSelected
t.WhereCondition = t.WhereCondition & " AND (ctl.ItemData(s) = -1)"
Next s
End If
End If
Where this broke on me was if someone selected more than one County. I realized they were only getting the last County selected.
For Example - Counties: red, blue, silver, and green would only return Green.
A similar issue had come up with Volunteer Positions. I needed to account for selecting multiple
So I found the following:
Public Function listBoxToString(ByRef theListBox As ListBox, Optional ByVal theDelimiter As String = vbNullString)
Dim varTemp As Variant
listBoxToString = vbNullString
For Each varTemp In theListBox.ItemsSelected
If listBoxToString <> vbNullString Then listBoxToString = listBoxToString & ","
listBoxToString = listBoxToString & theDelimiter & theListBox.ItemData(varTemp) & theDelimiter
Next varTemp
End Function
This takes all selections of a ListBox and makes a comma separated list of them. This WORKED for the Positions fields (there are multiple) because those field values are TEXT.
I tried to apply that to Counties as follows:
Dim s As String
Dim ctl As Control
Dim t As TCondition
Set ctl = Me.Counties
If ctl.ItemsSelected.Count <> 0 Then
s = listBoxToString(Me.Counties, Chr(34))
If t.WhereCondition = "" Then
t.WhereCondition = (ctl.ItemData(s) & " = -1")
Else
t.WhereCondition = t.WhereCondition & " AND (ctl.ItemData(s) = -1)"
End If
End If
It does NOT work for Counties, because ListBox returns TEXT that must then be compared to values in County that are BOOLEAN. So, logically, I get Data Type Mismatch error.
I have a separate piece of code, used to help display the Counties list on the report. It pulls records at runtime, takes the ID of the record, zeroes in on the Indexes of the Boolean fields, and converts them to the Name of the fields:
Public Function MakeListCounties(intID As Integer) As String
Dim rs As DAO.Recordset
Dim strList As String
Dim x As Integer
Set rs = CurrentDb.OpenRecordset("SELECT * FROM Volunteer WHERE ID=" & intID)
For x = 44 To 105
If rs(x).Type = dbBoolean Then
If rs(x) = True Then strList = strList & rs(x).Name & ", "
End If
Next
If strList <> "" Then MakeListCounties = Left(strList, (Len(strList) - 2))
rs.Close
Set rs = Nothing
End Function
Is there a way to work with this to get what I want? This may be superfluous, and, if so, apologies, and completely ignore that part.
To recap - I need to iterate through a ListBox of values, compare them with values of 70+ Boolean fields, retaining only records where Boolean = True for field names matching value(s) in the ListBox
Build function in a general module that returns a True or False. Call from query with expression like: MC: MatchCounties([ID]) with filter criteria of =True.
Assuming the combobox lists county names exactly matching the yes/no field names, consider:
Function MatchCounties(intID As Integer) As Boolean
Dim rs As DAO.Recordset
Dim varItem As Variant
With Forms!formname.Counties
If .ItemsSelected.Count <> 0 Then
Set rs = CurrentDb.OpenRecordset("SELECT * FROM Volunteer WHERE ID=" & intID)
For Each varItem In .ItemsSelected
If rs(.ItemData(varItem)) Then 'use the listbox value as field name and test for True
MatchCounties = True
Exit For 'only need to match 1 yes/no county field to retrieve record
End If
Next
rs.Close
Set rs = Nothing
End If
End With
End Function
If no items selected in listbox, no records will return because the function will return False. If you want to allow no selection and still return records, then likely want the function to return True if .ItemsSelected.Count = 0. Adjust code with an Else.
Change your first code snippet to the following. The reason you were always getting the last county is because your loop was overwriting the previous WHERE clause values.
Dim s As Variant
Dim ctl As Control
Dim t As TCondition
Set ctl = Me.Counties
If ctl.ItemsSelected.Count <> 0 Then
For Each s In ctl.ItemsSelected
t.WhereCondition = t.whereCondition & ctl.ItemData(s) & " = -1 OR"
Next s
' trim trailing " OR"
t.WhereCondition = Left(t.WhereCondition, Len(t.WhereCondition)-3)
End If
I have returned with yet another Question regarding MS Access and its VBA environment.
I'm currently constructing a database in MS Access 2016.
The main View headview has a combobox viewcombo and a subform listview.
What I need: I want the combobox to filter the listview depending on the chosen entry of it.
What I did:
Private Sub ViewCombo_AfterUpdate()
On Error GoTo Proc_Error
If IsNull(Me.ViewCombo) Then
Me.ListView.Form.Filter = ""
Me.ListView.Form.FilterOn = False
Else
Dim selectedOption As AccessObject
selectedOption = Me.ViewCombo
Select Case selectedOption
Case selectedOption = "open"
Me.ListView.Form.Filter = "Column1='" & "'"
End Select
End If
Proc_Exit:
Exit Sub
Proc_Error:
MsgBox "Error " & Err.Number & " Setting Filter:" & vbCrLf & Err.Description
Resume Proc_Exit
End Sub
Note: The Me.ListView.form.Filter = "Column1='" & "'" is supposed to be empty if the chosen entry of viewCombo is open, the available entries are Open, Closed, ovedue, cancel and "as seleced
However, it seems that Access doesnt work this way. How do I properly write the select case statements?
Edit 1:
The Values of the ComboBox ViewCombo are manualy written in it. Depending on the selection of a value, different Filters are to be set on the ListView
Example:
The selected value is open
The Listview is filtered with the statement: Column1 is empty
The selected value is closed
The Listview is filtered with the statement Column 1 is not empty, Column 2 contains the value 10 (10 is an ID for a status, these are given to me by the employees I work with, those are internal and have no meaning for the database)
Hope that helps to clarify the situation.
You will use the value of the combobox, not the combobox as an object, similar to:
If IsNull(Me.ViewCombo.Value) Then
Me.ListView.Form.Filter = ""
Me.ListView.Form.FilterOn = False
Else
Select Case Me.ViewCombo.Value
Case Is "open"
Me.ListView.Form.Filter = "[SomeFieldName] = 'open'" ' or other filter value.
End Select
Me.ListView.Form.FilterOn = True
End If
I solved it with the Input you guys gave me:
Private Sub AuswahlFilter_AfterUpdate()
On Error GoTo Proc_Error
If Me.ViewCombo.Value = "All" Then
Me.ListView.Form.Filter = ""
Me.ListView.Form.FilterOn = False
Else
Select Case Me.ViewCombo.Value
Case Is = "Open"
Me.ListView.Form.Filter = "FlagOpenClosed='1'"
Me.ListView.Form.FilterOn = True
End Select
End If
Proc_Exit:
Exit Sub
Proc_Error:
MsgBox "Error " & Err.Number & " when creating Filter:" & vbCrLf & Err.Description
Resume Proc_Exit
End Sub
I created some additional Columns on the ListView. The Table listviewis based on now has additional columns filled with values from statements like When(IsNull(Column1);1;0). Then I set the filter for those values.
I guess there is a better way to do it, however, I am a noob in VBA, so that is the best solution I came up with. If there is a better way to do it, please dont hesitate to write it as an answer here, I am glad to learn new things, and love to hear from you guys.
-Ninsa
I have a combobox that builds it's list upon first usage. I know that the way I want "NotInList" to behave isn't conventional - I don't want to waste adding the item to a table separate from the needed entry, but I'd like to still warn about an item that hasn't been used yet, so that the user has to think twice before accepting the entry.
Once the user adds the item, it will automatically appear in the list next time because the data source for the combo box is as follows:
SELECT tbl_SP.PROGRAM
FROM tbl_SP
GROUP BY tbl_SP.PROGRAM
HAVING (((tbl_SP.PROGRAM) Is Not Null And (tbl_SP.PROGRAM)<>""));
I tried this:
Private Sub cmbPROGRAM_NotInList(NewData As String, Response As Integer)
If MsgBox("'" & Chr(34) & NewData & Chr(34) & " hasn't been used yet. Add to list? ", vbQuestion + vbYesNo, "Add - " & NewData & "?") = vbYes Then
Response = acDataErrAdded
End If
End Sub
but of course, Access wants the item to actually exist before it will release the error. And...if I set LimitToList to "No" then the user doesn't get a warning.
How can I achieve this behavior?
Ok, I tried this which works fine if the user selects YES, but becomes more complicated when the user selects "NO"
Public Function ReturnsRecords(strSQL As String) As Boolean
Dim d As DAO.Database
Dim arr(1 To 3) As DAO.Recordset
'Dim rs As DAO.Recordset
'assume 3 items in array above
Set d = CurrentDb
Set arr(1) = d.OpenRecordset(strSQL)
' MsgBox "Record Count is " & arr(1).RecordCount
If arr(1).RecordCount > 0 Then
ReturnsRecords = True
Else
ReturnsRecords = False
End If
Set d = Nothing
End Function
Private Sub cmbPROGRAM_BeforeUpdate(Cancel As Integer)
Dim strSQL As String
strSQL = "Select * from LU_PROGRAM where PROGRAM ='" & Me.cmbPROGRAM & "'"
If ReturnsRecords(strSQL) = False Then
If MsgBox("'" & Chr(34) & Me.cmbPROGRAM & Chr(34) & " hasn't been used yet. Add to list? ", vbQuestion + vbYesNo, "Add - " & Me.cmbPROGRAM & "?") = vbNo Then
Cancel = True
' how do I reset this? Me.cmbPROGRAM.Text = Null
End If
End If
End Sub
How do I clear the combobox if the user selects NO? If I select me.undo, that will undo all of the entries, but I just want to clear the combobox.
Incidentally, the form is totally unbound and doesn't accept an entry until the user selects "Save"
First, I'm not quite sure what you wish to achieve ...
Then, educate the users to press Escape to cancel. This is mandatory wisdom when operating an Access application.
For your code to work, you can't change the content of a control in the BeforeUpdate event. So try the AfterUpdate event with either:
Me!cmbPROGRAM.Text = ""
or:
Me!cmbPROGRAM.Value = Null
I have a database with 2 primary keys, one for a LINE NUMBER and one for PHASE of construction. The reason for this is that we have projects that may use the same Line Number but must track several Phases of the project entirely seperatly. What I have is a combo box that will drive the record information on a form. This works fine, but now when I have more than one phase it will only bring up the line's first phase and not the other 4 phases. When something other than phas one is picked it results the first phase information.
Is there a way to tie a combo box with 2 fields to select the proper record based on both fields picked?
Or maybe I need to rething the way the form is brought up... Is there a better way to do this?
Code used to select the record:
Sub SetFilter()
Dim LSQL As String
LSQL = "select * from tblLineData_Horizon"
LSQL = LSQL & " where lineno = '" & cboSelected & "'"
Form_frmHorizon_sub.RecordSource = LSQL
End Sub
Private Sub cboSelected_AfterUpdate()
'Call subroutine to set filter based on selected Line Number
SetFilter
End Sub
Private Sub Form_Open(Cancel As Integer)
'Call subroutine to set filter based on selected Line Number
SetFilter
End Sub
A basic idea, but you'll most likely want to tweak the behaviour a bit and have some more checks. When the form loads, you only have the ability to select LineNo. When cbxLineNo has a value in it, it enables cbxPhaseNo for selection and upon selection, it changes the RecordSource of your subform.
Private Sub cbxLineNo_AfterUpdate()
If IsNull(cbxLineNo) Then
cbxPhaseNo.Enabled = False
Else
cbxPhaseNo.Enabled = True
cbxPhaseNo.RowSource = "SELECT PhaseNo FROM tblLineData_Horizon WHERE LineNo = " & cbxLineNo & ";"
End If
End Sub
Private Sub cbxPhaseNo_AfterUpdate()
If IsNull(cbxPhaseNo) = False And IsNull(cbxLineNo) = False Then
tblLineData_Horizon_sub.Form.RecordSource = "SELECT * FROM tblLineData_Horizon WHERE LineNo = " & cbxLineNo & " AND PhaseNo = " & cbxPhaseNo & ";"
End If
End Sub
Private Sub Form_Load()
cbxLineNo.Enabled = True
cbxPhaseNo.Enabled = False
cbxLineNo.RowSource = "SELECT LineNo FROM tblLineData_Horizon GROUP BY LineNo;"
End Sub
You question is a little unclear, but you can create a combobox with more than one column, then your select statement would be:
where lineno = '" & cboSelected.Column(0) & "' And otherfield='"& cboSelected.Column(1)&"'"
Go to the query behind your combobox by clicking into its RowSource property and clicking the Build button (...). Once you've added the columns you need, bring up the Properties for the query and set Unique Values to Yes, so that it doesn't repeat the combinations of the fields.
You will also need to change other properties of the combobox: 'Column Count' and 'Column Widths'.
I have an access database with a search form.
I have an "Object" table with amongst other things, a "name" field, and an "owner" table with a "name" field as well.
Between the two, I have a join table so I have a many-to-many relationship
An object does not necessarily have an owner.
In my search form, I have two unbound fields: "object name" and "owner name".
What I want to do:
When the user leaves both fields blank, he gets a list of all the objects (including those with no owner), and if that object has an owner it is also displayed in the list.
When the user fills something in the "object name" field, he gets a list of all the objects containing the entered substring (including those with no owner).
When the user fills something in the "owner name" field, he gets a list of all the objects where the owner name contains the entered substring (ignoring NULL owners).
What I did thus far:
I made a query with a left outer join, and a criteria on Object.name using the value of the "object name" textfield
That works fine for use case 1 and 2, but there's no owner filtering in case 3
However if I add a criteria on Owner.name based on the "owner name" textfield, case 3 works fine, but case 1 and 2 don't work anymore (making the left outer join obsolete)
How could I solve this problem?
It seems to me that you could use a Continuous Forms form with the following Record Source...
SELECT Objects.ObjectName, ObjectOwners.OwnerName
FROM (ObjectOwnership INNER JOIN ObjectOwners ON ObjectOwnership.OwnerID = ObjectOwners.OwnerID) INNER JOIN Objects ON Objects.ObjectID = ObjectOwnership.ObjectID
UNION ALL
SELECT Objects.ObjectName, NULL AS OwnerName
FROM ObjectOwnership RIGHT JOIN Objects ON Objects.ObjectID = ObjectOwnership.ObjectID
WHERE ObjectOwnership.ObjectID IS NULL
ORDER BY 1, 2;
...and then put a couple of text boxes and a "Filter" command button in the form header to update the forms .Filter property to filter the records as desired, like this:
Private Sub cmdFilter_Click()
Dim sFilter As String
If IsNull(Me.txtObjectFilter.Value) And IsNull(Me.txtOwnerFilter.Value) Then
Me.FilterOn = False
Else
If IsNull(Me.txtObjectFilter.Value) Then
sFilter = ""
Else
sFilter = "ObjectName LIKE ""*" & Me.txtObjectFilter.Value & "*"""
End If
If Not IsNull(Me.txtOwnerFilter.Value) Then
If Len(sFilter) > 0 Then
sFilter = sFilter & " AND "
End If
sFilter = sFilter & "Ownername LIKE ""*" & Me.txtOwnerFilter.Value & "*"""
End If
Me.Filter = sFilter
Me.FilterOn = True
End If
End Sub
When the form opens it shows all records...
...and then we can filter by object...
...or by owner...
...or both, for that matter.
Edit
A similar technique for Subforms would be to save the query above as [ObjectOwner_base_query] and specify that as the Record Source of the Subform, then change the VBA code very slightly, to
Private Sub cmdFilter_Click()
Dim sFilter As String, sSQL As String
sFilter = ""
If Not IsNull(Me.txtObjectFilter.Value) Then
sFilter = "ObjectName LIKE ""*" & Me.txtObjectFilter.Value & "*"""
End If
If Not IsNull(Me.txtOwnerFilter.Value) Then
If Len(sFilter) > 0 Then
sFilter = sFilter & " AND "
End If
sFilter = sFilter & "Ownername LIKE ""*" & Me.txtOwnerFilter.Value & "*"""
End If
sSQL = "SELECT * FROM ObjectOwner_base_query"
If Len(sFilter) > 0 Then
sSQL = sSQL & " WHERE " & sFilter
End If
Me.RecordSource = sSQL
End Sub
(It appears that modifying the .Filter property of a subform can cause Access to act strangely; updating the .RecordSource property seems to produce better results.)