Pass Through Query Won't Run From Command Line - vba

I created a pass through query in Access.
All it says is .
sp_Submit ''
If I click on it directly it runs the SSMS stored procedure which just changes some test tables.
However if I run it in VBA it does not work. It doesn't error out or anything, it just does not work.
I have tried
sSQL = "sp_Submit '" & Me.cboNumber & "'"
and
sSQL = "sp_Submit '"
Please not the stored procedure isn't doing anything much at this point. I have it testing some stuff. It just deletes everything in one table and inserts it in another.
What am I doing wrong? I've used this in the past and it has worked so I'm not sure why it doesn't work this time. The stored procedure itself is set up to accept one variable but it doesn't actually do anything with it (yet.).
Thank you.

Given what you have to far, then you should be able to edit the saved pass though query with
Sp_Submit 'test'
Assuming the 1 paramter is text. If the parameter is to be a number, then
Sp_Submit 123
At this point, you have to save that query. Now click on it, does it run correctly?
And in place of clicking on the query, you can certainly do
CurrentDB.execute "name of saved query goes here"
However, keep in mind that a PT query is raw T-SQL. What executes runs 100% on the server. This means that such query(s) cannot contain references to any form, or anything else. So you have to “pre-process” or create the value you wish to pass and modify the PT query. So your code of creating the SQL you have looks correct, but you then have to take that sql string and "set" the PT query.
The most easy way to do this is with code like this:
With CurrentDb.QueryDefs("MyPass")
.SQL = "sp_Submit '" & Me.cboNumber & "'"
.Execute
End With
Of course if the PT query returns records, then you would go:
Dim rstRecords As DAO.Recordset
With CurrentDb.QueryDefs("MyPass")
.SQL = "sp_Submit '" & Me.cboNumber & "'"
.ReturnsRecords = True
Set rstRecords = .OpenRecordset
End With
And to be fair, you likely should set “returns” records = false in the first example. You can do this in the property sheet of the save query, or in code like this:
With CurrentDb.QueryDefs("MyPass")
.SQL = "sp_Submit '" & Me.cboNumber & "'"
.ReturnsRecords = False
.Execute
End With
Note that you can use the one PT query over and over in your code. So once you ceated that one PT query, then you can use it to pass any new sql you wish, such as:
Dim rstRecords As DAO.Recordset
With CurrentDb.QueryDefs("MyPass")
.SQL = "select * from tblHotels"
.ReturnsRecords = True
Set rstRecords = .OpenRecordset
End With
So you can "stuff" in any sql you want for that one PT query - and use it throughout your application.

Related

Setting two rowsources in same procedure is terrible slow - Access 2010

I have two Listboxes which are filled via vba on a click event. The table 'Project' is a odbc datasource with 250 records.
List1.RowSource = "SELECT Name FROM Project WHERE ProjectID = " & ProjectID.Caption & " AND Year = " & ActualYear.Caption & " ORDER BY Name"
List2.RowSource = "SELECT ProjectShare FROM Project WHERE ProjectID = " & ProjectID.Caption & " AND Year = " & ActualYear.Caption & " ORDER BY Name"
So far so good. But when I run this code, it takes everytime up to 30sec to complete. I thought, okay it's because of odbc and so on. But when I run only one line of this code (no matter which), it is fast as lightning (0,1sec).
How can it be, that one query takes 0,1sec and two querys 30sec? May I could make a break between these two lines? Btw. without odbc everything works like a charm, no matter how many lines
You can bind both listboxes to the same recordset by manually creating the recordset. This allows Access to only query the table once instead of twice at the same time, avoiding any locking conflicts, and tends to avoid other problems as well.
This also allows you to use parameters, fixing any errors introduced by string concatenation.
Dim rs As DAO.Recordset
With CurrentDb.CreateQueryDef("", "SELECT Name, ProjectShare FROM Project WHERE ProjectID = p1 AND Year = p2 ORDER BY Name")
.Parameters(0).Value= ProjectID.Caption
.Parameters(1).Value = ActualYear.Caption
Set rs = .OpenRecordset(dbOpenSnapshot) 'Snapshot because it won't be updated
End With
Set list1.Recordset = rs
Set list2.Recordset = rs
Note that I have had errors occur when an object bound to a recordset with parameters was requeried, so you might want to use string concatenation if that's happening.

