MSACCESS 2010 VBA; Syntax Error in date in query expression - vba

I am creating a simple database for tracking working hours. The idea is that:
Every day you need to input only the days that employee did not work (startDate, endDate, absenceType),
Then calculate working days for the whole month or selected period.
Calculation of working days should take into account weekends (saturday, sunday) and holidays from Holiday table.
I took a function sample from MSDN (Counting the Number of Working Days in Access 2007) and put it into a module in my MS Access 2010 db but each time I run a query I have this error.
Typically the same error appears attempting to run a query in another sample database from somewhere.
The problem is in the strWhere clause:
strWhere = "[Holiday] >=#" & startDate & "# AND [Holiday] <=#" & endDate & "#"
' Count the number of holidays.
nHolidays = DCount(Expr:="[Holiday]", Domain:=strHolidays, Criteria:=strWhere)
Workdays = nWeekdays - nHolidays
The error msg from both databases is available in the link below
Runtime Error 3075 Syntax error in date in query expression
Any help is appreciated.

You must force a format on the string expressions for your dates. Get used to use the ISO sequence yyyy-mm-dd as it works everywhere:
strHolidays = "NameOfYourTable"
strWhere = "[Holiday] >= #" & Format(startDate, "yyyy\/mm\/dd") & "# AND [Holiday] <= #" & Format(endDate, "yyyy\/mm\/dd") & "#"
' Count the number of holidays.
nHolidays = DCount("*", strHolidays, strWhere)

In the past I have had issues where VBA doesn't always respect the regional date settings. Try forcing it into US format before concatenating it
strWhere = "[Holiday] >=#" & Format(startDate, "MM/dd/yyyy") & "# AND [Holiday] <=#" & Format(endDate, "MM/dd/yyyy") & "#"

Make sure the date is in MM/DD/YYYY order in VBA. Always. I generally use:
strWhere = "[Holiday] >= " & Format(startDate,"\#mm\/dd\/yyyy\#")
the second argument of DCount is strHolidays. That does not look like the name of a table/query. This argument should be the name of a table/query.

Related

How to filter by date field when system date format is dd/mm/yyyy

I have a report which contains a datetime field. There is a form used to gather user input for the query, specifically the From and To date for the query to be filtered.
The report is opened using this code:
Dim str as String
str = "DateCreated BETWEEN #" & format(From_Date.value, "yyyy-mm-dd") & "# AND #" & DateAdd("d", 1, format(To_Date.value, "yyyy-mm-dd")) & "#"
DoCmd.OpenReport "report_name", acViewReport, WhereCondition:=str
On Windows machines that have the date format as mm/dd/yyyy, or yyyy-mm-dd, the query works.
Some users have the system date set to dd/mm/yyyy. The filter is reading 08/11/2021 (Nov 8th, 2021) as Aug 11th, 2021.
I tried formatting the date inputs for the WHERE condition using format(From_Date.value, "yyyy-mm-dd").
Does Access support dd/mm/yyyy format? How can I filter by a date range?
Is the only option to adjust the user's system date format?
Always use parameters, never concatenate formatted dates to SQL strings.
If you use formatted dates in SQL strings you're setting yourself up for failure, the chance of accidentally doing something wrong is huge.
Dim str as String
str = "DateCreated BETWEEN p1 AND p2"
DoCmd.SetParameter "p1", From_Date.value
DoCmd.SetParameter "p2", DateAdd("d", 1, To_Date.value)
DoCmd.OpenReport "report_name", acViewReport, WhereCondition:=str
Read more on parameters in Access: How do I use parameters in VBA in the different contexts in Microsoft Access?
You can use one of the general date format codes (instead of a custom format string) to use the system format.
Dim str as String
str = "DateCreated BETWEEN #" & format(From_Date.value, "Long Date") & "# AND #" & DateAdd("d", 1, format(To_Date.value, "Long Date")) & "#"
DoCmd.OpenReport "report_name", acViewReport, WhereCondition:=str

How to check time range while adding a new record in a table?

