Thanks in advance everyone, Im using vba and MS Access 2016 to work on a restaurant's db.
I need to open a table to get a record which is a table name that I then need to open, its kinda messy but I thought I had it until I started getting the 3078 error. (Btw I just started using access for this project so it could be a simple syntax error I don't see)
The db im working on was made in a half assed way unfortunately so it isn't quietly consistent or well formated and it is half in spanish half in english however I'm sure the table name is correct and exists. If I put the query in access instead of vba and with the name instead of a variable it works just fine. Here's the code.
Sub QRventas()
Dim ventas As DAO.Recordset
Dim qrv As String
'Query daily sales
qrv = (SELECT menus.id, menus.descripcion, Sum(Nz(ComandasD.cantidad)) AS Total FROM ~~long and ugly but working query)
Set ventas = CurrentDb.OpenRecordset(qrv)
Dim receta As DAO.Recordset
Dim qrr As String
Do While Not ventas.EOF
'QR recipes
ventas.MoveNext
qrr = "SELECT ID, Ingredientes, Cantidad FROM [" & ventas(1) & "] GROUP BY ID, Ingredientes, Cantidad;" '<- Error Here
Set receta = CurrentDb.OpenRecordset(qrr) '<- Complains here 3078
Do While Not receta.EOF
'Updating Storage
CurrentDb.Execute "UPDATE Almacen " _
& "SET Cantidad_almacenada = Cantidad_almacenada - (cantidad * Total) " _
& "WHERE ID = " & receta(1) & ";"
receta.MoveNext
Loop
Loop
End Sub
possibly 'Fields' is missing:
qrr = "SELECT ID, Ingredientes, Cantidad FROM [" & ventas.Fields(1) & "]...
If Access complains that the table isn't there, it isn't.
Or, specifically use the Value property of the field.
So insert a debug line and study which table name it was supposed to find:
'QR recipes
ventas.MoveNext
Debug.Print "[" & ventas(1) & "]"
qrr = "SELECT ID, Ingredientes, Cantidad FROM [" & ventas(1).Value & "] GROUP BY ID, Ingredientes, Cantidad;" '<- Error Here
I tried the answers that people posted here but had no luck with them, then I did a "Compact and Repair" and the issue went away...
Thanks everyone again.
Related
I am told (and agree) that it is better to replace the SQL in an existing querydef, rather than delete and re-define the querydef each time the query needs to change. But my code only seems to work the second way. Here is the code I have that works:
Dim db As Database
Set db = CurrentDb
Dim QD As QueryDef
Dim mySql As String
mySql = ""
mySql = "TRANSFORM COUNT(tblDocs.Document) AS CountOfDocument " & _
"SELECT tblDocs.[Contractor Dept], " & _
"COUNT(tblDocs.Document) AS [Total Of Document] " & _
"FROM tblDocs " & _
"GROUP BY tblDocs.[Contractor Dept] " & _
"PIVOT tblDocs.[Engineering Status Code]"
On Error Resume Next
db.QueryDefs.Delete "qryX" 'Remove temporary query if exists
Set QD = db.CreateQueryDef("qryX", mySql) 'create temporary query
DoCmd.RunSQL "SELECT * INTO tblDocsCrossTabX FROM qryX;"
Here is the code I can't get to work
Dim db As Database
Set db = CurrentDb
Dim QD As QueryDef
Dim mySql As String
mySql = " "
Set QD = db.CreateQueryDef(("qryX"), mySql)
mySql = "TRANSFORM COUNT(tblDocs.Document) AS CountOfDocument " & _
"SELECT tblDocs.[Contractor Dept], " & _
"COUNT(tblDocs.Document) AS [Total Of Document] " & _
"FROM tblDocs " & _
"GROUP BY tblDocs.[Contractor Dept] " & _
"PIVOT tblDocs.[Engineering Status Code]"
QD.SQL = mySQL 'overwrite query SQL
DoCmd.RunSQL "SELECT * INTO tblDocsCrossTabX FROM qryX;"
Oddly, the second version doesn't throw any errors at me, but it doesn't make the crosstab table at all.
Edit: Maybe I wasn't clear enough. The problem is that the second set of code Does. Not. Execute. The. SQL. If it executed the code, I would be happy to re-write and use the same temp query over and over, but it does. not. execute. the. SQL..
Please respond with how to make the code in the second block actually execute the indicated SQL statement and build the desired table.
I know I have to remake a query if I delete it. Duh.
I know I "should" be able to re-use the same query if I can get the Set statement to properly overwrite the previous sql with the desired sql.
I know you all want to provide an answer, but please make it an answer to the question I am asking.
You can recycle the object if you don't delete it:
' On Error Resume Next
Set QD = db.QueryDefs("qryX")
QD.SQL = mySQL
DoCmd.RunSQL "SELECT * INTO tblDocsCrossTabX FROM qryX;"
Solved.
In the first block of code, when I delete and recreate the query, the string mySql contains a valid SQL statement, so Access is able to assign that SQL to the querydef when I completely recreate it with SET. Specifically,
mySql = "Transform..."
Comes Before
Set QD = db.CreateQueryDef("qryX", mySql)
In the second set of code, the string mySql contains only a space when the Set command is used, as " " is not a valid SQL Statement, the Set command won't even get executed, and the QueryDef QD never even gets created.
Specifically, the error in the second code occurs because
mySql = " " 'NOT a valid SQL Statement
comes before the attempt to create the queryDef
Set QD = db.CreateQueryDef(("qryX"), mySql) 'QD never gets created because mySql is not valid SQL
preventing the assignment of a valid SQL statement later, and so no table gets created.
If you can use a subquery, you can use a tempory QueryDef instead of bothering with checking forQueryDefalready existing or not, just combine the SELECT and the INSERT-Query to use a temporaryQueryDef
Unfortunally you can't useTransformin a subquery so this code leads toRuntime-Error 3129 Invalid SQL statement.
Sql = "SELECT * INTO tblDocsCrossTabX FROM (TRANSFORM COUNT(tblDocs.Document) AS CountOfDocument " & _
"SELECT tblDocs.[Contractor Dept], " & _
"COUNT(tblDocs.Document) AS [Total Of Document] " & _
"FROM tblDocs " & _
"GROUP BY tblDocs.[Contractor Dept] " & _
"PIVOT tblDocs.[Engineering Status Code])"
With CurrentDb.CreateQueryDef(vbNullString) 'or db.CreateQueryDef("") creates a not named and therefore temporary QueryDef
.SQL = Sql
.Execute dbFailOnError
End With
Sample of successful code.
Dim db As Database
Set db = CurrentDb
Dim QueryString As String
Dim QDDocsCross As QueryDef
Set QDDocsCross = db.CreateQueryDef("DocsCross")
QueryString = "TRANSFORM COUNT(Docs.Document) AS CountOfDocument " & _
"SELECT Docs.[Contractor Dept], " & _
"COUNT(Docs.Document) AS [Total Of Document] " & _
"FROM Docs " & _
"GROUP BY Docs.[Contractor Dept] " & _
"PIVOT Docs.[Engineering Status Code]"
QDDocsCross.SQL = QueryString
So I have been scratching my head for awhile on this issue and although it seems simple in theory I am having a tough time implementing it in VBA.
Some background on the project will be needed to understand what i am trying to do
So our database/application is meant to keep track of how we test a version of software, what the results are, and if the tests were done properly. we have a specific set of scripts that we use from version to version.
In the database we have a table that list these scripts without assigning them to a specific version of software.
then we have a form where you select the version of software you are running against.
here is the problem i am encountering
when you have selected a software version I want to have a button that you click and it takes all the associated test scripts copies them and assigns the selected software version IF THIS HASNT BEEN DONE YET. this will allow you to make notes for the specific script that can differ from version to version.
I am currently trying to do this with a union query and have experimented with using the append query but haven had any luck, with the code snippet that i am putting below the results i get when i click the button to execute the assigning of the software version it alerts the proper "Test Script", PROC_CHECK_ID and "Software Version" but then i get a strange prompt that sais "Enter Paramater Value" and it sais the "Test Script Name" with a text field, this goes into an infite loop where i can just keep entering values in the text field.
Here is my code
Dim rs1 As DAO.Recordset
Dim unionquery As String
Dim CURRENT_SOFTWARE_VERSION As String
CURRENT_SOFTWARE_VERSION = Me.Parent.[Software Version].Value
unionquery = "select [Test Script] , [PROC_CHECK_ID], [Software Version] from (FORMAL_CERT_PROCEDURE_TEST_SCRIPTS inner join FORMAL_CERT_PROCEDURE_CHECK on FORMAL_CERT_PROCEDURE_TEST_SCRIPTS.TEST_CASE_ID = FORMAL_CERT_PROCEDURE_CHECK.TEST_CASE_ID) inner join FORMAL_CERT_SOFTWARE_VERSION on FORMAL_CERT_PROCEDURE_TEST_SCRIPTS.TEST_CASE_ID = FORMAL_CERT_SOFTWARE_VERSION.TEST_CASE_ID where PROC_CHECK_ID=" & Me.PROC_CHECK_ID & " AND [Software Version]=""" & CURRENT_SOFTWARE_VERSION & """ "
' Debug.Print unionquery
Set rs1 = CurrentDb.OpenRecordset(unionquery, dbOpenForwardOnly)
If Not (rs1.EOF And rs1.BOF) Then
Do Until rs1.EOF = True
' MsgBox " " & rs1![Test Script] & ", " & rs1![PROC_CHECK_ID] & ", " & rs1![Software Version] & " "
INSERT_INTO_TEST_SCRIPTS = "insert into FORMAL_CERT_PROCEDURE_TEST_SCRIPTS([Test Script], [PROC_CHECK_ID_FK], [Software_Version], [TEST_CASE_ID]) values(" & rs1![Test Script] & ", " & rs1!PROC_CHECK_ID & ", " & rs1![Software Version].Value & ", " & Me.TEST_CASE_ID & ")"
' APPEND QUERY THAT THROWS INTO AN INFINITE LOOP *NEEDS WORK* INSERT_INTO_TEST_SCRIPTS = "INSERT INTO FORMAL_CERT_PROCEDURE_TEST_SCRIPTS([Test Script], [PROC_CHECK_ID_FK], [Software_Version], [TEST_CASE_ID]) SELECT FORMAL_CERT_PROCEDURE_TEST_SCRIPTS.[Test Script], " & rs1!PROC_CHECK_ID & ", " & rs1![Software Version].Value & ", FORMAL_CERT_PROCEDURE_TEST_SCRIPTS.TEST_CASE_ID FROM FORMAL_CERT_PROCEDURE_TEST_SCRIPTS WHERE FORMAL_CERT_PROCEDURE_TEST_SCRIPTS.TEST_CASE_ID = " & Me.TEST_CASE_ID & " "
DoCmd.SetWarnings False
DoCmd.RunSQL INSERT_INTO_TEST_SCRIPTS
DoCmd.SetWarnings True
rs1.MoveNext
Loop
End If
I appreciate any help and am willing to completely rework this mechanic, i am probably over complicating this : /
thanks!
Your first SELECT query (unionquery) has quotes around the value for [Software Version], indicating that it is a text field. However, your subsequent INSERT query (INSERT_INTO_TEST_SCRIPTS) omits the quotes. Therefore, the INSERT query is treating the value you are trying to insert as the name of some other field, and since no other field exists with that name you are getting the parameter prompt.
Your code might be a bit cleaner (and more reliable) if you did a Recordset insert instead of "gluing together" an INSERT statement. That approach would look something like this:
Dim rs2 As DAO.Recordset
Set rs2 = CurrentDb.OpenRecordset( _
"SELECT * FROM FORMAL_CERT_PROCEDURE_TEST_SCRIPTS", _
dbOpenDynaset)
rs2.AddNew
rs2![Test Script] = rs1![Test Script]
rs2![PROC_CHECK_ID_FK] = rs1!PROC_CHECK_ID
rs2![Software_Version] = rs1![Software Version]
rs2![TEST_CASE_ID] = Me.TEST_CASE_ID
rs2.Update
rs2.Close
Set rs2 = Nothing
I have been facing the error 3061 with error message "Too few Parameters: Expected 2". I have done all of the following to resolve the issue but still couldn't it.
I ran the query in SQL mode and it gives me result
I checked all the field names
I checked all the "&" s are placed. I find them correct.
Here is my code:
Private Sub cmbYear_Change()
Dim db As Database
Dim rs As DAO.Recordset
Dim Query As String
Query = " SELECT Yrs_Teaching, Highest_Edu, AD_Descr FROM ClassSurvey" & _
" WHERE ClassSurvey.Program/School_ID = " & Me.cmbProgId.Value & _
" AND ClassSurvey.ClassID = " & Me.cmbClassId.Value & _
" AND ClassSurvey.Teacher_ID = " & Me.cmbTeacherID.Value & _
" AND ClassSurvey.SYear = " & Me.cmbYear.Value
Set db = CurrentDb
Set rs = db.OpenRecordset(Query)
If rs.RecordCount > 0 Then
Me.TB1 = rs!Yrs_Teaching
Me.TB2 = rs!Highest_Edu
Me.TB3 = rs!AD_Descr
Else
Me.TB1 = "N/A"
End If
Set rs = Nothing
Set db = Nothing
End Sub
It appears your table includes a field named Program/School_ID. Bracket that field name in the SELECT statement so the db engine can properly recognize it as one field name.
That change might be all you need. But if you have another problem, give yourself an opportunity to examine the completed SELECT statement you're giving to the db engine. It might not be what you expect.
Dim db As Database
Dim rs As DAO.Recordset
Dim strQuery As String
strQuery = "SELECT cs.Yrs_Teaching, cs.Highest_Edu, cs.AD_Descr FROM ClassSurvey AS cs" & _
" WHERE cs.[Program/School_ID] = " & Me.cmbProgId.Value & _
" AND cs.ClassID = " & Me.cmbClassId.Value & _
" AND cs.Teacher_ID = " & Me.cmbTeacherID.Value & _
" AND cs.SYear = " & Me.cmbYear.Value
Debug.Print strQuery
Set db = CurrentDb
Set rs = db.OpenRecordset(strQuery)
If you get an error, you can go to the Immediate window (Ctrl+g), copy the statement text from there, open a new query in the query designer, switch to SQL View, paste in the statement text and try running it there. This tip is especially useful when the db engine complains about a missing parameter because when you try to run the query from the designer, Access will show you an input box asking you to supply a value and that box also contains the name of whatever Access thinks is the parameter.
I came across this when I was looking for a solution to the same problem. Turns out one of the values from a control on the form was not passing the value to the statement, sending it to the debug window (Debug.print) helped me spot the problem after a long time because I was using a global variable which the sql query was parsing. So load your controls' values into variables first!
This error may be because the column names in the query have special characters. Try surrounding the column names with square brackets in the SQL query. Column name with special symbols should be within square brackets and variables should be inside single quotes.
I had this issue too, I realized it was because I did not put quotes around my variables.
This was fixed by adding '& Chr(34)' around my variables
My fixed code looks like:
TextProducer = [Forms]![MyFormName]![TextInputBoxName]
strQuery = "SELECT FILEMASK" & _
" FROM TABLE_NAME" & _
" WHERE Producer = " & Chr(34) & TextProducer & Chr(34)
I have a small query builder on a form I created that allows the user to save the query they built. Works great! Then I realized that they can save multiple queries using the same name. Not good. What I'm doing is when they build the query and choose to save it, I just add the SQL string to a table in one field and a name, that they choose, in another field. Easy enough. So now I figure all I have to do search the Name field and check it against the name the user has chosen. I dont know why, but I cant seem to wrap my mind around it. I can't seem to get the FindRecord to work. Does it return a boolean? Can't I just do something like this...
If DoCmd.FindRecord(userNameVariable) = True Then
msgbox("That name exists")
Else
msgbox(That name doesnt exist)
End If
Now that I look at that, it doesn't give any where to look, such as the table and field name.
DoCmd.FindRecord returns the first record found with that criteria. If you only want to check if that name already exists I think that there is a better way to do what you need.
One way is to build a SQL string like
"SELECT [Name] FROM [Table] WHERE [Name] = '" & userNameVariable & "'",
execute the Query and then test if the recordset is empty. The Code would look like
Dim rs as recordset
Dim strSQL as string
strSQL = "SELECT [Name] FROM [Table] WHERE [Name] = '" & userNameVariable & "'"
Set rs = CurrentDb.OpenRecordset(strSQL)
If rs.RecordCount > 0 Then
msgbox "This Query name already exists, please select another"
End If
According to msdn, it simply goes to the data you searched for. I don't think that's what you need.
Here's what I would do (I'm not saying it's the best method, just what I would do). Assuming the table is called TblName and the field holding the saved name is SQLName then:
If CurrentDb.OpenRecordset( _
"Select count(*) from TblName where SQLName='" & SQLName & "';") _
.Fields(0) > 0 Then
'Do Something
End If
Saved query names are stored in the unsupported MSysObjects table, so in a local database you can look up that table to find if a query exists:
If IsNull(DLookup("name", "msysobjects", "name='" _
& qryname & "' and type=5")) Then
Set qdf = CurrentDb.CreateQueryDef(qryname, sSQL)
Else
MsgBox qryname " already exists."
End If
My wife wrote the following code and it used to work fine for her when her organization used Access 2007. They just updated to Access 2010 and it no longer works. I am not familiar with Access at all but I suggested I'd present it to Stack to see if you guys can see anything straight off that won't work in Access 2010. Thanks in advance for any insights.
Private Sub Originating_Zone_AfterUpdate()
Dim EscortDB As DAO.Database
Dim rstBldgs As DAO.Recordset
Set EscortDB = CurrentDb()
Set rstBldgs = EscortDB.OpenRecordset("SELECT BuildingName FROM" & _
" ZoneBldgLookup WHERE ZoneLocation = '" & _
Forms!DateID!EscortIDSubform.Form.[Originating Zone] & _
"' ORDER BY BuildingName", [dbOpenDynaset])
rstBldgs.MoveLast
rstBldgs.MoveFirst
Do Until rstBldgs.EOF
Forms!DateID!EscortIDSubform.Form.[Pick Up Location].AddItem rstBldgs!BuildingName
rstBldgs.MoveNext
Loop
rstBldgs.Close
End Sub
Update: She got it working using the following code. Thanks for your help!
Private Sub Originating_Zone_AfterUpdate()
Dim sBuildList As String
sBuildList = ("SELECT BuildingName FROM" & _
" ZoneBldgLookup WHERE ZoneLocation = '" & _
Forms!DateID!EscortIDSubform.Form.[Originating Zone] & _
"' ORDER BY BuildingName")
Forms!DateID!EscortIDSubform.Form.[Pick Up Location].RowSource = sBuildList
Forms!DateID!EscortIDSubform.Form.[Pick Up Location].Requery
End Sub
It's terrible code. Populating a dropdown list or listbox by walking a recordset and .AddItem is terribly inefficient. The whole thing can be done without code by simply assigning a SQL string to the Rowsource property of the combobox/listbox.
Now, clearly, the list changes based on the choices in the control to which this AfterUpdate event is attached, but all that means is that you assign the Rowsource in this event. Probably, all the above code can be replace with this:
Forms!DateID!EscortIDSubform.Form.[Pick Up Location].Rowsource = "SELECT BuildingName FROM" & _
" ZoneBldgLookup WHERE ZoneLocation = '" & _
Forms!DateID!EscortIDSubform.Form.[Originating Zone] & _
"' ORDER BY BuildingName"
I can't say what's wrong with the code not working (I suspect there's a sandbox mode/macro security issue going on), but it's way more lines of code than are needed.
In addition to #David-W-Fenton's suggestions, I think you should use a string variable to hold the SELECT statement. Then you can Debug.Print it to the Immediate Window, copy it to a new query (in SQL View), and make sure it actually returns rows.
Dim strSql As String
strSql = "SELECT BuildingName FROM" & _
" ZoneBldgLookup WHERE ZoneLocation = '" & _
Forms!DateID!EscortIDSubform.Form.[Originating Zone] & _
"' ORDER BY BuildingName"
Debug.Print strSql
Forms!DateID!EscortIDSubform.Form.[Pick Up Location].Rowsource = strSql
Also if this is code in the module of a form named DateID, you can replace Forms!DateID with the keyword Me (which is shorthand for "this form" ... the form which contains the code you're running). That's not dramatically shorter, but Me will not need to be changed if the form is ever re-named. Still not a big deal ... just one less detail you won't have to fiddle with down the road.