I am trying to have a msgbox popup when clicking on a command button within a form in Access 2003.
The msgbox should be triggered by the current date, when compared to dates referenced within a table that is in the database. It would look like this:
If Date() is < [Date in table?], THEN "Msgbox" = "It is now Quarter 2"
once it is beyond the date for quarter 3, the msg box would read "It is now Quarter 3"
Thanks if you can help
Access has a set of functions called Domain Functions for looking up a single piece of information stored in a table. Some of the most common ones are DCount(), DLookup(), DSum(), DAvg(), DMax(), and DMin().
You need to use the DLookup function for this. Basically, it needs a field name and a table name to lookup a value. And in many cases you want to include a criteria statement (or WHERE clause) as the third argument to make sure that the DLookup function is actually retrieving the value from the correct row. If you don't pass in a criteria statment, the Domain functions will simply return the first match.
If Date() <= DLookup("SomeDateField", "tblYourTableName") Then
MsgBox "The date in stored in the table is today or else is in the future."
Else
MsgBox "The date stored in the table is in the past."
End If
Here's an alternate way to write this:
If Date() < DLookup("SomeDateField", "tblYourTableName") Then
MsgBox "The date in stored in the table is in the future."
Else
MsgBox "The date stored in the table is today or is in the past."
End If
And here's how you do it if you have multiple records/rows in the table. You then need to some kind of criteria statement to narrow it down to retrieving the value you want to from the very row you want.
If Date() < DLookup("SomeDateField", "tblYourTableName", "UserID = 1") Then
MsgBox "The date in stored in the table is in the future."
Else
MsgBox "The date stored in the table is today or is in the past."
End If
While it's not really what you are asking, I think it's important to realize what's really going on behind the scenes with this function (and other domain functions). Basically, you are choosing to retrieve one single value from one single table with the option to specify which record/row you want the value retrieved from using a criteria statement, known as a WHERE clause in SQL. So let's take a look at how you would write a function like this, and at how Microsoft likely did write their DLookup function.
Public Function MyLookup(ByVal strField As String, _
ByVal strTable As String, _
Optional ByVal strCriteria As String) As Variant
'Error handling intentionally omitted
'Proper error handling is very critical in
'production code in a function such as this
If strField <> "" And strTable <> "" Then
Dim sSQL as string
sSQL = "SELECT TOP 1 " & strField & " FROM " & strTable
If strCriteria <> "" Then
sSQL = sSQL & " WHERE " & strCriteria
End If
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset(sSQL, dbOpenSnapshot)
If Not (rst.EOF and rst.BOF) Then
MyLookup = rst(strField).Value
End If
rst.Close
Set rst = Nothing
End If
End Function
Now let's suppose you want to find the birthdate of someone in your contacts table:
Dim dteBirthDate as Date
dteBirthDate = MyLookup("BirthDate", "tblContacts", "ContactID = " & 12345)
If you didn't have a DLookup function, (or if you didn't write your own), you'd end up writing all that code in the "MyLookup" function up above for every time you needed to lookup a single value in a table.
I think what you're looking for is the following:
'Dates to be retrieved from the db (quarter start dates)
Dim q1 As Date
Dim q2 As Date
Dim q3 As Date
Dim q4 As Date
'Today's date
Dim today As Date
Dim quarter As Integer
Set today = Date()
Set q1 = DLookup("FieldContainingDate", "tableContainingDates", "quarter=1")
Set q2 = DLookup("FieldContainingDate", "tableContainingDates", "quarter=2")
Set q3 = DLookup("FieldContainingDate", "tableContainingDates", "quarter=3")
Set q4 = DLookup("FieldContainingDate", "tableContainingDates", "quarter=4")
Set quarter = 1 'Base case.
If (today > q1) Then quarter = 2
If (today > q2) Then quarter = 3
If (today > q3) Then quarter = 4
MsgBox "It is quarter " & quarter 'Display which quarter it is in a msgbox
You may have to fiddle with the date formatting depending on how you have it stored in the database, etc. It would also be much more efficient to write it in another way (for instance remove the intermediary q# variables) but I wrote it out in a lengthy way to make it more clear.
Related
I have just inherited a new database to maintain. But one of the tables is, well, not great. I could write a complex query to fix this problem, but it would be long and tedious. I am wondering if there is an easier way to it?
The table looks like this :
Name
Data point
Date1
date 2
date 3
date 4
...
dateN
alpha
yes
date
date
date
date
...
date
beta
no
date
date
date
date
...
date
Thing is , what I need it to look like is this :
Name
Data point
DateCat
Date
alpha
yes
date1
date
beta
no
date2
date
alpha
yes
date3
date
beta
no
date4
date
alpha
yes
date2
date
beta
no
date1
date
Now a crosstab would allow me to go from what I want to what I have, is there an easy way to do the reverse, or is this a "Get your hands dirty and do it manually" situation? I am considering exporting the table, throwing it in to pandas and manipulating it that way, because I know I can do it there. Hoping Access has something built in for this?
Whilst Access doesn't have a single built-in function to do what you want, it is relatively easy to create something using VBA that loops the fields in the first table to output the data as required. Something like:
Sub sUnXTabData()
On Error GoTo E_Handle
Dim db As DAO.Database
Dim rsSteer As DAO.Recordset
Dim rsData As DAO.Recordset
Dim intCount As Integer
Dim intLoop1 As Integer
Set db = CurrentDb
Set rsSteer = db.OpenRecordset("SELECT * FROM tblXTab;")
If Not (rsSteer.BOF And rsSteer.EOF) Then
db.Execute "DELETE * FROM tblNotXTab;"
Set rsData = db.OpenRecordset("SELECT * FROM tblNotXTab WHERE 1=2;")
intCount = rsSteer.Fields.Count - 1
Do
For intLoop1 = 2 To intCount
rsData.AddNew
rsData("Name") = rsSteer("Name")
rsData("Datapoint") = rsSteer("Datapoint")
rsData("DateCat") = rsSteer.Fields(intLoop1).name
rsData("Date") = rsSteer.Fields(intLoop1)
rsData.Update
Next intLoop1
rsSteer.MoveNext
Loop Until rsSteer.EOF
End If
sExit:
On Error Resume Next
rsSteer.Close
rsData.Close
Set rsSteer = Nothing
Set rsData = Nothing
Set db = Nothing
Exit Sub
E_Handle:
MsgBox Err.Description & vbCrLf & vbCrLf & "sUnXTabData", vbOKOnly + vbCritical, "Error: " & Err.Number
Resume sExit
End Sub
Please note that Name and Date are reserved words in Access, so you should change them.
I need help, because when I run de code, Error appears when some date field is empty. I have a table with information and I run this code since the generator.
Eliminate #Error when I run the code vba in ACCESS
I will grateful for you help.
Option Compare Database
Public Function WorkingDays2(FECHA_DE_VALIDACION_FA As Date, FECHA_IMPRESIÓN As Date) As Integer
'....................................................................
' Name: WorkingDays2
' Inputs: StartDate As Date
' EndDate As Date
' Returns: Integer
' Author: Arvin Meyer
' Date: May 5,2002
' Comment: Accepts two dates and returns the number of weekdays between them
' Note that this function has been modified to account for holidays. It requires a table
' named tblHolidays with a field named HolidayDate.
'....................................................................
Dim intCount As Integer
Dim rst As DAO.Recordset
Dim DB As DAO.Database
Set DB = CurrentDb
Set rst = DB.OpenRecordset("SELECT [DIAFESTIVO] FROM DIASFESTIVOS", dbOpenSnapshot)
'StartDate = StartDate + 1
'To count StartDate as the 1st day comment out the line above
intCount = 0
Do While FECHA_DE_VALIDACION_FA <= FECHA_IMPRESIÓN
rst.FindFirst "[DIAFESTIVO] = #" & FECHA_DE_VALIDACION_FA & "#"
If Weekday(FECHA_DE_VALIDACION_FA) <> vbSunday And Weekday(FECHA_DE_VALIDACION_FA) <> vbSaturday Then
If rst.NoMatch Then intCount = intCount + 1
End If
FECHA_DE_VALIDACION_FA = FECHA_DE_VALIDACION_FA + 1
Loop
WorkingDays2 = intCount
Exit_WorkingDays2:
Exit Function
WorkingDays2 = intCount
Exit_WorkingDays2:
Exit Function
Err_WorkingDays2:
Select Case Err
Case Else
MsgBox Err.Description
Resume Exit_WorkingDays2
End Select
End Function
It depends a bit where you are calling this function from within your database. Probably as a calculated field in a query? Something like this:
WorkingDays: WorkingDays3([YourDateField])?
Try this instead:
WorkingDays: WorkingDays3(Nz([YourDateField],Date())
Your original question included code for a function named WorkingDays3, which takes one date parameter.
Your illustration shows a function named WorkingDays2, which takes two date parameters.
I think you will need to give more detailed information about the data you are working with, and under which conditions you are seeing the #Error.
Below I have some code I've written to validate whether the user entered data on a form, which populates a table. I am trying to confirm whether they have left field (MinAge) null. I am getting a data mismatch when I run the code. Is this the best way to do this? Help!
Dim MinAgeVal As Integer
MinAgeVal = DLookup("[MinAge]", "User_ProductDefaultsAge")
If MinAgeVal Is Null Then
x = MsgBox("Missing Minimum Age Value", vbCritical)
Else
x = MsgBox("clear", vbCritical)
End If
Also, the may be multiple rows within the table.
(UPDATED):
Ok... I have a table, which is populated by a user from a form. The user will enter a series of age ranges (min and max)... 0 - 5, 6 - 10, etc... each min / max range will be on its own row... I need to write code that will check each row for three things... 1) that there aren't any fields (min or max) that are null... 2) that the min range is not greater or equal to the max range... the the next row of data is in sequential order (max year of record 1 is less than the min year of record 2)
Min Year Max Year
0 1
2 10
15
Below, some code was provided for guidance...
Dim RS As DAO.Recordset
Dim SQL As String
'ordering is only important if you want the FIRST three MIDs.
'If you don't care, just omit the "order by MID" part.
SQL = "select top 3 MID from DealContent where DealID = xxx order by MID"
Set RS = CurrentDb.OpenRecordset(SQL)
Do While Not RS.EOF
Me!MID = Me!MID & RS("mid") & " "
RS.MoveNext
Loop
RS.Close
Set RS = Nothing
I get what most of the code is doing but can't figure out how to make/alter my code to do:
Set RS = CurrentDb.OpenRecordset(SQL)
Do While Not RS.EOF
Me!MID = Me!MID & RS("mid") & " "
RS.MoveNext
Try this:
Dim MinAgeVal As Variant
MinAgeVal = DLookup("[MinAge]", "User_ProductDefaultsAge")
If IsNull(MinAgeVal) Then
x = MsgBox("Missing Minimum Age Value", vbCritical)
Else
x = MsgBox("clear", vbCritical)
End If
The answer that Gustav provided will only work for one row. Dlookup cannot handle more than one record. You will need to use a recordset. Please see the link
I am having problems coming up with a solution to the following problem:
I have a booking form, but when the user adds details I want to check my database to see if the exact vehicle has been booked out for those dates already. If it has, an error message would appear.
Your vehicles should have ID Numbers. So, when a user tries to book a vehicle, you check the ID against the table of booked vehicles. Something like this (aircode) should work:
Dim db as Database
Dim rec as Recordset
Set db = CurrentDB
Set rec = db.OpenRecordset ("SELECT CarID FROM tblBookedCars WHERE CarID = " & Me.cboCarsToBook.Selected & "")
If rec.EOF Then
'Your car isn't booked, so process your booking
Else
Msgbox "That car is already booked"
End If
Assuming that booked out cars have a start and end date, then a booking collision occurs when:
RequestStartDate <= EndDate
and
RequestEndDate >= StartDate
The above is thus a rather simply query, but if any collision occurs, the above will return records, and you simply don’t allow the booking. And this means you don’t have to maintain some huge “messy” table of cars and each date that the car is book. You ONLY need simple row attached to a given vehicle with the start and end date (and thus it easy to change dates - you only update the one booking reocrd.
Air code to build such a query will look much like this:
dim strWhere as string
dim dtRequeestStartDate as date
dim dtRequestEndDate as date
dim lngCarID as long
dtRequestStartDate = inputbox("Enter start Date")
dtRequestEndDate = inputbox("Enter end date")
lngCarID = inputbox("What car id")
strWhere="#" & format(dtRequestStartDate,"mm/dd/yyyy") & "# <= EndDate" & _
" and #" & format(dtRequestEndDate,"mm/dd/yyyy") & "# >= StartDate and CarID = " & lngCarID
if dcount("*","tableBooking",strWhere) > 0 then
msgbox "sorry, you cant book
...bla bla bla....
The above is just an example, and I am sure you would build a nice form that prompts the user for the booking dates. However, what is nice here is that the above simple query will return ANY collision.
Dim lastcomp As String
Dim qty As Integer
Dim rs As New ADODB.Recordset
rs.Open "select Prem1Item,Prem1Qty from [TU FAR Before VB] order by Prem1Item", accCon
Do While Not rs.EOF
If Not IsNull(rs(0).Value) Then
If rs(0).Value <> "n/a" Then
If rs(0).Value <> "" Then
premlist.AddItem rs(0).Value & Format(rs(1).Value, "00")
End If
End If
End If
rs.MoveNext
Loop
rs.Close
Dim i As Integer
Dim j As Integer
i = 1
For i = 1 To premlist.ListCount
For j = 1 To finallist.ListCount
**If Not finallist(j) = premlist(i) Or finallist(j) = "" Then**
finallist.AddItem premlist(i)
End If
Next j
Next i
AccessConnection ("Close")
End If
I am trying to take the records and pull all of the items in Prem1Item and condense then down to not show duplicates and also get the amount from Prem1Qty and show the total of each item it finds. I was trying to put them in these listboxs and then export them to a table that has 2 columns (Premium and Sum)
I am getting error 13 Type mismatch highlighting the area I have put in Bold ("If Not finalist(j) = premlist(i) Or finalist(j) = "" Then"). My plans were to get that list populated and then fill the table to generate my report with.
A list box object does not allow you to retrieve row values with an index value, like you would for an array, or a VBA Collection, or a recordset Fields collection, and so on.
There is probably a better way to say that, but I don't know how. But attempts such as the following will throw that "Type Mismatch" error ...
Debug.Print Me.finallist(1)
Debug.Print TypeName(Me.finallist(1))
If you want to retrieve the bound column value from each of the list box's rows, use the ItemData property.
Dim i As Long
For i = 0 To (Me.finallist.ListCount - 1)
Debug.Print Me.finallist.ItemData(i)
Next
Debug.Print "done"
I think you should try adding the .value to your comparrison e.g.
finallist(j).value = premlist(i).value