I have an Access table called "Reservations" and an Access form called "Reservations Form".
Reservation Table
Employee_Name
Service_Name
Service Hours
Start_DateTime
End_DateTime
John
Head Massage
2 hours
31-Dec-20 3:00:00 PM
31-Dec-20 5:00:00 PM
Bob
Foot Massage
1 hour
31-Dec-20 3:00:00 PM
31-Dec-20 4:00:00 PM
The form structure
Employee_Name : (Input Field)
Service_Name : (Input Field)
Service_Hours : (Input Field)
Start_DateTime : (Input Date Time Field)
End_DateTime : (Input Date Time Field)
Sample Data in the form
Employee_Name : John
Service_Name : Head Massage
Service_Hours : 2 Hours
Start_DateTime : 31-Dec-20 4:00:00 PM
End_DateTime : 31-Dec-20 5:00:00 PM
We can't accept two reservations for the same employee on the same day and same time.
There is a reservation for John from 31-Dec-20 3:00:00 PM to 31-Dec-20 5:00:00 PM.
No other reservation can be accepted in this time period.
If a new reservation is submitted by the reservation form we need to check the Date and time with employee name.
John is already reserved from 31-Dec-20 3:00:00 PM to 31-Dec-20 5:00:00 PM.
He is not available for the new reservation (From 31-Dec-20 4:00:00 PM to 31-Dec-20 5:00:00 PM).
VBA Code
Private Sub Command11_Click()
Dim strWhere As String
Dim dtRequeestStartDate As Date
Dim dtRequestEndDate As Date
dtRequestStartDate = Me![Text1].Value
dtRequestEndDate = Me![Text2].Value
If (DCount("Employee_Name", "Reservations", "Employee_Name=""" & [Employee_Name].Value & """ AND #" & Format(dtRequestStartDate, "dd/mm/yyyy hh:mm:ss AM/PM") & "# <= EndDate" & " and #" & Format(dtRequestEndDate, "dd/mm/yyyy hh:mm:ss AM/PM") & "# >= StartDate") <> 0) Then
MsgBox "Can't book a reservation."
End If
I get an error
The expression you entered as a query parameter produced this error: 'EndDate'
Field names for date fields used in criteria are not same as field names shown in table.
Might want to first validate that requested dates are for a future date, not a typo with last month or last year. Can use ValidationRule property of textbox: >=Now().
As is now, both start and end date must be within range for request to be rejected. Should probably check if either start OR end date is between already reserved range. In other words, check for overlapping ranges.
AND (#" & Format(dtRequestStartDate, "dd/mm/yyyy hh:mm:ss AM/PM") & "# BETWEEN Start_DateTime AND End_DateTime OR #" & _
Format(dtRequestEndDate, "dd/mm/yyyy hh:mm:ss AM/PM") & "# BETWEEN Start_DateTime AND End_DateTime)"
Ok, that is starting to look quite nice.
The idea of the "strWhere" you have (and I see you not using it) is simply to help in writing the code (and I suppose to save some days in rooms requring padded walls).
How do you eat a elephant?
Answer: one bite at a time.
So, the idea here is to break this down into smaller and smaller parts - so small that this becomes a walk in the park.
So, we first need (and want) to setup a date/range test/criteria.
So, this should do the trick:
Dim strWhere As String
Dim dtRequeestStartDate As Date
Dim dtRequestEndDate As Date
dtRequestStartDate = Me![Text1].Value
dtRequestEndDate = Me![Text2].Value
ftime = "mm/dd/yyyy HH:MM"
strWhere = "#" & Format(dtRequestStartDate, ftime) & "# <= End_DateTime" & _
" and #" & Format(dtRequestEndDate, ftime) & "# >= Start_DateTime"
So, that takes care of our date range. but we also need to add to the above the staff.
So, we simply add it to above.
strWhere = strWhere & " AND "Employee_Name = '" & [Employee_Name].Value & "'"
So, see why we have the strWhere. We don't have to do this, but now we can break this down, and add one or even 5 more criteria to the where clause.
So, now that we have strWhere with the date range, and with the staff?
Then we can use dcount()
dcount() is
dcount("some field name", "some table name", "some where clause")
So, that's the syntax for dcount(). In fact, dlookup(), and dcount() are much the same. The only real differance is that lookup() returns a value, while dcount() returns a count.
In this case, all we care if the request has a count of 1, or 20 or whatever (anything greater then 0 is a collision).
So, now we have the criteria loaded up into that where clause?
Then we can use dcount() like this:
If DCount("*", "Reservations", strWhere) > 0 then
MsgBox "Can't book a reservation."
End If
So you can see why the suggest to load up the criteria into the strWhere. It just allows the code to be read oh so much with greater ease. And note I used "*" for the first value in dcount(). You could put in "id" or any column you want - but we really don't care, since we are just counting rows - we ONLY care if we have a result of > 0.
So, in summary, we have quite much this code:
Dim strWhere As String
Dim dtRequeestStartDate As Date
Dim dtRequestEndDate As Date
Dim ftime As String
ftime = "mm/dd/yyyy HH:MM"
dtRequestStartDate = Me![Text1].Value
dtRequestEndDate = Me![Text2].Value
' date range critera
strWhere = "#" & Format(dtRequestStartDate, ftime) & "# <= End_DateTime" & _
" and #" & Format(dtRequestEndDate, ftime) & "# >= Start_DateTime"
' employee criteria
strWhere = strWhere & " AND Employee_Name = '" & [Employee_Name].Value & "'"
' doctors exam room criteria
' ok - we don't' have any!!!, but we can add many more criteria.
' now data pull - check for existing -
If DCount("*", "Reservations", strWhere) > 0 then
MsgBox "Can't book a reservation."
else
' ok to book - call routines to add this record to reservations
End If

SQL for fetching all date/times on a single date

I have a table of whose rows contain a date/time filled with appointment times. The appointment times are a single field (i.e. the date and the time together). I've created a recordset to fetch all the appointments which occur on a given date:
Dim dt as date
dt = #3/2/2019#
Set rs = Currentdb.OpenRecordSet("SELECT stuff FROM Appt WHERE
Int(Appt.apptTime) = #" & dt & "#") --------
This works, but the "Int" function makes it inefficient. One solution would be to separate the date/time field into two fields (date and time) then just search on the date field. Unfortunately, I don't have the option of modifying the database structure.
Does anyone have a suggestion of how I can make this fetch more efficient?
You must format the date expressions properly and remember the equal option:
Set rs = Currentdb.OpenRecordSet("SELECT stuff FROM Appt WHERE Appt.apptTime >= #" & Format(dt, "yyyy\/mm\/dd") & "# AND Appt.apptTime < #" & Format(DateAdd("d", 1, dt), "yyyy\/mm\/dd") & "#")
I just figured out a solution:
WHERE (Appt.apptTime > #" & dt & "#) AND (Appt.apptTime < #" & dt + 1 & "#")
You can use DateValue(Appt.apptTime)
eg:
"WHERE ( DateVaue(Appt.apptTime) = #" & dt & "#"
The above will return only the date part and remove the time portion.
However, the above can't use high-speed indexing. So, your follow answer of :
WHERE (Appt.apptTime > #" & dt & "#) AND (Appt.apptTime < #" & dt + 1 & "#")
will run much faster. The only other issue is that you should (need) to force the format to USA format, else your posted solution can fail depending on the users reginal (date format) settings. So, on some computer you find the above will not work, or fail, or even get things like 4/5/2020 mixed up. Is that April 5, or May 4th?
So, you need to correctly format the date to USA and ensure that you IGNORE the users date format, else your code will fail on many computers with different date formats.
You should create a helper function for this, like this:
Public Function quDateT(dt As Date) As String
' return formatted date
quDateT = "#" & Format(dt, "mm\/dd\/yyyy HH:NN:SS") & "#"
End Function
Then, your query becomes:
WHERE (Appt.apptTime > " & qudateT(dt) & ") AND (attt.apptTime < " & qudateT(dt + 1)
Now in your case, DT will not have time, so the time portion of qudateT will be 00:00:00.
So, your example follow up should work, but you want to FORCE the date format to MM/DD/YYYY (USA) format, and if users have their setting such as DD/MM/YYYY, then your example query will fail on computers with such (different) regional settings.
I don't see why date formatting matter as all dates, regardless of displayed format, are stored as double-precision, floating-point numbers. The integer portion being the number of days since December 30, 1899; the fractional portion being the fraction of the 24-hour day. So my computation (in my updated "found a solution" post), which treats the dates as numbers should be immune to whatever date format has been chosen for the display of dates, right?

Subquery Excel VBA SQL

I need help with subquery in excel VBA. First: I need look for data by date -> for example from: 20.8.2018 to 21.8.2019 and Second: I need look for data by time from first result - > for example from 08:00:00 to 14:00:00
Now, I am looking data only by Date
strQueryQ7DrRightElox = "Select nio,checked FROM q7_dr_right_elox_incoming_inspection where date >= '" & sDateFrom & "' AND date <= '" & sDateTo & "' "
I found solution . I have two columns Date and Time in SQL DB.Then I created another column datetime where is date and time together in one column and I can compare data correctly

What's wrong with my SELECT statement?

I'm using this code to get the last number in a column where date of column is today date:
cn.Open("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & Application.StartupPath & "\bysys.mdb")
rs.Open("Select max(snum) From tblbill where idate = #" & Format(Today.Date, "dd/MM/yyyy") & "# ", cn, 1, 2)
If IsDBNull(Rs.Fields(0).Value) Then
TextBox6.Text = 1
Else
TextBox6.Text = Rs.Fields(0).Value + 1
End If
Sometimes it works correctly, but sometimes, it always return 1..
When you submit a value which can represent a valid date in mm/dd/yyyy format, Access will interpret it as such. You could deliberately format it as mm/dd/yyyy instead of dd/mm/yyyy. But many of us prefer yyyy/mm/dd because Access always interprets that format correctly and we humans needn't be bothered about possible confusion over whether the date is dd/mm/yyyy or mm/dd/yyyy format.
"Select max(snum) From tblbill where idate = #" & Format(Today.Date, "yyyy/mm/dd") & "# "
However the db engine supports a function, Date(), which your query can use to refer to the current date without bothering about any formatting. So this alternative seems simplest to me ...
"Select max(snum) From tblbill where idate = Date()"