Reputation: 123
This may be a very simple question, but I've had difficulty understanding the information I've found online so far. When I try to run SQl from within my VBA, it gives me a type mismatch on my strSQl.
I have a table [tbl_DatabaseUpdateLog] with 4 columns
UpdateID (Autonumber)
Start (Date/Time)
End (Date/Time)
Duration (Date/Time)
I have to regularly pull information from company databases for a smaller analysis project, and I want to log how often and how long it takes to run these queries. Every time starts the update, it runs the following:
Dim StartUpdate, EndUpdate, LengthUpdate, strSQl As Date
StartUpdate = Time()
Call UpdateAll 'This calls the collection of queries and is irrelevant for my problem
EndUpdate = Time()
LengthUpdate = EndUpdate - StartUpdate
Forms!frm_Timer.Caption = "Update Completed at " & EndUpdate & " (" & Format(LengthUpdate, "HH:MM:SS") & ")"
DoCmd.SetWarnings (0)
strSQl = "INSERT INTO tbl_DatabaseUpdateLog ( Start, [End], Duration ) " & _
"SELECT '" & StartUpdate & "' AS Started, '" & EndUpdate & "' AS Ended, '" & LengthUpdate & "' AS Lasted"
DoCmd.RunSQL strSQl
DoCmd.SetWarnings (-1)
DoCmd.Close acForm, Me.Name
I have tried using #'s around the dates and using Now() instead of Time() but I feel like I'm missing a basic concept to help me fix the problem. I just need the Time of Day and duration (not so much the date itself) if that helps.
Upvotes: 2
Views: 8670
Reputation: 97101
When I try to run SQl from within my VBA, it gives me a type mismatch on my strSQl
Examine these 2 statements ...
Dim StartUpdate, EndUpdate, LengthUpdate, strSQl As Date
strSQl = "INSERT INTO tbl_DatabaseUpdateLog ( Start, [End], Duration ) " & _
"SELECT '" & StartUpdate & "' AS Started, '" & EndUpdate & "' AS Ended, '" & LengthUpdate & "' AS Lasted"
When you declare strSQl As Date
, that means strSQl
can only hold Date/Time values. A string such as "INSERT INTO ... whatever" is not a Date/Time value. So when you attempt to store such a string to strSQl
, Access complains the datatypes are not compatible: "Type mismatch".
Since you intend strSQl
to hold the text of a SQL Statement declare it this way (instead of As Date
): Dim strSQl As String
That change should get you past the error. For your larger goal, use a parameter query with DAO.
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim StartUpdate As Date, EndUpdate As Date, LengthUpdate As Date
Dim strSQl As String
StartUpdate = Time()
Call UpdateAll 'This calls the collection of queries and is irrelevant for my problem
EndUpdate = Time()
LengthUpdate = EndUpdate - StartUpdate
Forms!frm_Timer.Caption = "Update Completed at " & EndUpdate & " (" & Format(LengthUpdate, "HH:MM:SS") & ")"
strSQl = "INSERT INTO tbl_DatabaseUpdateLog ([Start], [End], Duration) " & _
"VALUES ([p1], [p2], [p3]);"
Set db = CurrentDb
Set qdf = db.CreateQueryDef(vbNullString, strSQl)
With qdf
.Parameters("p1").Value = StartUpdate
.Parameters("p2").Value = EndUpdate
.Parameters("p3").Value = LengthUpdate
End With
qdf.Execute dbFailOnError
DoCmd.Close acForm, Me.Name
Note that with this approach for the INSERT
, date format is not even an issue. Since StartUpdate
, EndUpdate
, and LengthUpdate
will all be valid Date/Time values, you can simply feed them to the parameters without bothering about format and #
delimiters.
Upvotes: 3
Reputation: 55806
A more straight method is using native DAO:
Dim rs As DAO.Recordset
Dim StartUpdate As Date
Dim EndUpdate As Date
Dim LengthUpdate As Date
StartUpdate = Time
Call UpdateAll 'This calls the collection of queries and is irrelevant for my problem.
EndUpdate = Time
LengthUpdate = EndUpdate - StartUpdate
Forms!frm_Timer.Caption = "Update Completed at " & EndUpdate & " (" & Format(LengthUpdate, "h:mm:ss") & ")"
Set rs = CurrentDb.OpenRecordset("Select Top 1 * From tbl_DatabaseUpdateLog")
rs.AddNew
rs!Start.Value = StartUpdate
rs!End.Value = EndUpdate
rs!Duration.Value = LengthUpdate
rs.Update
rs.Close
Set rs = Nothing
DoCmd.Close acForm, Me.Name
Upvotes: 1
Reputation: 155045
I see you're using INSERT INTO SELECT FROM (literal)
when a straightforward INSERT INTO (columns) VALUES (values)
would be simpler. You can also have multiple VALUES
sub-statements in a single INSERT
statement, which is neat.
I also see you're storing denormalized data, it's clear that Duration
can be derived from End - Start
, so you might want to drop that column.
Also, avoid Hungarian Notation, in this case prefixing a table's name with tbl_
. It isn't the 1980s anymore. Don't do it.
(Never do this)
If you're using SQL Server you need to enclose dates in single-quotes and you need to convert to an unambiguous date format string, such as yyyy-MM-dd HH:mm:ss
.
strSQL = "INSERT INTO neverDoThis VALUES ( '" & Format( startUpdate, "yyyy-MM-dd HH:mm:ss" & "' )"
If you're using Access or Jet you need to enclose dates in hash characters '#' and use the 'MM/dd/yyyy hh:mm:ss tt' format (dumb Americans...).
strSQL = "INSERT INTO neverDoThis VALUES ( #" & Format( startUpdate, "MM/dd/yyyy hh:mm:ss tt" & "# )"
Here's a reference for the Format
function: https://msdn.microsoft.com/en-us/library/office/gg251755.aspx?f=255&MSPPError=-2147217396
(Do this instead)
SQL Server uses named parameters like @foo
:
cmd.CommandText = "INSERT INTO databaseUpdateLog ( [Start], [End], [Duration] ) VALUES ( @start, @end, @duration )"
cmd.Parameters.Append cmd.CreateParameter( "@start", , , startUpdate )
cmd.Parameters.Append cmd.CreateParameter( "@end", , , endUpdate )
cmd.Parameters.Append cmd.CreateParameter( "@duration", , , lengthUpdate )
Access uses anonymous placeholders accessed by the order they're added, use `?':
cmd.CommandText = "INSERT INTO databaseUpdateLog ( [Start], [End], [Duration] ) VALUES ( ?, ?, ? )"
cmd.Parameters.Append cmd.CreateParameter( "?", , , startUpdate )
cmd.Parameters.Append cmd.CreateParameter( "?", , , endUpdate )
cmd.Parameters.Append cmd.CreateParameter( "?", , , lengthUpdate )
The Append
method in VBA is a Sub
so calling it doesn't use parenthesis.
The CreateParameter
method has 3 optional arguments in the middle: Type
, Direction
, and Size
which can be inferred from the values, so they are omitted by putting , , ,
.
Upvotes: 3
Reputation: 369
To calculate the time of day only, in VBA you can use this expression:
CDate(Now - Date())
Enclose the result in #'s as the result is still a Date type, even though only time info is being stored.
You can use the DateDiff function to calculate the duration, you need to choose appropriate units. e.g. :
DateDiff(DateInterval.Second, EndUpdate, StartUpdate)
The result is a long integer so you don't need to enclose the result in your SQL.
BTW parameterising your SQL is recommended, but not required.
Upvotes: -1