Help with DateDiff in query

emik

New Member
Joined
Mar 22, 2011
Messages
27
Hi everyone, I've been really stuck on this so I hope someone can help me out.

I have an access 2007 database and am trying to do a calculation on the dates.

I am taking the average over 5 years, so from my transactions table I take the date field and I drop the year and group (to get the average for 01/01). I then want to add in the current year, so I take those first 5 characters and add the current year:

forecast_date: DateValue(Left([Value_Date],Len([Value_Date])-5) & "/" & Year(Date()))

The problem is I want the query to return only dates that are greater than today and less than today + 35. I tried using DateDiff:

datedifftest: DateDiff("d",[forecast_date],Date()) and it returns a number but I am not able to put a criteria on it. I even tried creating a sub query where my criteria was >0 and <35 but I get "Data type mismatch in criteria expression.

Any feedback is much appreciated.
 
Emik,<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:eek:ffice:eek:ffice" /><o:p></o:p>
<o:p></o:p>
You have to approach this different. Like I said a few posts ago, I gave you a solution, but its not the way to go by far.<o:p></o:p>
<o:p></o:p>
How I would do it, is like follows:<o:p></o:p>
First create a query definition that selects the raw data from your table.<o:p></o:p>
Then create a query that groups the data by days and months.<o:p></o:p>
Then create a tmpTable to hold the information you need. Use this tmpTable to insert data into a resultTable. You’ll end up with a table that holds, day, month, date, avgamount and avgOverNYears.<o:p></o:p>
The big advantage now is that you have a table with all numbers and dates in place which you can use to query your data really easy.
You can copy/paste this code into a module within Access

Code:
Option Compare Database
Option Explicit
'Set reference to the Microsoft ActiveX Data Object 2.x Library
[COLOR=teal]'don't change these values[/COLOR]
[COLOR=teal]Const sTmpTblName As String = "tmpForeCast"[/COLOR]
[COLOR=teal]Const sResultTableName As String = "resultForeCast"[/COLOR]
[COLOR=teal]Const sQAvgAmount As String = "qAvgAmount"[/COLOR]
[COLOR=sienna]'Change this if necessary[/COLOR]
[COLOR=sienna]'Create a query that returns the Fields "ValueDate" and "Amount" based on your sourcetable[/COLOR]
[COLOR=sienna]'If you use different fieldnames you'll have to change this through all SQL statements in this module[/COLOR]
[B][COLOR=sienna]Const sQDataOrigin As String = "qDataOrigin"[/COLOR][/B] [COLOR=sienna]'name of your query definition,[/COLOR]
Public Sub Start()
'Start process
Dim iYearForecast As Integer
Dim iDaysAhead As Integer
[B][COLOR=slategray]'\\\\\\\\\\\\\\\\ - INPUT - //////////////[/COLOR][/B]
iYearForecast = 2011    'range starts at first day of year
iDaysAhead = 8000        'number of days within the resulttable
[B][COLOR=slategray]'/////////////////////\\\\\\\\\\\\\\\\\\\[/COLOR][/B]
ReturnAvgAmountsForEachDay iYearForecast, iDaysAhead
End Sub
Public Sub CreateTmpTable(ByVal sTblName As String)
Dim db As DAO.Database
Dim tDef As DAO.TableDef
Set db = CurrentDb
'check if tbl exists and if so delete
For Each tDef In db.TableDefs
        If tDef.Name = sTblName Then
                 db.TableDefs.Delete tDef.Name
                Exit For
        End If
Next tDef
'Create table
Set tDef = db.CreateTableDef(sTblName)
'Append fields
    With tDef
        .Fields.Append .CreateField("rDay", dbInteger)
        .Fields.Append .CreateField("rMonth", dbInteger)
        .Fields.Append .CreateField("rYear", dbInteger)
        .Fields.Append .CreateField("rDate", dbDate)
        .Fields.Append .CreateField("rAvgAmount", dbDouble)
        .Fields.Append .CreateField("rAvgOverNYears", dbInteger)
    End With
db.TableDefs.Append tDef
End Sub
Public Sub ReturnAvgAmountsForEachDay(ByVal iYearForecast As Integer, _
                                      ByVal iDaysAhead As Integer)
