I have a report, selecting from a table called "Volunteers". The entire WHERE clause is constructed in VBA at runtime, based on the following parameters selected on the form
Volunteer Type: One of 2 checkboxes
Region: 1 dropdown - but, in VBA, each region could be any number of offices
Position: 4 option multi-select
County: 70 option multi-select
My report has to compile all of these dynamic variables at runtime.
What I thought would be my last question - regarding Counties - actually doesn't work, and that's where I'm at now.
In the "Volunteer" table, each of the 70 Counties is its own Boolean field.
The ReportFrom represents Counties as Strings. In order to loop through up to 70 selections, in an OR statement, to evaluate String against True/False, the following solution was supplied:
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
This worked out GREAT except when compiling these selections with the other parameters of the WHERE clause. There were not enough parens around this selection, and it was not filtering records properly.
I attempted several solutions - the closest of which was this:
If ctl.ItemsSelected.Count <> 0 Then
For Each s In ctl.ItemsSelected
t.WhereCondition = t.WhereCondition & "((" & ctl.ItemData(s) & ") = -1) OR )"
Next s
t.WhereCondition = Left(t.WhereCondition, Len(t.WhereCondition) - 4)
End If
The problem is Trimming 4 characters removes the RParen that I need in order for this statement to properly filter the report. Trimming only 3 leaves a trailing "O".
I need to somehow remove just the trailing OR, keeping the trailing parenthesis.
Is there a way to do that?
(I hate posting afternoon (EST) questions, as I won't be able to follow up until tomorrow, but, I've been racking my brain on this all day)
The not-so-glorious but quick-and-dirty way to do this would be:
t.WhereCondition = Left(t.WhereCondition, Len(t.WhereCondition) - 4)
t.WhereCondition = t.WhereCondition & ")"
Or just:
t.WhereCondition = Left(t.WhereCondition, Len(t.WhereCondition) - 4) & ")"
A coworker managed to approach this a different way, and encapsulated the dynamic WHERE clause in a different section of code
t.WhereCondition = "(" & t.WhereCondition & ") AND
Encasing the current WHERE as it's built looks like it supplies the extra separation needed to properly filter records.
Related
Bear with me; I have very little MS Access experience, by plenty of SQL experience.
This is the basic data structure:
I have an Employee table, a Training table, and a joining Employee_Training table (many-to-many relationship). There is a list of employees, and a list of possible training that those employees can do. Any employee may have attended several training sessions, where each entry has a recorded attendance date.
I am trying to make a form that performs in the following way:
You select an employee from a combobox at the top of the page
The form contains a list of all possible training sessions, each with a label and a textbox. If the employee has attended a training session, the corresponding textbox has the attendance date in it, otherwise the text box is blank.
I want to be able to enter a date in a blank textbox, or change the date in a non-blank textbox.
I can't use a DataSheet view because there are about 150 training types, and this needs to be converted into a printable form, so the information is compressed in columns on the form, like below:
Rough Layout:
Select Employee: [ John Smith | v ]
Training type 1: [ ] Training type 25: [ ]
Training type 2: [ ] Training type 26: [ 05/06/15 ]
Training type 3: [ ] Training type 27: [ ]
... ...
The form was originally created by hand, but now is created by a VBA script, though I don't think that will be too relevant here.
How do I structure the form's record source and the control source of the text boxes to allow me to see what I want to see, and edit what I need to edit?
you have to drop out the databinded forms.
if you use Recordset objects, you yan use a query binded to comboboxes and
some small vba code to save your data to tables.
I think the printing in access more flexible if u use the reports instead of the forms :)
First, for printing out data, you will create a report. So drop the idea that because of repeating data you have some problem or issue here. You can format your report like an invoice or whatever. The idea that you have “many” choices effects this choice is simply a non-issue. You form/report likely not to include all 150 choices, and makes it hard to read. And if you really must, then you can include all 150 choices along with the “only” ones chosen showing a date.
Next up: Attempting to display 150 choices on the form is going to be REALLY hard – you run out of room fast on the form. And even your above mock-up shows a datasheet like repeating data display – if it goes on for 150 rows, you not likely to fit all that on a screen without using some kind of repeating data display anyway.
Think of ANY existing software you used – VERY rare to see 150 choices all at once – you have to “choose” from a list. Think of an invoice form in an accounting package – you can display all the choices – you have to scroll or “search” a bit to narrow down choices.
The most easy would be to have the main form based on the employee (so name, phone and all that jazz). The sub form would then display a combo box to select the training/course, and then a date box to enter the date. (The date could even automatic be defaulted to today, or the course start date or whatever).
The result is you point + shoot, point + shoot – much like a click, click click type of process.
Here is an example of an invoice form in Access. To make this animation I did not touch the keyboard – it was just mouse click, mouse click etc. However the combo box DOES allow partial matching and search to narrow down the list presented (again with your long list you don’t want to torture users!). So you can type in a “few” characters into the combo box to narrow down the list of choices.
I mean, either way you going to force the user to pick from 150 choices. However, having to “scroll” through 150 choices ALWAYS to JUST view the courses the person has taken is going to be torture to the user.
So display JUST the courses selected – that way when you bring up a student, you can EASY see what courses they have, and as this follow animation shows, it would be a snap to add additional courses.
As noted, the droop down list could “remove” existing choices, or display the date if any course has already been selected. Simple logic to prevent duplicates would be added to the combo box before update event.
There are a ton of possible solutions for this question. I'm gonna try to stay close to your rough layout. I imagine a database with 3 tables like this :
* table: Employee (EmpID, EmpName)* table: Training (TraID, TraName)* table: Employee_Training (EmpTraID, ET_EmpID, ET_TraID, ET_Date)
Create a continuous form based on a query like:
SELECT Training.TraID, Training.TraName, Employee_Training.EmpTraID, Employee_Training.ET_EmpID, Employee_Training.ET_Date
FROM Training LEFT JOIN Employee_Training ON Training.TraID = Employee_Training.ET_TraID;
In the header-section of the main form, place a combobox called "ChosenEmpoyee". As recordsource for this combobox
"SELECT EmpID, EmpName FROM Employee", so 2 columns, and the ColumnWidths set to "0;5" to hide the first column. The column with EmpID is needed to filter the records.
When selecting an employee from the combobox, the afterupdate event will change the recordsource of the form to a query like this example:
SELECT Training.TraID, Training.TraName, A.EmpTraID, A.ET_EmpID, A.ET_Date
FROM ( SELECT Employee_Training.EmpTraID, Employee_Training.ET_EmpID, Employee_Training.ET_TraID, Employee_Training.ET_DateFROM Employee_Training WHERE Employee_Training.ET_EmpID = 3 ) As ARIGHT JOIN Training ON Training.TraID = A.ET_TraID
The code to perform this :
Private Sub ChosenEmployee_AfterUpdate()
Dim SQL As String
SQL = "" & _
" SELECT Training.TraID, Training.TraName, A.EmpTraID, A.ET_EmpID, A.ET_Date " & _
" FROM (SELECT EmpTraID, ET_EmpID, ET_TraID, ET_Date " & _
" FROM Employee_Training WHERE ET_EmpID = " & ChosenEmployee & _
" ) As A " & _
" RIGHT JOIN Training ON Training.TraID = A.ET_TraID"
Me.RecordSource = SQL
Me.Requery
End Sub
A second part of the question; having a contineous form with 5 columns, presenting the information in 5 textboxes with the same name:
TraID / TraName / EmpTraID / ET_EmpID / ET_Date
The employee is chosen by selecting in the combobox in the header.
The training will be chosen by double clicking on the textbox in the
desired row. If there was already a date, the EmpTraID will
have a value greater then 0.
The code to perform this :
Private Sub AT_Date_DblClick(Cancel As Integer)
Dim S As String
Dim D As Date
Dim SQL As String
Dim EmpTraID As Long
S = "Please give the date of attendance."
S = InputBox(S)
If Not IsDate(S) Then
S = "I'm sorry, the entered value > is not recognised as a date."
MsgBox S, vbExclamation
'Cancel = True
Else
D = CDate(S)
S = "Are you sure to enter the following date of attendance ?" & vbCrLf & Format(D, "dddd, dd mmmm yyyy")
If MsgBox(S, vbYesNo + vbDefaultButton2 + vbQuestion) = vbYes Then
'
' the following 2 lines will result into troubles ...
' Ms Access is not able to alter values
' in a recordset based on a query with a JOIN-statement
'
'Me.AT_Date = CDate(S)
'Me.Refresh
'
' if there was already a date then
' change the date by using AttTraiID
' else
' insert a record in AttTrai_T
' end if
'
EmpTraID = Nz(Me.EmpTraID.Value, 0)
If EmpTraID <> 0 Then
SQL = ""
SQL = SQL & "UPDATE Employee_Training "
SQL = SQL & " SET ET_Date = "
SQL = SQL & " #" & Format(D, "mm/dd/yyyy") & "# " ' US-date-format needed when using '#' in a query in MsAccess
SQL = SQL & " WHERE EmpTraID = " & EmpTraID
Else
SQL = ""
SQL = SQL & "INSERT INTO Employee_Training "
SQL = SQL & " (ET_EmpID, AT_TraID, ET_Date) "
SQL = SQL & " VALUES "
SQL = SQL & " (" & ChosenEmployee
SQL = SQL & " ," & Nz(Me.TraID.Value, 0)
SQL = SQL & " , #" & Format(D, "mm/dd/yyyy") & "# " ' US-date-format needed when using '#' in a query in MsAccess
SQL = SQL & " )"
End If
CurrentDb.Execute SQL
DoEvents: DoEvents: DoEvents
Me.Requery
End If
End If
End Sub
Using Access 2007.
I have to compare several data entry fields with their corresponding tables fields. If the fields match, do not add a new record. If not, add a new record with the values.
AnimalInfo Table fields
WHno (Wildlife Health Number)
Species
LETClr1 (Left Ear Tag Color 1)
LETNo1 (Left Ear Tag Number 1)
LETClr2 (Left Ear Tag Color 2)
LETNo2 (Left Ear Tag Number 2)
RETClr1 (Right Ear Tag Color 1)
RETNo1 (Right Ear Tag Number 1)
RETClr2 (Right Ear Tag Color 2)
RETNo2 (Right Ear Tag Number 2)
Form F_HotelForm unbound fields
txtSpecies
txtLETClr1
txtLETNo1
txtLETClr2
txtLETNo2
txtRETClr1
txtRETNo1
txtRETClr2
txtRETNo2
I am trying to create a DCount to check and see if there are any matching records. The animal's uniqueness is determined by its species and ear tag information. It can have one ear tag number and color, or four. (Some of the older data has none but I can't do anything about that! In those cases, a new record, i.e. new Wildlife Health Number will be generated)
This is what I want to accomplish with this form:
If there are no matching fields (DCount = 0) add a new record and update fields from the form into table.
If there is 1 matching record, then the animal's wildlife health number is displayed (in a new form eventually)
If there are multiple records, then these are displayed in another form and the user needs to pick the correct animal.
LETClr1 and LETNo1 are paired.
LETClr2 and LETNo2 are paired.
RETClr1 and RETNo1 are paired.
RETClr2 and RETNo2 are paired.
Any and all of these fields could have values or not. Left ear tag numbers and colors could have been entered as either LETClr1 or LETClr2 so I have to compare both LETClr1 and LETClr2 with the txtLETClr1 data entry. (This holds true for all paired fields)
Below is a sample of the script so far. It is very rudimentary as I am very new to this and am just trying to see what works.
Private Sub GenerateWHno_Click()
Dim rs As DAO.Recordset
If IsNull(Forms!F_HotelEntry!txtSpecies) Or (Forms!F_HotelEntry!txtSpecies) = "" Then
MsgBox "Species is a required field. Please enter a species"
Exit Sub
End If
MsgBox txtSpecies
SpeciesCount = DCount("[Species]", "AnimalInfo", "[Species]= '" & txtSpecies & "'AND [L_ET_Color1]='" & txtL_ET_Color1 & "' AND [L_ET_No1]='" & txtL_ET_No1 & "'")
If SpeciesCount > 1 Then
MsgBox SpeciesCount & " Greater than 1"
ElseIf SpeciesCount = 0 Then
MsgBox "You need a new WHno"
WHno = Nz(DMax("WHno", "AnimalInfo")) + 1
MsgBox WHno
Set rs = CurrentDb.OpenRecordset("AnimalInfo")
rs.AddNew
rs!WHno = WHno
rs!Species = txtSpecies
rs!L_ET_Color1 = txtL_ET_Color1
rs!L_ET_No1 = txtL_ET_No1
rs!R_ET_Color2 = txtR_ET_Color2
rs.Update
rs.Close
Else
End If
Forms!F_HotelEntry!txtSpecies = ""
Forms!F_HotelEntry!txtL_ET_Color1 = ""
Forms!F_HotelEntry!txtL_ET_No1 = ""
End Sub
So the problem is that I cannot concatenate NULL fields. The DCount only works if there is Non Null data in the form/table.
Any ideas as to how I can work around this?
Many thanks.
My comments are getting garbled so I am putting below original posting.
I copied the suggested code into module and rewrote query a couple of different way but still got error message: Run-time error 424. Object required
SpeciesCount = DCount("[Species]", "AnimalInfo", "[Species] = txtSpecies AND (is_null([L_ET_Color1],"""") = is_null(txtL_ET_Color1,""""))")
SpeciesCount = DCount("[Species]", "AnimalInfo", "[Species] = '" & txtSpecies & "'AND is_null([L_ET_Color1],"") ='" & is_null(txtL_ET_Color1, "") & "' AND [L_ET_No1]='" & txtL_ET_No1 & "'")
I have been tinkering with this for 3 hours and am no closer to a solution. What am I doing wrong?
In a module create the following function:
public function is_null(ctl as variant, nullreplace as string) as variant
if ctl is null then
is_null = nullreplace
else
is_null = ctl
end if
end function
In your query change your reference to a given field, yourField to is_null(yourField, "").
In a string enclosed in double quotes, this will need to be is_null(yourField, """") (it needs a double-quote to escape a double-quote, so 4 is 2 internally)
I am using DCount to help display an error message if the data signals an error. I have it working with one criteria where a number is equal to another number. Now I wanted to add another criteria in there where another field, ReturnDate (this field is Text not Date/Time) is equal to a hyphen (-).
I'm just not really sure how to format it. I have this:
If DCount("*", "CrewTable", "KitNumber=" & _
Me.AssignKit.Value And "ReturnDate=" & _
"-") > 0 Then
Cancel = True
MsgBox "Kit is already assigned!"
AssignKit = ""
AssignKit.SetFocus
Else
...
The error pops up with a 'Type Mistmatch' and the debugger highlights the whole statment from 'If -> Then' and has an error pointing to the line with the hyphen in the quotes.
If DCount("*", "CrewTable", "ReturnDate='-' AND KitNumber=" & _
Me.AssignKit.Value) > 0 Then
It's easier to troubleshoot DCount errors when you store its Criteria option in a string variable.
Dim strCriteria As String
strCriteria = "ReturnDate='-' AND KitNumber=" & Me.AssignKit.Value
Debug.Print strCriteria
If DCount("*", "CrewTable", strCriteria) > 0 Then
If you had used this approach, Access would have alerted you to the fact that the original code which built the Criteria string was invalid. That should make it clearer that the problem wasn't due to the If condition, and it wasn't exactly a DCount problem either ... it was a problem with string concatenation.
Me.AssignKit.Value & " And ReturnDate=" & _
I have a sub form in Access:
The CopyNo is a combobox that lets me select from the MovieCopies table. When I select one, I want the Title field to show the correct movie title associated to that copy's movie ID. I also want the format to show. When I select from DaysRented combobox, if I select 1 and the movie is New, I want it to display the price, if it is regular for 3 days display the correct price etc.
I'm just not sure how to give logic to the comboboxes.
If anyone could point me in the right direction of how to do this sort of thing in Access 2007 I'd really appreciate it.
Thanks
Something like this:
Private Sub cboCopyNo_AfterUpdate()
If Nz(Me.cboCopyNo, "") <> "" Then
Me.txtTitle = DLookup("Title", "MovieMaster", "MovieID = " & Me.cboCopyNo)
End If
End Sub
Private Sub cboDaysRented_AfterUpdate()
If Nz(Me.cboDaysRented, 0) > 0 Then
Dim strType as String
strType = DLookup("[Type]", "MovieMaster", "MovieID = " & Me.cboCopyNo)
If Me.cboDaysRented = 1 Then
Me.txtPrice = DLookup("Price1Day", "Price", "[Type] = '" & strType & "'")
Else
Me.txtPrice = DLookup("Price3Day", "Price", "[Type] = '" & strType & "'")
End If
End If
End Sub
Couple notes. Some of your field names are reserved words in certain databases, such as "Type". I highly recommend you try to use field names that are not reserved words in Access or SQL server.
DLookups are not necessarily the fastest way to lookup data but will likely be fast enough for what you're trying to do here. Sometimes I create my own DAO recordset and lookup the values I want rather than using DLookup. It's basically like writing your own DLookup function.
DLookup uses SQL language so your syntax in the third argument, the WHERE clause, needs to match SQL. If the field in your WHERE clause is text/string you'll need to use a single quote on either side of the value (as shown above around the strType variable). If it is a number field you will not need the quotes. If it's a date you'll need hash signs (#).
I'm trying to get the length of a string in order to format a report using VBA in Access 2000. Yes I know this old but it's what I've been asked to do. I want to get the width of the string when printed; exactly what TextWidth() is meant to return. What I'm finding is that for strings ranging for 4-20 characters the returned value can range from exactly the right length to the correct length plus about an inch. This is too inaccurate for the formatting I wish to do. Is this common? I can't find any reference to this as a common problem but I've gone over and over the code and I'm fairly certain the function is just inaccurate ratehr than there being a logic problem.
Check the report's FontName and FontSize properties. If they are different than the field you are working with, you'll get wildly different results.
Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
MsgBox (Me.FontName & " ," & Me.FontSize)
MsgBox (TextWidth("Test"))
Me.FontName = Me.f2.FontName 'ariel
Me.FontSize = Me.f2.FontSize '8
MsgBox (Me.FontName & " ," & Me.FontSize)
MsgBox (TextWidth("Test"))
Me.FontName = Me.f1.FontName 'ariel
Me.FontSize = Me.f1.FontSize '16
MsgBox (Me.FontName & " ," & Me.FontSize)
MsgBox (TextWidth("Test"))
End Sub
I'm still not sure how to set the report's font name and size though, I don't see anything in it's properties.