Run-time Error 2498 for Append and Make Table Queries Created in VBA

I'm getting a 2498 error and really don't understand why. I'm building a string in VBA and am getting the error with the following line of code...
DoCmd.OpenQuery qdfNew, acNormal
It happened with a very long string created to create the query so I simplified the code as much as possible and am still getting the error.
Here's the code...
Option Compare Database
Option Explicit
Dim dbsFootball As Database
Dim strInsertSQL, strSelectSQL, strIntoSQL, strFromSQL, strOrderSQL, strSQL As String
Dim qdfNew As QueryDef
Sub CreateFormattedData()
Set dbsFootball = CurrentDb()
strSelectSQL = ""
strIntoSQL = ""
strFromSQL = ""
strOrderSQL = ""
strSQL = ""
strSelectSQL = "SELECT [tbl_Raw_League_Data].[Season]"
strIntoSQL = "INTO [tbl_Manip Data]"
strFromSQL = "FROM [tbl_Raw_League_Data]" _
+ "LEFT JOIN Referees ON [tbl_Raw_League_Data].[Referee] = Referees.[Referee from Source Data]"
strSQL = strSelectSQL + " " + strIntoSQL + " " + strFromSQL + " " + strOrderSQL
On Error Resume Next ' If query doesn't exist, error won't stop execution
DoCmd.DeleteObject acQuery, "pgmqry_Create Table tbl_Manip"
On Error GoTo 0 ' Reset error handler
Set qdfNew = dbsFootball.CreateQueryDef("pgmqry_Create Table tbl_Manip", strSQL)
DoCmd.OpenQuery qdfNew, acNormal
End Sub
The source field, [tbl_Raw_League_Data].[Season], is a "Short Text" data type (field size = 7).
If I terminate the VBA code and run the query that was created by the code, it works fine with no apparent errors. However, it will never run the query from within the VBA code.
I was originally getting the error 2498 when using "INSERT INTO" for an append query, but realized that the table could as easily be recreated at code execution time.
I'm lost and would sure appreciate some ideas!
Thanks in advance,
Jason
You are passing the querydef object to DoCmd.OpenQuery when it expects a string referencing name of a stored query object. Consider using the querydef's Name property:
DoCmd.OpenQuery qdfNew.Name, acNormal
Alternatively, use .Execute command from database object using the SQL string variable, bypassing any need for querydef:
dbsFootball.Execute strSQL, dbFailOnError
Or with querydef object, as #HansUp suggests, where you simply execute directly since it is an action query:
qdfNew.Execute dbFailOnError
Do note above two options bring up the regular MS Access discussion, of using stored vs VBA string query. While the former is precompiled and runs through query optimizer caching best plan, the latter can have sql dynamically created (structural components that is like SELECT, FROM and JOIN clauses as both can use passed in parameters). From your code snippet consider saving SQL query beforehand without needing to build it in VBA on the fly, and call it with DoCmd.OpenQuery.

MS Access: Use variables instead of text.SetFocus method to query