'Create all days starting from Date_Start
On Error GoTo err_ReturnAllDays
Dim Date_Start As Date
Dim oCn As New ADODB.Connection
Dim oRs As New ADODB.Recordset
Dim db As DAO.Database
Dim qCompressedData As QueryDef
Dim arrDays() As String
Dim sSQLInsert As String
 
'create the tmpTable
CreateTmpTable sTmpTblName
Set oCn = CurrentProject.Connection
Set db = CurrentDb
ReDim arrDays(iDaysAhead)
Date_Start = CDate("1-1-" & iYearForecast)
'Statement to enter tmptable
sSQLInsert = "Select * From " & sTmpTblName
'Create array with dates
For iDaysAhead = 0 To UBound(arrDays)
           arrDays(iDaysAhead) = Date_Start + iDaysAhead
Next iDaysAhead
'Open recordset to append the array
oRs.Open sSQLInsert, oCn, adOpenDynamic, adLockOptimistic
For iDaysAhead = 0 To UBound(arrDays)
        'Insert date reference
        With oRs
                .AddNew
                .Fields("rDate").Value = arrDays(iDaysAhead)
                .Fields("rDay").Value = Day(arrDays(iDaysAhead))
                .Fields("rMonth").Value = Month(arrDays(iDaysAhead))
                .Fields("rYear").Value = Year(arrDays(iDaysAhead))
                .Update
        End With
 
Next iDaysAhead
oRs.Close
'delete qdef if exists
For Each qCompressedData In db.QueryDefs
    If qCompressedData.Name = sQAvgAmount Then
        db.QueryDefs.Delete qCompressedData.Name
        Exit For
    End If
Next qCompressedData
'Create the qDef object for the grouped data
Set qCompressedData = db.CreateQueryDef(sQAvgAmount, SQL_GroupedData(sQDataOrigin))
'Create resultstable
CreateTmpTable sResultTableName
DoCmd.SetWarnings False
        DoCmd.RunSQL SQL_InsertResultForeCast
DoCmd.SetWarnings True
        'Delete the tmp objects
       db.QueryDefs.Delete sQAvgAmount
       db.TableDefs.Delete sTmpTblName
 
Exit Sub
err_ReturnAllDays:
        Debug.Print Err.Description & vbTab & Err.Number
Resume Next
End Sub
Public Function SQL_InsertResultForeCast() As String
'Insert the data into the resultstable
SQL_InsertResultForeCast = "INSERT INTO resultForeCast ( rDay, rMonth, rYear, rDate, rAvgAmount, rAvgOverNYears ) " _
                         & "SELECT tmpForeCast.rDay, tmpForeCast.rMonth, tmpForeCast.rYear, tmpForeCast.rDate, CDbl(nz([AvgAmountFromData],0)) AS rAvgAmount, AvgOverNYears " _
                         & "FROM tmpForeCast LEFT JOIN qAvgAmount ON (tmpForeCast.rMonth = qAvgAmount.KeyMonth) AND (tmpForeCast.rDay = qAvgAmount.KeyDay)"
End Function
Public Function SQL_GroupedData(ByVal sQOrigin As String) As String
'SQL_statement to compress data
SQL_GroupedData = "SELECT Day([ValueDate]) AS KeyDay, Month([ValueDate]) AS KeyMonth, Avg(qDataOrigin.Amount) AS AvgAmountFromData, Count(qDataOrigin.Amount) AS AvgOverNYears " _
                & "FROM " & sQOrigin & " " _
                & "GROUP BY Day([ValueDate]), Month([ValueDate])"
End Function
 
Last edited:
Upvote 0

Excel Facts

Test for Multiple Conditions in IF?
Use AND(test, test, test, test) or OR(test, test, test, ...) as the logical_test argument of IF.
Hi Kreszch68,

I agree with you that it is easier to work with data from a table, but in this case I am not doing very much manipulation (I already have the week number and month number). The only issue I am still having is the roll over to the next year. The first solution you gave me works great but if I go 365 days into the future, it doesn't carry over to 2012, it always keeps the year of the current date.

