I'm trying to assign a list of Names to a combobox control in Access VBA.
My problem is that the output string of names is not correct.
Here is my code:
Private Sub command186_click()
Dim firstName As String
Dim lastName As String
Dim rst As Object
Dim rowSourceText As String
Dim fullName As String
Set rst = CurrentDb.OpenRecordset("Pool_Contact")
Do While Not rst.EOF
firstName = rst("FName").Value
lastName = rst("LName").Value
fullName = firstName + " " + lastName
rst.MoveNext
Loop
Forms(FrmDaysAvailable).Controls("Combo202").rowSource = fullName
Debug.Print fullName
End Sub
I know that the error is somewhere inside of my loop, where the variable fullName is written over by the second result.
how can I fix this loop to produce a string that looks like fullName , fullName, fullName ...
Thanks for all your help
This can be a lot simpler:
Forms(FrmDaysAvailable).Controls("Combo202").rowSource = _
"SELECT ID, FName & ' ' & LName FROM Pool_Contact"
Or
Forms!FrmDaysAvailable.Combo202.rowSource = _
"SELECT ID, FName & ' ' & LName FROM Pool_Contact"
Or
Me.Combo202.rowSource = "SELECT ID, FName & ' ' & LName FROM Pool_Contact"
Furthermore, use & not + to concatenate. Plus (+) will give you problems with nulls.
You must add each item to the ComboBox, instead you are only adding the last one
Do While Not rst.EOF
firstName = rst("FName").Value
lastName = rst("LName").Value
fullName = firstName & " " & lastName
Me!Combo202.AddItem(fullName)
rst.MoveNext
Loop
Also you should declare rst as DAO.Recordset not as object. (You might have to add a reference to the DAO dll).
Optionally you can assign a table or a query directly to the row source of the ComboBox and drop the loop completely
Me!Combo202.RowSource = "Pool_Contact"
But you can do that in the form designer and do not need to do it in VBA at all. If you need to refresh the contents of the ComboBox you can simply write
Me!Combo202.Requery
Note: I assume that Forms(FrmDaysAvailable) is the current form. In that case you can simply address it through Me. Further, the Controls collection is the default property of a form. Forms(FrmDaysAvailable).Controls("Combo202") can be simplyfied to Me("Combo202") or even to Me!Combo202 with the VBA collection access operator !.
I also suggest you to give your ComboBox (and other controls) meaningful names like cboFullName. This makes the code more readable. I usually make a query corresponding to the ComboBox with the same name prefixed with "q": qcboFullName and assign this to the RowSource of the combo in the properties window. A query has the advantage over a table that you can apply a "ORDER BY" and select exactly the columns needed for the ComboBox.
Typically you would have a hidden ID column (enter 0 in the column width property) as result of the user selection and a string column for display.
SELECT PersonID, firstName & ' ' & lastName AS Display
FROM tblPerson
ORDER BY firstName, lastName
Related
I'm having trouble getting Access to search on a multi-valued filed for a report. The multi-valued field is Group_List, and when trying to search a value in the multi-valued field and I keep getting the error that says cannot search in a where or having a clause. In the report, if I search for a value in the field I would only like those values to show up in the report.
Private Sub Command284_Click()
Dim reportsearch As String
Dim reportText As String
Dim strReport As String
If IsNull(Me.txtReport.Value) Then
strReport = "'SELECT * FROM NCECBVI'"
DoCmd.OpenReport "NCECBVI-Report", acPreview, , strReport
txtReport.Value = ""
Else
reportText = Me.txtReport.Value
reportsearch = "[Last Name] LIKE ""*" & reportText & "*"" OR [First Name] LIKE ""*" & reportText & "*"" OR Group_List LIKE "" * " & reportText & " * """
DoCmd.OpenReport "NCECBVI-Report", acPreview, , reportsearch
txtReport.Value = ""
End If
End Sub
Although I highly recommend to not use this kind of "dynamic query", there is a way to handle that kind of criteria for mutivalued fields.
Supposed that your Group_List is filled from a Groups table that as a GroupID and a GroupName column, you need to join your Groups table to the NCECBVI table (Connecting GroupID and Group_List.Value) and apply the criteria to the GroupName field. To show every record of the NCECBVI table only once, use DISTINCTROW. The assembled query would look something like this:
SELECT DISTINCTROW NCECBVI.*
FROM NCECBVI
INNER JOIN Groups ON Groups.GroupID = NCECBVI.Group_List.Value
WHERE Groups.GroupName LIKE "*SomeText*"
To deal with queries on multi-valued fields, I recommend this article.
Access table Allowances_3_15_18 has 5 columns. I want to insert a calculated field from a form EmployeeSalary) into one of the columns Amount in the table.
Each value will link with the relevant primary ID's from the form and the table which are the same JobID. How do I do this in VBA?
I currently have done it in the afterUpdate event in the property sheet.
Private Sub ProjectedDollarAmount_AfterUpdate()
Dim strSQL As String
Dim ProjectedDollarAmount As Currency
strSQL = "INSERT INTO [Allowances_3_15_18] ([Amount]) VALUES (" & _
PrepareSQLNumber(Me.ProjectedDollarAmount) & ") WHERE JobID = " & _
PrepareSQLNumber(Me.JobID) & ";"
Call ExecuteMyCommand(strSQL)
End Sub
You need to get away from SQL concatenation and start using parameters.
Create a query with two parameters, the amount to be inserted and the JobId. The query's SQL should be something like this:
PARAMETERS [prmAmount] Currency, [prmJobId] Long;
UPDATE [Allowances_3_15_18] SET [Amount] = [prmAmount]
WHERE JobID = [prmJobId];
Then in code, simply pass the parameter values and execute the above query:
Sub Add()
With CurrentDb().QueryDefs("qryName")
.Parameters("[prmAmount]").Value = PrepareSQLNumber(Me.ProjectedDollarAmount)
.Parameters("[prmJobId]").Value = PrepareSQLNumber(Me.JobID)
.Execute dbFailOnError
End With
End Sub
You need to change the qryName to the actual name of the query.
You can read more about parameter queries here.
I have a large database that monitors employees attendance at training events. Each record is an employee, and there are (along with basic information) a hundred or so fields that represent training events over the last 10 years. These fields are all yes/no checkboxes and so are checked if the employee attended that workshop.
I have a form that allows viewing information for individual employees easily, but I want a dynamic list on this form that shows what events the currently selected employee attended.
So I want a list to see which fields are designated as true for the specified record.
Is there any way to do this? Been searching all day and can't find a solution. Thanks.
Maybe somthing like this, assuming that all boolean fields are relevant and field name is workshop name:
Public Function getWorkshops(ByVal strEmployee As String) as String
' Declare vars
Dim db as DAO.Database
Dim rs as DAO.Recordset
Dim lngFieldsCount as Long
Dim n as Long
Dim strWorkshops as string
Set db = CurrentDb() '
lngFieldsCount = db.TableDefs("myTable").Fields.Count ' Count number of fields to iterate through
Set rs = db.OpenRecordset("SELECT * FROM myTable WHERE employeeName LIKE '" & strEmployee & "';",DbOpenSnapshot)
Do While not rs.Eof
For n = 0 to lngFieldsCount -1 ' iterate through all fields
If TypeOf rs.Fields(n) is dbBoolean Then ' check if field is boolean
If rs.Fields(n) Then ' check if boolean is true
strWorkshops = strWorkshops & rs.Fields(n).Name & vbCrLf ' add field names to string, separated by linebreaks
End If
End If
Next n
rs.MoveNext
Loop
getWorkshops = strWorkshops 'Set result of function
'Clean up
rs.Close
Set rs = Nothing
Set db = Nothing
End Function
This returns the name of all true fields in a string, separated with linebreaks (not tested).
VBA noob here (as of this mourning),
In MS Access I wrote a test function to find the value of a record base on some criteria you pass in.
The function seems to work fine except in cases where there is a lookup in the column that I am searching.
Basically it might return "19" and 19 corresponds to some other table value.
It seems that the RowSource of the column is what Im after so I can do a second query to find the true value.
Can someone point me in the right direction on finding the RowSource assuming I know the column name and then utilizing it to find the value Im after?
Edit: It seems that Im not explaining myself clearly, Here is a picture of what I trying to get programatically
Try this -- I think I finally understand why you are looking for the RowSource -- sorry I didn't "get" it at first. The field you're trying to pull is a foreign key into a description table.
This function should work as a general solution for all such fields (assuming the RowSource always has the primary key first, and the description second). If there is no RowSource, it will just pull the value of the field.
It's based on your original code, rather than the changes proposed by #ron, but it should set you in the right direction. You should fix it to make it parameterized, and allow for variant data types, as ron suggests (+1 ron)
As an aside, use the ampersand (&) to join strings together in VBA to avoid things like this: abc = "1" + 1, where abc is now equal to 2 instead of "11" as you would expect if both items were intended to be strings.
Public Function lookUpColumnValue(Database As Database, column As String, table As String, lookUpColumn As String, lookUpValue As String) As String
Dim sql As String
Dim recordSet As DAO.recordSet
Dim result As String
lookUpColumnValue = "" 'Return a blank string if no result
On Error Resume Next
sql = "SELECT [" & table & "].[" & column & "] FROM [" & table & "] WHERE [" & table & "].[" & lookUpColumn & "] = '" & lookUpValue & "'"
Set recordSet = Database.OpenRecordset(sql)
If Not recordSet.EOF Then
Dim td As DAO.TableDef
'this gives your number - say, 19
result = recordSet(column)
Set td = Database.TableDefs(table)
'Get the rowsource
Dim p As DAO.Property
For Each p In td.Fields(column).Properties
If p.Name = "RowSource" Then
RowSource = Replace(td.Fields(column).Properties("RowSource"), ";", "")
Exit For
End If
Next
If Not RowSource = "" Then
Dim rs2 As DAO.recordSet
Dim qd As DAO.QueryDef
Set qd = Database.CreateQueryDef("", RowSource)
Set rs2 = Database.OpenRecordset(RowSource)
If rs2.EOF Then Exit Function
PKField = rs2.Fields(0).Name
rs2.Close
qd.Close
sql = "SELECT * FROM (" & RowSource & ") WHERE [" & PKField & "]=[KeyField?]"
Set qd = Database.CreateQueryDef("", sql)
qd.Parameters("KeyField?").Value = result
Set rs2 = qd.OpenRecordset()
If Not rs2.EOF Then
'NOTE: This assumes your RowSource *always* has ID first, description 2nd. This should usually be the case.
lookUpColumnValue = rs2.Fields(1)
End If
Else
'Return the field value if there is no RowSource
lookUpColumnValue = recordSet.Fields(column)
End If
End If
End Function
If I understand your question correctly, I think using a parameter query will solve your problem. Using parameters is good practice since they will perform implicit data type casts and also prevent injection attacks.
Notice in the following function, I changed the lookupValue to a Variant type, which allows you to pass any type of value to the function.
Public Function lookUpColumnValue( _
database As DAO.database, _
column As String, _
table As String, _
lookUpColumn As String, _
lookUpValue As Variant) As String
Dim sql As String
Dim recordSet As DAO.recordSet
Dim result As String
Dim qd As QueryDef
Set qd = database.CreateQueryDef("")
sql = "SELECT [" + table + "].[" + column + "] FROM [" + table + "] " & _
"WHERE [" + table + "].[" + lookUpColumn + "] = [parm1];"
qd.sql = sql
qd.Parameters![parm1] = lookUpValue
Set recordSet = qd.OpenRecordset()
result = recordSet(column)
EDIT
lookUpColumnValue = DLookup("Space Use Description", "Space Use Codes", result)
End Function
I have a report in my Access database containing multiple fields, e.g., it looks like as follows:
Name John
Number 18
Place somewhere
Name John
Number 19
Place somewhere
Name John
Number 20
Place somewhere
Name Bogo
Number 30
Place somewhere
John can have multiple Numbers. As you can see, "John" is listed multiple times, each with a different Number. I would like to get just one detail row with the name "John", something like the following:
Name John
Number 18; 19; 20
Place somewhere
Name Bogo
Number 30
Place somewhere
How can I achieve this?
The solution is to use VBA code in an Access Module to "string together" the repeated values ("Number" in your case). The general form of the code is:
Option Compare Database
Option Explicit
Public Function ListChildNames(ParentID As Long) As String
Dim cdb As DAO.Database, rst As DAO.Recordset, rtn As String
Const separator = "; "
Set cdb = CurrentDb
Set rst = cdb.OpenRecordset( _
"SELECT [ChildName] FROM [ChildTable] " & _
"WHERE ID=" & ParentID, _
dbOpenSnapshot)
rtn = ""
Do While Not rst.EOF
rtn = rtn & rst![ChildName] & separator
rst.MoveNext
Loop
rst.Close
Set rst = Nothing
Set cdb = Nothing
If Len(rtn) > 0 Then
rtn = Left(rtn, Len(rtn) - Len(separator)) '' trim trailing separator
End If
ListChildNames = rtn
End Function
(You will have to tweak the table and column names to match your table structures.)
Then, in the Record Source for your report, instead of using...
SELECT [Name], [Number] ... FROM ...
...you would use something like...
SELECT [Name], ListChildNames([Name]) AS Numbers ... FROM ...
...to retrieve the [Name] and the (concatenated list of) [Number] values in a single row.