In the comments on this answer, Remou writes that
CurrentDB.Execute "insert sql here"
is better than
DoCmd.SetWarnings = 0
DoCmd.RunSQL "insert sql here"
due to the built-in warnings that Access produces. I'm trying to understand the difference.
If they both mask errors, why is the first one preferable over the second? Are there any best practices here?
They do not both mask errors. DoCmd.SetWarnings masks errors and is system wide, not confined to the single application that you are using. DoCmd.SetWarnings False without the corresponding DoCmd.SetWarnings True will mean that action queries will run without any prompts in any Access application on the PC.
Execute does throw warnings, the warnings that you need, such as the query failed to execute, but does not give warnings you may not need, such as "Are you sure you want to run this query".
In this thread Allen Browne, Access MVP, says he does not use Set Warnings.
As an aside, I would generally recommend using an instance of CurrentDB, as this will allow you to return a record count, amongst other things, so:
Set db = CurrentDB
db.Execute sSQL, dbFailOnError
Related
On a form, a user is able to select a value of either 1 or 2. This number is on an unbound control called CountVal.
When the user selects the submit button, an update query is ran. The following is the query.
UPDATE UserData_T SET UserQuantity = Forms!MainUser_F!CountVal.value;
The query, when run separately, runs as should. The issue comes when I call it in the submit button click event. I use the CurrentDb.Execute method. This method throws a
3061 error of "Too few parameters'.
I have found through much research that control based parameters do not work with the execute method. It works when I set the value as either 1 or 2 but not through the control. I need to have this dynamic.
I have also tried the DAO.Database.OpenRecordset() method, however I am struggling with looping through each record. Logically, I would gravitate to a for each but I'm not finding any references on using this loop with a DAO recordset. Also, wouldn't looping through the recordset be extremely slow? Could I also add an if statement to the query itself?
In MS Access, stored queries can refer to open form or report controls as parameters. However, queries called via DAO methods like CurrentDb.Execute, do not see the GUI interface and hence cannot evaluate form or report controls.
So to continue using form controls as is, simply save your SQL statement as a stored query and call it with DoCmd.OpenQuery (which do not need to be closed for action queries like UPDATE, INSERT, DELETE). This is the coding counterpart to clicking the stored query via Navigation Pane.
DoCmd.OpenQuery "mySavedUpdateQuery"
Do note the above will raise prompts of data changes. To suppress such prompts, use DoCmd.SetWarnings:
DoCmd.SetWarnings False
DoCmd.OpenQuery "mySavedUpdateQuery"
DoCmd.SetWarnings True
You must concatenate the value to build the SQL:
Dim Sql As String
Sql = "UPDATE UserData_T SET UserQuantity = " & Forms!MainUser_F!CountVal.Value & ""
I'm trying to set the sql code for a query and then run the query from VB. The problem is that when I change the sql dynamically, the VB opens the query but does not refresh it. It still shows results from old sql. If I check the sql, it has changed, and if I then run the query (! button), it runs with the new sql.
I'm doing:
Set qdf = CurrentDb.QueryDefs("temp_query")
qdf.SQL = SQL_query_string
MsgBox (qdf.SQL)
DoCmd.OpenQuery ("temp_query")
With SQL_query_string containing the new, dynamically generated sql. The message box shows me that I indeed have the new string. And, as I said, I can check it in the query itself, and it has changed, but DoCmd.OpenQuery("temp_query") seems to just give the query the focus, not actually running it. What command runs it with the fresh sql?
If the query is already open, you need to close it and then reopen, interestingly enough, you probably do not even need to check if it is open, you can just close and then run the code.
DoCmd.Close acQuery, "temp_query"
Set qdf = CurrentDb.QueryDefs("temp_query")
qdf.SQL = SQL_query_string
'MsgBox (qdf.SQL)
DoCmd.OpenQuery "temp_query"
Make sure you have not used Set Warnings or On Error resume next, because they will mask errors.
I've inherited a script that runs and inserts records from one database into another database.
Everything appeared to be working fine until a few days ago when people complained that a record wasn't being pulled from one system to the other system.
I looked at the macro which was set to run with a scheduled task on Windows Server 2003. The macro sends it's logged output to SQL Server, and so I went there and looked for the appropriate log statements which read that one employee had been inserted into the database. However, when going to the other system, the employee that was reportedly transferred and inserted, was not there.
Upon further inspection pulled just the fields that were being selected from the one database, to the insert statement which added them to the other database.
When I tried to insert these values manually I received an SQL error that the fields were not allowed to be NULL or a zero length string. However, despite error checking in the script,
Function SomeFunc
On Error GoTo The_Err
DoCmd.SetWarnings False ' This statement seems a bit suspect to me...maybe fields being
' null or a zero length are just warnings? Seems wrong because
' I don't want a warning when my record will not be inserted,
' I want an error.
....
DoCmd.OpenQuery "qryAddNewEmp_S1toS2", acViewNormal, acAdd ' This is the statement that
' selects from the one db
' and inserts into the other db
...
The_Exit:
Exit Function
The_Err:
' MsgBox Error$ ' You can turn this on and off.
dmsg = "Error AUCP"
RunCheck dmsg, errArea, 0, 0
DoCmd.SetWarnings True
Resume The_Exit
End Function
Are the warnings turned off from DoCmd.SetWarnings False preventing the errors from being logged? Also should I just be doing the validation in the code instead, checking each of the values? It doesn't seem right to me, it seems like that's something that should be the responsibility of the database, since the database has that built in.
Instead of DoCmd.OpenQuery, use an approach like this ...
Dim db As DAO.Database
Set db = CurrentDb
db.Execute "qryAddNewEmp_S1toS2", dbFailOnError
Set db = Nothing
Then you will have no reason to turn SetWarnings off (False). And an INSERT failure will be captured by your error handler code, and the error will be logged (assuming RunCheck is a custom procedure which does the logging).
How do I execute a saved query in MS Access 2007 in VBA?
I do not want to copy and paste the SQL into VBA. I rather just execute the name of the query.
This doesn't work ... VBA can't find the query.
CurrentDb.Execute queryname
You can do it the following way:
DoCmd.OpenQuery "yourQueryName", acViewNormal, acEdit
OR
CurrentDb.OpenRecordset("yourQueryName")
You should investigate why VBA can't find queryname.
I have a saved query named qryAddLoginfoRow. It inserts a row with the current time into my loginfo table. That query runs successfully when called by name by CurrentDb.Execute.
CurrentDb.Execute "qryAddLoginfoRow"
My guess is that either queryname is a variable holding the name of a query which doesn't exist in the current database's QueryDefs collection, or queryname is the literal name of an existing query but you didn't enclose it in quotes.
Edit:
You need to find a way to accept that queryname does not exist in the current db's QueryDefs collection. Add these 2 lines to your VBA code just before the CurrentDb.Execute line.
Debug.Print "queryname = '" & queryname & "'"
Debug.Print CurrentDb.QueryDefs(queryname).Name
The second of those 2 lines will trigger run-time error 3265, "Item not found in this collection." Then go to the Immediate window to verify the name of the query you're asking CurrentDb to Execute.
To use CurrentDb.Execute, your query must be an action query, AND in quotes.
CurrentDb.Execute "queryname"
Thre are 2 ways to run Action Query in MS Access VBA:
You can use DoCmd.OpenQuery statement. This allows you to control these warnings:
BUT! Keep in mind that DoCmd.SetWarnings will remain set even after the function completes. This means that you need to make sure that you leave it in a condition that suits your needs
Function RunActionQuery(QueryName As String)
On Error GoTo Hell 'Set Error Hanlder
DoCmd.SetWarnings True 'Turn On Warnings
DoCmd.OpenQuery QueryName 'Execute Action Query
DoCmd.SetWarnings False 'Turn On Warnings
Exit Function
Hell:
If Err.Number = 2501 Then 'If Query Was Canceled
MsgBox Err.Description, vbInformation
Else 'Everything else
MsgBox Err.Description, vbCritical
End If
End Function
You can use CurrentDb.Execute method. This alows you to keep Action Query failures
under control. The SetWarnings flag does not affect it. Query is executed always without warnings.
Function RunActionQuery()
'To Catch the Query Error use dbFailOnError option
On Error GoTo Hell
CurrentDb.Execute "Query1", dbFailOnError
Exit Function
Hell:
Debug.Print Err.Description
End Function
It is worth noting that the dbFailOnError option responds only to data processing failures. If the Query contains an error (such as a typo), then a runtime error is generated, even if this option is not specified
In addition, you can use DoCmd.Hourglass True and DoCmd.Hourglass False to control the mouse pointer if your Query takes longer
in ms-access i am running a macro that runs several queries, during the execution of a query a message box appears
"you are about to run an update.......... are you sure you want to run this query ? "
how can i automatically select for all such cases so that macro runs without human intervention.
You can turn off temporary the warnings like this:
DoCmd.SetWarnings = False
DoCmd.RunSQL ...
DoCmd.SetWarnings = True
It is generally best to use Execute in such cases in order to trap errors:
Dim db As Database, qdf As QueryDef, strSQL As String
Set db = CurrentDb
Set qdf = db.QueryDefs("Query17")
qdf.Execute dbFailOnError
Debug.Print qdf.RecordsAffected
Or
strSQL="UPDATE SomeTable SET SomeField=10"
db.Execute strSQL, dbFailOnError
Debug.Print db.RecordsAffected
Trapping errors with dbFailOnError and an error trap is more or less essential and there are a number of other useful aspects to the Execute Statement
To avoid having to write the code #Remou supplies every time you execute arbitrary SQL you could use my SQLRun function, which is designed as a dropin replacement for DoCmd.RunSQL and avoids all the problems therewith.