I have two parameters form a FROM and THRU textbox. The code object is txtFROM and txtTHRU. Now I tried to open the query and reports with a txtFROM.SetFocus and txtTHRU.SetFocus and used in the query criteria: Between [FORMS]![ReportName]![txtFROM].[Text] and [FORMS]![ReportName]![txtTHRU].[Text]. However nothing turns up when I link a button to the query and report to show the data with those two parameters. I think it may be due to the fact that the .SetFocus method will only work on one parameter, so I think writing VBA variables to pass into a query might work if possible. The thing is I do not know if it is possible to call a VBA variable while running to a query as it were an object. The variables would otherwise read .SetFocus to ready the parameter to be passed to the Access query.
DoCmd.SetWarnings False
If IsNull(txtFROM.Value) = False And IsNull(txtTHRU.Value) = False Then
dataFROM = CDate(txtFROM.Value)
dataTHRU = CDate(txtTHRU.Value)
End If
DoCmd.OpenQuery ("Expiring")
DoCmd.OpenReport ("Expirees"), acViewPreview
DoCmd.SetWarnings True
The above variables dataFROM and dataTHRU would be what I would like to fit in the query criteria to reference the Form which displays reports.
You might need to script the query "on the fly" by using CreateQueryDef. Sort of like:
Dim db as Database
Dim qdf as QueryDef
Set db = CurrentDB
Set qdf = db.CreateQueryDef("Expiring", "SELECT * FROM MyTable WHERE " &_
"MyDate >= #" & CDate(txtFROM.Value) & "# and MyDate =< #" CDate(txtTHRU.Value) & "#")
DoCmd.OpenReport "Expirees", acViewPreview
Of course, you'll probably need to add some code at the beginning to delete that query if it already exists. Definitely inside an If/Then because if the code happens to burp and doesn't create the query one time, it'll crash the next time you run it.
Edit
As suggested by HansUp, another option is simply to alter the query's SQL statement, which you can do in code.
Set myquery = db.OpenQueryDef("Expiring")
strsql = "SELECT * FROM MyTable WHERE " &_
"MyDate >= #" & CDate(txtFROM.Value) & "# and MyDate =< #" CDate(txtTHRU.Value) & "#"
myquery.SQL = strsql
myquery.Close
It looks like there was a mixup in my query code, the FROM was duplicated, FROM FROM, not FROM THRU. The code works as it should have with the reference to the Reports and Form which the text controls. Keep with the usual method then.

VBA to show message box if update query changes 1 row, show another if none

I'm working on running an append query (to change someones login password) in access, currently it checks to make sure the password matches and that they knew the original password. However, I run into a problem where if the update query: DoCmd.RunSQL "UPDATE Credentials SET Credentials.[Password] = [Forms]![LoginSubmit]![DesiredPassword] WHERE (((Credentials.Password)=[Forms]![LoginSubmit]![CurrentPassword]) AND ((Credentials.[User ID])=[Forms]![LoginSubmit]![User ID]));" updates 0 rows (meaning that the conditions were not met) it closes (I have a docmd.close following). If it does update their password it does the same, so in the end you don't know if it was successful until you try your new password.
I would like to know when it updates 0 rows so I can shoot up a MsgBox telling them it didn't work, end the sub and have them try again. If it updates 1 row I would have a MsgBox say "Success".
I know the VBA to the above except for the part that returns a value for the amount of updated rows in that query. Could someone help me out?
Thanks in advance.
Execute your UPDATE statement from a DAO.Database object variable. Afterward you can base your user notice on the variable's RecordsAffected property.
Here is a simple example, verified with Access 2007.
Dim db As DAO.Database
Dim strUpdate As String
strUpdate = "UPDATE tblFoo" & vbCrLf & _
"SET some_text = 'bar'" & vbCrLf & _
"WHERE id = 7;"
Debug.Print strUpdate
Set db = CurrentDb
db.Execute strUpdate, dbFailOnError
MsgBox db.RecordsAffected & " records affected"
Set db = Nothing

Loop Not Running Through Entire Table