The user will never touch the Access database, I have an Excel file that is currently linked to the query and returns the results. When I upload data from Excel to Access I do it all through SQL (never opening Access). Do you think I should still go through with the solution you posted or can I modify my query a little to give me the desired results?

Thanks.
 
Upvote 0
Personally I find it rare that a temp table is required and that a query can't do the entire thing. I don't know what other thread you have so I can't chime in about that but I am going to go try to find it.
 
Upvote 0
This is the only thread I have

Okay, I see that. I've been trying to wade through everything but it is a very jumbled mess.

First off, I don't understand why nobody has mentioned the DateAdd function to you. When trying to set criteria, it sometimes is better to use the DateAdd function instead of just adding a number:

DateAdd("d", 35, [DateFieldHere])

And especially if you are interested in a leap year:

DateAdd("yyyy", 1, [DateFieldHere])

Or on Criteria

Between Date() And DateAdd("d", 35, Date())


And then for getting the full date for which you have parts you should use DateSerial:

DateSerial(Year([DateFieldHere]) +1, Month([DateFieldHere], Day([DateFieldHere))

And if you want to get the last day of the month, for example, you can get:

DateSerial(Year([DateFieldHere]), Month([DateFieldHere]) + 1, 0)



Try to stay away from using NOW() unless you really need the time component. Use Date() instead.
 
Upvote 0
Hi Bob,

Thanks for the reply. The main problem I have is creating a date.

A quick example. I have 5 years of data (for each day of the year):

$200 on May 5, 2006
$400 on May 5, 2007
$500 on May 5, 2008
$700 on May 5, 2009
$300 on May 5, 2010

Now I need to forecast what the average will be for May 5, 2011. To do this I need to take the average of all previous May 5. In order to group and average them in my query I drop the year. The problem is when I try to re-add the year.

The result I am looking for is:
$420 on May 5, 2011

In the solution that I got from Kreszch68 on the previous page it only keeps the current year. Since I always need to have forecasted 35 days into the future, at the end of the year I will run into problems when we are currently in Dec 2011 but I need the forecast for Jan 2012.
 
Upvote 0
The problem is when I try to re-add the year.
The way to add the year back in, as I've said is to use the DateSerial Function. It is the way to do it. So, if you want to ensure that the correct date is there:

MyNewDate: DateSerial(Year(DateAdd("d", 35, Date()), Month(DateAdd("d", 35, Date()), Day(DateAdd("d", 35, Date()))
 
Upvote 0
MyNewDate: DateSerial(Year(DateAdd("d", 35, Date()), Month(DateAdd("d", 35, Date()), Day(DateAdd("d", 35, Date()))

I get an error when I put this into an Access query:
function containing the wrong number of arguements
 
Upvote 0
Sorry, missed a few closing parens. This should work:

MyNewDate: DateSerial(Year(DateAdd("d",35,Date())),Month(DateAdd("d",35,Date())),Day(DateAdd("d",35,Date())))
 
Upvote 0
I don't seem to be getting the correct results:

Code:
ForeCastDate: CDate(Day([Value_Date]) & "-" & Month([Value_Date]))

This returns today + 35 (but I have the problem of Dec 2011 to Jan 2012).

I tried modifying the solution you provided
Code:
DateSerial(Year(DateAdd("d",35,Date())),Month(DateAdd("d",35,Date())),Day(DateAdd("d",35,Date())))

and it only gives me today + 35 days (not each day in between). I tried to modify it as follows:

Code:
MyNewDate: DateSerial(Year(Date()),Month([Value_Date]),Day([Value_Date]))

With the criteria Between Now() And Now()+400 (but it only goes to Dec 31, 2011. It does not rollover to 2012. What am I missing?

I need to combine the code you gave me with the dateadd but where would I do this? As a new field?

I think I found the solution:

MyNewDate: DateAdd("d",35,DateSerial(Year(Date()),Month([Value_Date]),Day([Value_Date])))


Thanks
 
Last edited:
Upvote 0

Forum statistics

Threads
1,215,227
Messages
6,123,739
Members
449,116
Latest member
alexlomt

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top