Jason Steward
asked on
Append New Record Query Without Using "SetWarnings"
I had this question after viewing Microsoft Access Form With A SearchForRecord Macro In A Combo Box Appears To Be Spontaneously Deleting Records.
I get an error message: Run-time Error '3622':
You must use the dbSeeChanges option with OpenRecordset when accessing a SQL Server table that has an IDENTITY column.
Here's my code:
Can anyone provide details on that?
I get an error message: Run-time Error '3622':
You must use the dbSeeChanges option with OpenRecordset when accessing a SQL Server table that has an IDENTITY column.
Here's my code:
Private Sub cboFacilityID_AfterUpdate()
'Old way of not displaying warning messages:
'DoCmd.SetWarnings False
'DoCmd.OpenQuery "PowerlineF_PowerlineParticipationAppend"
'DoCmd.SetWarnings True
"""""""""""""""""""""""
'New way:
CurrentDb.QueryDefs("PowerlineF_PowerlineParticipationAppend").Execute dbFailOnError
FacilityPowerSF.Requery
End Sub
Can anyone provide details on that?
Does the table that you are trying to link carries a Primary Key ? its essential.
When the backend is SQL server (where Identity is their name for Autonumber) you need to use the extra dbSeeChanges constant.
In your case it would go here:
In your case it would go here:
CurrentDb.QueryDefs("PowerlineF_PowerlineParticipationAppend").Execute dbFailOnError+dbSeeChanges
ASKER
Anders, I got an error: Too Few Parameters. Expected 2
Usually there is a problem with your query ...can you try it by putting static values instead of dynamic...just take the SQL of the Query and substitute the Values with static one that match the fields datatype..e.g VALUES ('1','04-23-2019,'Easter') ...
If you can run the action query manually (not using VBA code) and it runs o.k., then your code should run it ok too as long as you do what Anders suggested. No amount of VBA code will fix a bad query that won't run manually. Get a query that runs manually first, then run it with code.
Also, just checking. This isn't a pass-thru query you're trying to run is it? (built with T-SQL and has a connection string to the database)
ASKER
It runs fine manually. In fact, the original code with the SetWarnings False runs fine. See original post that I modified to show exact code. The "Old way" executes nicely.
Then probably you have some Values that need evaluation before passed to the query...just prepare the Values before presenting them to the query and it would run just fine.
e.g.
Instead of VALUES (Form!CtlSomething....)
Dim value1st as Integer
value1st = Form!CtlSomething
VALUES (value1st ,....)
Just give it a try ...and if it works ...you can try to implement Eval into the Values
VALUES(Eval(Form!CtlSometh ing),....)
e.g.
Instead of VALUES (Form!CtlSomething....)
Dim value1st as Integer
value1st = Form!CtlSomething
VALUES (value1st ,....)
Just give it a try ...and if it works ...you can try to implement Eval into the Values
VALUES(Eval(Form!CtlSometh
There is another difference between the 2 methods. Docmd.OpenQuery is the same as running it manually, through access, whereas CurrentDB.Execute is a more direct line to the database engine (Yet not the same as a passthrough).
It is a bit difficult to explain, but when using the query manually or through the use of Docmd, then access will pre-parse the query, and resolve such references as Forms!myForm!Control . This doesn't happen with the Execute syntax as it cannot understand form references.
In that case, you can either continue to use the docmd syntax, or build the query string entirely in VBA, and execute that.
It is a bit difficult to explain, but when using the query manually or through the use of Docmd, then access will pre-parse the query, and resolve such references as Forms!myForm!Control . This doesn't happen with the Execute syntax as it cannot understand form references.
In that case, you can either continue to use the docmd syntax, or build the query string entirely in VBA, and execute that.
ASKER
That makes sense... my query has criteria that refer to combo boxes on a form. Is that a limitation of the CurrentDB.Execute method?
in addition to Anders comment, if your query contains parameters, you can use syntax similar to:
If you insist on using docmd.SetWarnings, then I would always use a construct that looks something like:
Dim qdf as dao.querydef
set qdf = currentdb.querdefs("YourQueryName")
qdf.Parameters("ParamName1") = me.someValue
qdf.Parameters("NextParamName") = me.SomeOtherValue
qdf.Execute dbfailonError + dbSeeChanges
set qdf = nothing
I never use the docmd.OpenQuery method because of the SetWarnings issue. I cannot tell you how many databases I've had to fix where the users used:docmd.SetWarnings False
and either did not get back to:docmd.SetWarnings True
or placed that line of code in the wrong spot in their code, so that it did not fire on certain circumstances. Additionally, when you SetWarnings = False, you not only obscure the warnings that you are about to update, append, or delete X records, you also obscure warnings that warn you that you are violating some rule and that the query didn't execute at all.If you insist on using docmd.SetWarnings, then I would always use a construct that looks something like:
Private Sub YourProcedure
'Dim variables here
On Error goto ProcError
'some code here
docmd.setwarnings false
'some more code here
ProcExit:
on error resume next
'close and set objects to nothing
docmd.setwarnings True
Exit Sub
ProcError:
'Handle your error here
Resume ProcExit
End Sub
This construct, placing the docmd.setwarnings = True in ProcExit and ensuring you resume ProcExit in your Error handler will ensure that that command always gets executed before you exit a procedure.
@Dale: If there was a "Like" button, I'd give you one....
ASKER
@Dale: Thanks for the information! I don't want to use docmd.setwarnings, but I haven't been able to find a way around it (as per my previous post). If you have any additional information relevant to my situation where there are form-based criteria in the append query, I'd love to try it. Otherwise, I'll try out your ProcExit within the DoCmd.SetWarnings method.
You could always try the Passthrough query solution and get done with it.
@Jason,
Modified from my sample code above:
I usually give the parameters meaningful names and actually define them:
PARAMETERS [SomeDate] DateTime, [PONum] Text (15);
INSERT INTO tbl_Numbers ( TestDate, PONumber )
Values ([SomeDate], [PONum])
Modified from my sample code above:
Dim qdf as dao.querydef
set qdf = currentdb.querdefs("YourQueryName")
qdf.Parameters("SomeDate") = Forms!yourFormName.txt_SomeDate
qdf.Parameters("PONum") = Forms!yourFormName.txt_PONumber
qdf.Execute dbfailonError + dbSeeChanges
set qdf = nothing
I usually give the parameters meaningful names and actually define them:
PARAMETERS [SomeDate] DateTime, [PONum] Text (15);
INSERT INTO tbl_Numbers ( TestDate, PONumber )
Values ([SomeDate], [PONum])
As previously suggested, have you thought about building your SQL string in code - complete with the criteria pulled in from the form controls - and then putting it into your querydef and running with CurrentDB.Execute, or just running the SQL string with Currendb.Execute and be done with it. Best of both worlds....
ASKER
Sorry, guys, I'm self-taught on this and easily get lost in the lingo. I also get lost easily when attempting to apply an abstract concept to my specific scenerio especially when I'm not sure what's VBA programming code and what values are supposed to be changed to accommodate my circumstance.
@Dale, by parameters so you mean the criteria behind my append query? Here's my query: In the PowerlineF form, I'm selecting a Facility through [Forms]![PowerlineF]![cboF acilityID] criteria and selecting a Powerline through [Forms]![PowerlineF]![txtP owerlineUI D] criteria. This append query that is used for the insert is named "PowerlineF_PowerlineParti cipationAp pend" and activates nicely through the incorrect method discussed previously. I do believe if I can grasp this concept, I could apply it to other append queries I have.
@Mark, I don't understand what you mean by "SQL string in code". I'm all for using the most dependable and efficient method, but I have limited knowlege and I carry 100% support of this system so I need to fully understand how to implement. My named query method with the SetWarnings is VERY simple, but I'd like to learn from your experience and do this the right way. I'm interested in learning more about how you would specifically code this.
@Dale, by parameters so you mean the criteria behind my append query? Here's my query: In the PowerlineF form, I'm selecting a Facility through [Forms]![PowerlineF]![cboF
@Mark, I don't understand what you mean by "SQL string in code". I'm all for using the most dependable and efficient method, but I have limited knowlege and I carry 100% support of this system so I need to fully understand how to implement. My named query method with the SetWarnings is VERY simple, but I'd like to learn from your experience and do this the right way. I'm interested in learning more about how you would specifically code this.
Jason: The Querydef database objects (the ones you see in the Queries pane of the Navigation Pane), are just graphical "screens" for putting together SQL strings to run. If you put your query in Design View as you have shown in your screenshot, what you are seeing is the Builder pane of the querydef. If, however, you put the querydef in the SQL View, then you will see the actual SQL string that the builder pane built. It is the SQL that is actually executed. If you have the SQL string, you don't need the querydef object unless you added parameters to it or an ODBC connection string.
However, the Builder pane is limited in what it can "build" as far as creating SQL strings. Sometimes you need to add an element to your string that the builder just can't do, such as unionizing two queries together:
SELECT [Field1] FROM [Query1]
UNION
SELECT [Field1] FROM [Query2]
- that can only be built in SQL View.
You can build an SQL query string in code, complete with anything you need to add, and, if the querydef object will accept it, you can set the querydef .SQL property to the SQL string, or just execute the string - don't need the querydef. For example:
Dim strSQL as string
strSQL="SELECT * FROM [MyTableName] WHERE [Field1]='" & forms("myForm").cboMyCombo box & "'"
Where [Field1] is a text field (string). If the value in the combobox is "xyz", then when the code runs, you have:
strSQL="SELECT * FROM [MyTableName] WHERE [Field1]='xyz'"
You can then put it into the querydef:
CurrentDB.querydefs("Myque rydefname" ).SQL = strSQL
and then run the query:
CurrentDB.Execute "Myquerydefname"
or just execute the SQL string.
CurrentDB.Execute strSQL
Hope that helps...
However, the Builder pane is limited in what it can "build" as far as creating SQL strings. Sometimes you need to add an element to your string that the builder just can't do, such as unionizing two queries together:
SELECT [Field1] FROM [Query1]
UNION
SELECT [Field1] FROM [Query2]
- that can only be built in SQL View.
You can build an SQL query string in code, complete with anything you need to add, and, if the querydef object will accept it, you can set the querydef .SQL property to the SQL string, or just execute the string - don't need the querydef. For example:
Dim strSQL as string
strSQL="SELECT * FROM [MyTableName] WHERE [Field1]='" & forms("myForm").cboMyCombo
Where [Field1] is a text field (string). If the value in the combobox is "xyz", then when the code runs, you have:
strSQL="SELECT * FROM [MyTableName] WHERE [Field1]='xyz'"
You can then put it into the querydef:
CurrentDB.querydefs("Myque
and then run the query:
CurrentDB.Execute "Myquerydefname"
or just execute the SQL string.
CurrentDB.Execute strSQL
Hope that helps...
Your issue is part of a bigger issue with Access. Access has a "low/no code" app building capability that a lot of people first learn and try to use because, well.... that's how every Access how-to book is built - learn the built-in wizards, builder and such so you don't have to code.
BUT! These wizards, builders, and such have limited capability when it comes to doing everything you want, so a lot of app builders start getting an itch to start using VBA to be able to do what the built-in stuff can't.
I didn't start using VBA until I switched from Access to Visual Studio and VB3 early in my career. When .Net came out, it had some issues with it so I decided to work with Access for awhile until they fixed .Net. When I got into the VBA IDE, I immediately recognized that it looked a lot like Visual Studio! So, I thought.... I wonder if I can do here some of the things I did in Visual Studio? and guess what? I COULD! That opened up a whole new world to me and I've been able to make a go of VBA development as a career ever since.
BUT! These wizards, builders, and such have limited capability when it comes to doing everything you want, so a lot of app builders start getting an itch to start using VBA to be able to do what the built-in stuff can't.
I didn't start using VBA until I switched from Access to Visual Studio and VB3 early in my career. When .Net came out, it had some issues with it so I decided to work with Access for awhile until they fixed .Net. When I got into the VBA IDE, I immediately recognized that it looked a lot like Visual Studio! So, I thought.... I wonder if I can do here some of the things I did in Visual Studio? and guess what? I COULD! That opened up a whole new world to me and I've been able to make a go of VBA development as a career ever since.
If you want an idea of what you can do with VBA that the built-in stuff can't, watch my youtube video for some ideas:https://www.youtube.com/wa tch?v=-A8f u--aa6k
ASKER
Wow! Great points, Mark. Very helpful! I'll try to apply some of your instructions to my coding.
ASKER
I got a compile error when trying to apply your directions. Please see code below. Also, how would I change this for integer fields. Both of my ID fields are integer.
Private Sub txtFacilityID_AfterUpdate()
strSQL = "SELECT * FROM [MyTableName] WHERE [FacilityID]='" & Forms("FacilityProductionDetailedF").txtFacilityID & "'" and [ProjectID] ='" & Forms("FacilityProductionDetailedF").txtProjectID & "'"
CurrentDb.QueryDefs("FacilityProductionDetailedParticipationAppend").sql = strSQL
CurrentDb.Execute "FacilityProductionDetailedParticipationAppend"
'DoCmd.SetWarnings False
'DoCmd.OpenQuery ("FacilityProductionDetailedParticipationAppend")
'DoCmd.SetWarnings True
txtFacilityID = Null
Requery
End Sub
ok. First "MyTableName" means "put-your-table-name-here" Do you actually have a table named "[MyTableName]" in your db? If not, you get the picture.
Also, the sample query SQL I gave was for example. I don't know what the SQL is in your query. The sample SQL I gave is a SELECT query (displays records) that pulls all fields from what ever table name you put in place of "MyTableName". What does the actual SQL in your querydef look like? I would need it if you need YOUR SQL shown how to build it as a string SQL.
Tip: Get use to seeing contributors post sample SQL with "fillers" that take the place of what you would actually use because they don't know what you have. You are expected to recognize the need for substitution, or include your SQL and other data so the others know what you have and can use it.
Since you are filtering on number fields, you would not put single quote characters at each end of your filter insert. Instead you would:
& "#"
Make sure you don't replace you original SQL in your querydef with a sample SQL unless you have a copy of the original SQL. Otherwise, you'll be re-creating your query from scratch.
Once you get the hang of it, you'll wonder how you ever got by without it!
Also, the sample query SQL I gave was for example. I don't know what the SQL is in your query. The sample SQL I gave is a SELECT query (displays records) that pulls all fields from what ever table name you put in place of "MyTableName". What does the actual SQL in your querydef look like? I would need it if you need YOUR SQL shown how to build it as a string SQL.
Tip: Get use to seeing contributors post sample SQL with "fillers" that take the place of what you would actually use because they don't know what you have. You are expected to recognize the need for substitution, or include your SQL and other data so the others know what you have and can use it.
Since you are filtering on number fields, you would not put single quote characters at each end of your filter insert. Instead you would:
WHERE [FacilityID] = " & Forms("FacilityProductionDetailedF").txtFacilityID & " and [ProjectID] = " & Forms("FacilityProductionDetailedF").txtProjectID
The single quotes at each end in the sample are if you are using a string to filter a text field. If it was a date or time data type field, you would use "#" signs as in [MyDateField]=#" & forms("myForm").txtTextboxMake sure you don't replace you original SQL in your querydef with a sample SQL unless you have a copy of the original SQL. Otherwise, you'll be re-creating your query from scratch.
Once you get the hang of it, you'll wonder how you ever got by without it!
ASKER
Sorry about that. I didn't even notice MyTableName when using the code. Thanks for the help.
My query is an "Append" query. So should I replace the word SELECT with the word APPEND?
My query is an "Append" query. So should I replace the word SELECT with the word APPEND?
ASKER
I'll repost my actual query and the SQL to help avoid any confusion.
INSERT INTO FacilityProjectParticipationT ( FacilityID, FacilityProjectID )
SELECT FacilityT.FacilityID, FacilityProjectT.ProjectID
FROM FacilityT, FacilityProjectT
WHERE (((FacilityT.FacilityID)=[Forms]![FacilityProductionDetailedF]![txtFacilityID]) AND ((FacilityProjectT.ProjectID)=[Forms]![FacilityProductionDetailedF]![txtProjectID]));
ASKER
I get Run-time error '3075'
Syntax error (missing operator) in query expression '*WHERE [FacilityID] = 2221 and [ProjectID] = 12410'.
Row-3 was highlighted.
This is my code:
Syntax error (missing operator) in query expression '*WHERE [FacilityID] = 2221 and [ProjectID] = 12410'.
Row-3 was highlighted.
This is my code:
Private Sub btnADD_Click()
strSQL = "SELECT * WHERE [FacilityID] = " & Forms("FacilityProductionDetailedF").txtFacilityID & " and [ProjectID] = " & Forms("FacilityProductionDetailedF").txtProjectID
CurrentDb.QueryDefs("FacilityProductionDetailedParticipationAppend").sql = strSQL
CurrentDb.Execute "FacilityProductionDetailedParticipationAppend"
'DoCmd.SetWarnings False
'DoCmd.OpenQuery ("FacilityProductionDetailedParticipationAppend")
'DoCmd.SetWarnings True
txtFacilityID = Null
Requery
End Sub
Your SQL Query is missing the FROM clause: Its: "SELECT * FROM [Tablename] WHERE [Field1]=123"
Since you supplied your code, I'll build your SQL string for you:
I noticed that you don't have any links between your two tables, resulting in a "cartesian" query. Is there any field in one table that you need to match to in the other table?
Since you supplied your code, I'll build your SQL string for you:
strSQL = "INSERT INTO FacilityProjectParticipationT ( FacilityID, FacilityProjectID )" _
& vbCrLf & "SELECT FacilityT.FacilityID, FacilityProjectT.ProjectID" _
& vbCrLf & "FROM FacilityT, FacilityProjectT" _
& vbCrLf & "WHERE ( ((FacilityT.FacilityID)=" & [Forms]![FacilityProductionDetailedF]![txtFacilityID] & ") AND ((FacilityProjectT.ProjectID)=" & [Forms]![FacilityProductionDetailedF]![txtProjectID] & "));"
See if that works...I noticed that you don't have any links between your two tables, resulting in a "cartesian" query. Is there any field in one table that you need to match to in the other table?
By the way, Jason, what are you using to learn Access programming and database building? An Access book? An online course? Winging it?....
ASKER
Thanks! There's nothing between those two queries that's related. It was the only way I knew to make it work. It seemed to work well, so I just went with it.
I tried the code you provided. I didn't get an error, but nothing seemed to have executed. I checked the table it was supposed to append to and there were no new records.
I learned a basic understanding of Access through AccessLearningZone.com, but I've gotten most of my program built by researching discussion boards.
I tried the code you provided. I didn't get an error, but nothing seemed to have executed. I checked the table it was supposed to append to and there were no new records.
I learned a basic understanding of Access through AccessLearningZone.com, but I've gotten most of my program built by researching discussion boards.
Here's another tip: Since you are putting your SQL in a query def object, you can open the querydef and just run the SELECT part to see if you are pulling any records to put in your append table.
With you querydef in Design View, click the table grid button to the left of the red exclamation point at the left-end of the Design ribbon. That will ignore the INSERT clause and just run the SELECT part of the query. Do you get any records?
With you querydef in Design View, click the table grid button to the left of the red exclamation point at the left-end of the Design ribbon. That will ignore the INSERT clause and just run the SELECT part of the query. Do you get any records?
I just thought of something.... If your code ran the DoCmd.SetWarnings False, but threw an error before executing the DoCmd.SetWarning True, then you've turned off warnings and not turned 'em back on. Add a
DoCmd.SetWarnings True
at the beginning of your code to make sure you have them on. It won't hurt anything...
DoCmd.SetWarnings True
at the beginning of your code to make sure you have them on. It won't hurt anything...
ASKER
Thanks! I'll try the SELECT tomorrow!
Side note:
And since queries tend to becomes long quickly, this kind of "facility" becomes a nuisance (good luck finding that missing or duplicated quote within soo many lines of invalid text).
Instead, I recommend concatenating with several instructions:
strSQL = "INSERT INTO FacilityProjectParticipatiI do not recommend using the _ (underscore) character within your multiline instructions, for the simple reason that one little mistake within you strings concatenation will toggle the whole instruction (4 lines in this specific case, this is long already) as invalid (it will show up in red in the VBE editor).onT ( FacilityID, FacilityProjectID )" _
& vbCrLf & "SELECT FacilityT.FacilityID, FacilityProjectT.ProjectID" _
& vbCrLf & "FROM FacilityT, FacilityProjectT" _
& vbCrLf & "WHERE ( ((FacilityT.FacilityID)=" & [Forms]![FacilityProductionDetailedF ]![txtFaci lityID] & ") AND ((FacilityProjectT.Project ID)=" & [Forms]![FacilityProductio nDetailedF ]![txtProj ectID] & "));"
And since queries tend to becomes long quickly, this kind of "facility" becomes a nuisance (good luck finding that missing or duplicated quote within soo many lines of invalid text).
Instead, I recommend concatenating with several instructions:
strSQL = vbNullString
strSQL = strSQL & "INSERT INTO FacilityProjectParticipationT ( FacilityID, FacilityProjectID )" & vbcrlf
strSQL = strSQL & "SELECT FacilityT.FacilityID, FacilityProjectT.ProjectID" & vbcrlf
strSQL = strSQL & "FROM FacilityT, FacilityProjectT" & vbcrlf
strSQL = strSQL & "WHERE ( ((FacilityT.FacilityID)=" & [Forms]![FacilityProductionDetailedF]![txtFacilityID] & ") AND ((FacilityProjectT.ProjectID)=" & [Forms]![FacilityProductionDetailedF]![txtProjectID] & "));"
If there is an invalid instruction somewhere, only one line will show up as invalid (it is easyer to fix one small line, than one spanning over a bunch of lines).
For those of you who might not know how compile errors work in underscored (continued) code lines, here's an example. If there is a compile error, Access will highlight the first item in the string that violates the compile. Can you find the offending typo below?
No? It's the first double-quote character in the second line, which causes the FROM to be interpreted not as a string, but code.
Now if the whole SQL string compiles, but the whole SQL string fails when run, then that's a different issue altogether. It doesn't matter what string building technique you use, you're still going to have to use the clues in the error message to find the offending part.
No? It's the first double-quote character in the second line, which causes the FROM to be interpreted not as a string, but code.
Now if the whole SQL string compiles, but the whole SQL string fails when run, then that's a different issue altogether. It doesn't matter what string building technique you use, you're still going to have to use the clues in the error message to find the offending part.
This question needs an answer!
Become an EE member today
7 DAY FREE TRIALMembers can start a 7-Day Free trial then enjoy unlimited access to the platform.
View membership options
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.