So I have a system built in which it sets a few different flags and so on and so forth, but one of the things I want to do is take the contents of a staging table and send it over to another table used for tracking. I'm trying to do it using an insert into loop but I simply cannot figure out how to make it work as intended.
Private Sub Form_Load()
DoCmd.SetWarnings False
DoCmd.OpenQuery ("qryDeleteEmail")
Dim db As Object
Dim rst As Object
Dim test As Object
Set db = Application.CurrentDb
Set rst = db.OpenRecordset("qryDate")
Set test = db.OpenRecordset("tblEmailTemp")
If Me.RecordsetClone.RecordCount = 0 Then
MsgBox ("No delinquent accounts. No email will be generated.")
Me.Refresh
DoCmd.Close acForm, "qryDate", acSaveNo
DoCmd.CancelEvent
Else
rst.MoveFirst
Do Until rst.EOF
rst.Edit
rst!NeedsEmail = 1
rst.Update
rst.MoveNext
Loop
'DoCmd.Requery
'rst.Close
DoCmd.RunMacro ("StagingTable")
test.MoveFirst
Do Until test.EOF
CurrentDb.Execute "Insert Into EmailTracking (Account, ExpirationDate)" & _
"Values ('" & AccountName & "', '" & ExpirationDate & "')"
test.MoveNext
Loop
test.Close
rst.MoveFirst
Do Until rst.EOF
rst.Edit
rst!EmailSent = 1
rst.Update
rst.MoveNext
Loop
'DoCmd.Requery
rst.Close
DoCmd.RunMacro ("Close")
'DoCmd.OpenQuery ("qryDeleteEmail")
End If
Exit Sub
End Sub
What's happening right now is it's copying the first record of the staging table twice. For instance I have an account name A and an account name S, but instead of inserting the record for A and the record for S, it is simply inserting A twice.
Any help would be greatly appreciated!
Create and test a simpler procedure which is narrowly focused on the issue you're trying to solve. Unfortunately, I'm not sure what that issue is. I'll suggest this anyway ...
Public Sub TestLoopThruTable()
Dim db As DAO.database
Dim test As DAO.Recordset
Dim strInsert As String
DoCmd.SetWarnings True ' make sure SetWarnings is on
Set db = CurrentDb
Set test = db.OpenRecordset("tblEmailTemp")
Do While Not test.EOF
strInsert = "INSERT INTO EmailTracking (Account, ExpirationDate)" & vbCrLf & _
"VALUES ('" & AccountName & "', '" & ExpirationDate & "')"
Debug.Print strInsert
'db.Execute strInsert, dbFailOnError
test.MoveNext
Loop
test.Close
Set test = Nothing
Set db = Nothing
End Sub
Notice in your original version there was no space between ExpirationDate) and Values. I used a line break (vbCrLf) instead of a space, but either will keep the db engine happy.
I made sure SetWarnings is on. In your code, you turned it off at the start but never turned it back on again. Operating with SetWarnings off suppresses important information which you could otherwise use to understand problems with your code.
As that code loops through the recordset, it simply creates an INSERT statement and displays it for each row. You can view the output in the Immediate window (go there with the Ctrl+g keyboard shortcut). Copy one of those INSERT statements and test by pasting into SQL View of a new Access query. If it fails there, figure out what you need to change to satisfy the db engine. If the INSERT succeeds, try executing them from your code: enable the db.Execute line by removing the single quote from the start of that line.
The way you wrote the VALUES clause, it appears [ExpirationDate] is a text field. However if its data type is actually Date/Time, don't include quotes around the value you're inserting; use the # date delimiter instead of quotes.
Also make sure to include Option Explicit in the Declarations section of your code module like this:
Option Compare Database
Option Explicit
I mentioned that point because in an earlier version of this question you showed Option Compare but not Option Explicit. Trying to troubleshoot code without Option Explicit is a waste of time IMO.
I am not sure to understand what you are trying to do here; it is hard to understand what ErrorHandler is doing in the Else statement (even if commented).
As far as looping through a recordset goes, I advice you to read a little bit about the basis of VBA programmation in MS-Access. You can start by reading the articles below. It is a quick introduction about VBA recordsets and then the most common mistakes in VBA.
http://allenbrowne.com/ser-29.html
http://www.techrepublic.com/blog/10things/10-mistakes-to-avoid-when-using-vba-recordset-objects/373
It should help you improving your code.