I have a query that i wan't to use in Application.ExportXML. But the query expects a parameter, this parameter has to be a value of textbox in my form. Right now i have something like this.
sql = "SELECT * FROM Reports WHERE Reports.Ref_Q ='" & txtRef & "';"
Set qd = CurrentDb.QueryDefs("getReports")
qd.sql = sql
Application.ExportXML acExportQuery, getReports, strPath
When I run this code i get the following error:
The command or action '|' isn't avaible now
I als tried doing it like this
Set qd = CurrentDb.QueryDefs("getReports")
qd.Parameters("prm") = txtRef.Value
But then the prompt screen for the parameter keeps comming on the screen.
Set qd = CurrentDb.QueryDefs("getReports") is expecting to find a saved query called getReports, which may not exist.
You would need something like:
sql = "SELECT * FROM Reports WHERE Reports.Ref_Q ='" & txtRef & "';"
Set qd = CurrentDb.CreateQueryDef("getReports", sql)
DB.QueryDefs.Refresh
Application.ExportXML acExportQuery, getReports, strPath
Or:
sql = "SELECT * FROM Reports WHERE Reports.Ref_Q = [prm];"
Set qd = CurrentDb.CreateQueryDef("getReports", sql)
qd.Parameters("[prm]") = txtRef.Value
DB.QueryDefs.Refresh
Application.ExportXML acExportQuery, getReports, strPath
DB.QueryDefs.Refresh is usually necessary, as without it, Access won't find your newly created query.
Using parameters is preferable when you need to reuse the query lots of times with different parameters, as creating a query has more overhead than just calling it with a different parameter.
You might want to add a DB.QueryDefs.Delete "getReports" if you don't want your query hanging around.
Related
I am trying to run this code to fire an update query from VBA. Access is giving me a syntax error. I suspect this has to do with the fact that I'm trying to run an update query using an INNER JOIN with a form. Is what I'm trying to do at all possible?
Private Sub Btn_Edit_Data_Click()
Dim db As DAO.Database
Dim UpdateQdf As DAO.QueryDef
Dim UpdateSQL As String
Set db = CurrentDb()
Set UpdateQdf = db.QueryDefs("Qry_Update_Counterparty_Data")
UpdateSQL = "UPDATE Repository_Redux INNER JOIN [Forms]![Frm_Reject_Button] ON Repository_Redux.[Counterparty ID] = [Forms]![Frm_Reject_Button]![Txt_CP_ID] " & _
"SET Repository_Redux.[Counterparty Name] = [Forms]![Frm_Reject_Button]![Txt_CP_Name_Edit]"
UpdateQdf.SQL = UpdateSQL
DoCmd.OpenQuery "Qry_Update_Counterparty_Data"
Set db = Nothing
Set qdf = Nothing
End Sub
I solved it this way, thanks everyone:
UpdateSQL = "UPDATE Repository_Redux SET Repository_Redux.[Counterparty Name] = [Forms]![Frm_Reject_Button]![Txt_CP_Name_Edit] WHERE Repository_Redux.[Counterparty ID] = [Forms]![Frm_Reject_Button]![Txt_CP_ID]"
Just a suggestion, I've not tried this...
On your form you have have an event handler that stores in a global variable (yes, I know that's dodgy) the values from your form that you intend to use in the query. Then you can define a function that reads the global variable. Then you can use the function in the SQL query.
Let us know how you get on.
Googling suggests other have tried this
Global Variable as query parameter - PC Review
How to put global variable name in query
Anybody else got a better "global state machine" to bridge the form to the SQL?
No, you can never join a form in a query (or SELECT FROM a form, for that matter). You can only join in tables or other queries.
You can, however, try to join in a forms record source.
I am trying to run an Update Query in VBA and am at a lost as to what I'm supposed to write for the code. I'm running a query to find the most recent date from a table. That query works fine. Now I want to run an update query to update another table's date field to equal to the date that was queried. Here is what I have:
Dim Date1 As Date
Dim newdate1
'selects datadate 1
Date1 = CurrentDb.OpenRecordset("Select Max(Date1_Event) from TBL_Event WHERE ID = '" & [Forms]![FRM_Main]![ID] & "'")(0)
'update datadate 1
newdate1 = CurrentDb.OpenRecordset("Update Tbl_Name set CollectionDate = DataDate1 WHERE PID = '" & [Forms]![FRM_Main]![ID] & "'")(0)
Is there a way to run an update query like this? Thank you.
Action queries (DELETE, UPDATE, INSERT INTO) are to be executed (CurrentDb.Execute) while SELECT queries are to be opened as recordsets (CurrentDb.OpenRecordset).
Additionally, consider using parameterization to avoid any need of quote enclosure or string concatenation in query. And here the max date is calculated with domain aggregate, DMax(), instead of opening another query.
Dim strSQL As String
Dim qdef As Querydef
' PREPARE SQL STATEMENT
strSQL = "PARAMETERS [MaxDateParam] Date, [FormIDParam] Long;" _
& "UPDATE Tbl_Name SET CollectionDate = [MaxDateParam]" _
& " WHERE PID = [FormIDParam];"
' BUILD TEMP QUERY
Set qdef = CurrentDb.CreateQueryDef("", strSQL)
' BIND PARAMETERS
qdef!MaxDateParam = DMax("Date1_Event", "TBL_Event", "ID=" & [Forms]![FRM_Main]![ID])
qdef!FormIDParam = [Forms]![FRM_Main]![ID]
' EXECUTE ACTION
qdef.Execute dbFailOnError
Set qdef = Nothing
Though above may look unusual and slightly more lines. Don't be intimidated and run for the easy 1-2 lines. Parameterization is a programming industry best practice not just in VBA but across all general purpose languages that run dynamic SQL queries using values from user input.
I have a form in which one of the ComboBoxes lists all the documents of a given project. The user should select one and after pressing a button, and if present in Table Dessinsit opens a second form showing that record. If it is not present in that table, I want to add it in.
One of my collegues told me all I had to do was to execute an SQL query with VBA. What I have so far is this:
Dim rsDessin As DAO.Recordset
Dim strContrat As String
Dim strProjet As String
Dim strDessin As String
Dim sqlquery As String
'I think these next 3 lines are unimportant. I set a first query to get information I need from another table
strDessin = Me.Combo_Dessin
strProjet = Me.Combo_Projet
sqlquery = "SELECT [Projet HNA] FROM [Projets] WHERE [Projet AHNS] = '" & strProjet & "'"
Set rsDessin = CurrentDb.OpenRecordset(sqlquery)
If Not rsDessin.RecordCount > 0 Then 'If not present I want to add it
strContrat = rsDessin![Projet HNA]
sqlquery = "INSERT INTO Feuilles ([AHNS], [Contrat], [No Projet]) VALUES (strDessin, strContrat, strDessin)"
'Not sure what to do with this query or how to make sure it worked.
End If
'Checking my variables
Debug.Print strProjet
Debug.Print strContrat
Debug.Print strDessin
'By here I'd like to have inserted my new record.
rsDessin.Close
Set rsDessin = Nothing
I also read online that i could achieve a similar result with something like this:
Set R = CurrentDb.OpenRecordset("SELECT * FROM [Dessins]")
R.AddNew
R![Contrat] = strContrat
R![Projet] = strProjet
R![AHNS] = strDessin
R.Update
R.Close
Set R = Nothing
DoCmd.Close
Is one way better than the other? In the case where my INSERT INTO query is better, what should I do to execute it?
You're asking which is preferable when inserting a record: to use an SQL statement issued to the Database object, or to use the methods of the Recordset object.
For a single record, it doesn't matter. However, you could issue the INSERT statement like this:
CurrentDb.Execute "INSERT INTO Feuilles ([AHNS], [Contrat], [No Projet]) VALUES (" & strDessin & ", " & strContrat & ", " & strDessin & ")", dbFailOnError
(You should use the dbFailOnError option to catch certain errors, as HansUp points out in this answer.)
For inserting multiple records from another table or query, it is generally faster and more efficient to issue an SQL statement like this:
Dim sql = _
"INSERT INTO DestinationTable (Field1, Field2, Field3) " & _
"SELECT Field1, Field2, Field3 " & _
"FROM SourceTable"
CurrentDb.Execute sql
than the equivalent using the Recordset object:
Dim rsSource As DAO.Recordset, rsDestination As DAO.Recordset
Set rsSource = CurrentDb.OpenRecordset("SourceTable")
Set rsDestination = CurrentDb.OpenRecordset("DestinationTable")
Do Until rs.EOF
rsDestination.AddNew
rsDestination!Field1 = rsSource!Field1
rsDestination!Field2 = rsSource!Field2
rsDestination!Field3 = rsSource!Field3
rsDestination.Update
rs.MoveNext
Loop
That said, using an SQL statement has its limitations:
You are limited to SQL syntax and functions.
This is partially mitigated in Access, because SQL statements can use many VBA built-in functions or functions that you define.
SQL statements are designed to work on blocks of rows. Per-row logic is harder to express using only the Iif, Choose, or Switch functions; and logic that depends on the current state (e.g. insert every other record) is harder or impossible using pure SQL. This can be easily done using the Recordset methods approach.
This too can be enabled using a combination of VBA and SQL, if you have functions that persist state in module-level variables. One caveat: you'll need to reset the state each time before issuing the SQL statement. See here for an example.
One part* of your question asked about INSERT vs. Recordset.AddNew to add one row. I suggest this recordset approach:
Dim db As DAO.Database
Dim R As DAO.Recordset
Set db = CurrentDb
Set R = db.OpenRecordset("Dessins", dbOpenTable, dbAppendOnly)
With R
.AddNew
!Contrat = rsDessin![Projet HNA].Value
!Projet = Me.Combo_Projet.Value
!AHNS = Me.Combo_Dessin.Value
.Update
.Close
End With
* You also asked how to execute an INSERT. Use the DAO.Database.Execute method which Zev recommended and include the dbFailOnError option. That will add clarity about certain insert failures. For example, a key violation error could otherwise make your INSERT fail silently. But including dbFailOnError ensures you get notified about the problem immediately. So always include that option ... except in cases where you actually want to allow an INSERT to fail silently. (For me, that's never.)
I have a form where a user selects a vendor's name from a combobox, whose catalog file is to be imported. The combobox selection then drives a query to create a one-record recordset (rsProfile) containing several profile variables queried from a table of all vendor profiles. These variables are then used in a series of different queries to reformat, translate and normalize the vendor's uniquely structured files to a standardized format that can be imported into our system.
I am frustrated that I can't figure out how to build my stored queries that will use one or more parameters that are automatically populated from the profile recordset.
Here is my rsProfile harvesting code. It works. Note that intVdrProfileID is a global variable set and used in other places.
Private Sub btn_Process_Click()
Dim ws As Workspace
Dim db, dbBkp As DAO.Database
Dim qdf As DAO.QueryDef
Dim rsProfile, rsSubscrip As Recordset
Dim strSQL As String
Dim strBkpDBName As String
Dim strBkpDBFullName As String
strBkpDBName = Left(strVdrImportFileName, InStr(strVdrImportFileName, ".") - 1) & "BkpDB.mdb"
strBkpDBFullName = strBkpFilePath & "\" & strBkpDBName
Set db = CurrentDb
Set ws = DBEngine.Workspaces(0)
MsgBox ("Vendor Profile ID = " & intVdrProfileID & vbCrLf & vbCrLf & "Backup file path: " & strBkpFilePath)
' Harvest Vendor Profile fields used in this sub
strSQL = "SELECT VendorID, Div, VPNPrefix, ImportTemplate, " & _
"VenSrcID, VenClaID, ProTyp, ProSeq, ProOrdPkg, ProOrdPkgTyp, JdeSRP4Code, " & _
"PriceMeth, " & _
"ProCost1Frml, ProCost2Frml, " & _
"ProAmt1Frml, ProAmt2Frml, ProAmt3Frml, ProAmt4Frml, ProAmt5Frml " & _
"FROM tZ100_VendorProfiles " & _
"WHERE VendorID = " & intVdrProfileID & ";"
Set qdf = db.QueryDefs("qZ140_GetProfileProcessParms")
qdf.SQL = strSQL
Set rsProfile = qdf.OpenRecordset(dbOpenSnapshot)
DoCmd.OpenQuery "qZ140_GetProfileProcessParms"
' MsgBox (qdf.SQL)
I have used QueryDefs to rewrite stored queries at runtime, and although it works, it is quite cumbersome and does not work for everything.
I was hoping for something like the sample below as a stored query using DLookups. I can get this to work in VBA, but I can't get anything to work with stored queries. I am open to other suggestions.
Stored Query "qP0060c_DirectImportTape":
SELECT
DLookUp("[VPNPrefix]","rsProfile","[VendorID]=" & intVdrProfileID) & [PartNo] AS VenPrtId,
Description AS Des,
DLookup("[Jobber]","rsProfile",[VendorID=" & intVdrProfileID) AS Amt1,
INTO tP006_DirectImportTape
FROM tJ000_VendorFileIn;
ADDENDUM:
Let me adjust the problem to make it a bit more complex. I have a collection of about 40 queries each of which use a different collection of parameters (or none). I also have a table containing the particular set of queries that each vendor 'subscribes' to. The goal is to have a database where a non-coding user can add new vendor profiles and create/modify the particular set of queries which would be run against that vendor file. I have almost 100 vendors so far, so coding every vendor seperately is not practical. Each vendor file will be subjected to an average of 14 different update queries.
Simplified Example:
Vendor1 file needs to be processed with queries 1, 2 and 5. Vendor2 file might need only update queries 2 and 4. The parameters for these queries might be as follows:
query1 (parm1)
query2 (parm1, parm4, parm8, parm11)
query4 (parm5, parm6, parm7, parm8, parm9, parm10, parm11)
query5 () -no parms required
This is the core query processing that loops through only the queries relevant to the current vendor file. rsSubscrip is the recordset (queried from a master table) containing this filtered list of queries.
' Run all subscribed queries
MsgBox "Ready to process query subscription list."
With rsSubscrip
Do While Not .EOF
db.Execute !QueryName, dbFailOnError
.MoveNext
Loop
.Close
End With
You can set the parameters of a predefined query using the syntax;
Set qdf = CurrentDB.QueryDefs(QueryName)
qdf.Parameters(ParameterName) = MyValue
To add parameters to the query, add the following before the SELECT statement in the sql
PARAMETERS [ParameterOne] DataType, [ParameterTwo] DataType;
SELECT * FROM tblTest;
I have an SQL query which takes up a parameter stored in the db. I want to invoke the same from VBA code which is running on the same db. I am using MS Access for my work.
So for example consider, I have an SQL query 'Q' which takes a parameter 'p', I intend to invoke this SQL query from my VBA code 'C' , which also naturally involves passing this parameter 'p' to the query.
Help much appreciated
Soham
There are a few possibilities here.
Let us say it is a SELECT query built on a form that holds the parameters to be used and that the input is safe:
s = "SELECT * FROM MyTable WHERE AText ='" & Me.MyText & "'"
This can be used like so:
Forms!SomeForm.RecordSource = s
Or
Set qdf = CurrentDb.CreateQueryDef("NewQuery", s)
However, the above can be done in other, better ways.
Let us say it is a ACTION query run from a form that holds the parameters to be used and that the input is safe:
s = "UPDATE MyTable Set AText ='" & Me.MyText & "'"
Then
Set db = CurrentDB
db.Execute s, dbFailOnError
Or you can use a temporary query, which can be safer:
'Temporary query
s = "UPDATE MyTable Set AText = MyRext"
Set qdf = db.CreateQueryDef("", s)
qdf.Parameters!MyText = Me.MyText
qdf.ReturnsRecords = False
qdf.Execute dbFailOnError
Something similar to the above would also be suitable for an existing query.
You can also pass the parameter to a procedure, in which case Me.MyText becomes a variable, or you can use Inputbox, which is rarely a good idea.
After that, there is the whole world of ADO.