Using parameters on Excel Connections to SQL Server - vba

I have been struggling with a need I had for several month and today I found the solution, or workaround if you'd like, to it.
The solution was inspired on a post I found here:
how to pass parameters to query in SQL (Excel)
And, even though I wanted to thank #mono código for the idea, I couldn't comment on the post anything on the original thread due to my lack of reputation. So I thought of posting this to thank and also to help others with the struggle.
My first approach for this was using Power Query, but doing modifications to the script afterwards is very complicated. This approach is much more simpler IMO.
It is basically getting the command text of your connection and modifying it on the fly:
With ActiveWorkbook.Connections("MyConnection").OLEDBConnection
queryOriginalText = .CommandText
queryPreText = .CommandText
queryPostText = Replace(queryPreText, "SET #From=#From", "SET #From='" & Range("StartDate") & "'")
queryPreText = queryPostText
queryPostText = Replace(queryPreText, "SET #To=#To", "SET #To='" & Range("EndDate") & "'")
queryPreText = queryPostText
queryPostText = Replace(queryPreText, "SET #OrderNo=#OrderNo", "SET #OrderNo='" & Range("OrderNo") & "'")
.CommandText = queryPostText
ActiveWorkbook.Connections("MyConnection").Refresh
.CommandText = queryOriginalText
End With
My script has 3 variables that I use as conditions to filter my data:
#From, #To and #OrderNo. And, when I set those on my script I do it like this:
SET #From=#From
SET #To=#To
SET #OrderNo=#OrderNo
In my VBA I look for those specific strings and replace them one by one with values that the user input on the Sheet, on specific cell with Range names.
At the end I put back the original text so the strings to replace are always there when the user hit the button that runs the macro. This only works if you unchecked the option
Connection Properties
otherwise you will get a runtime error.
I hope this helps

Are you saying you need to pass variable to the ConnectionString? That doesn't seem right at all. Pass dates to the Query that is passed to the ConnectionSting. Follow this example.
Private Sub CommandButton1_Click()
Dim FromDate As Date
Dim ToDate As Date
FromDate = Format(Sheets("Sheet1").Range("B1").Value, "yyyy-mm-dd") 'Pass value from cell B1 to SellStartDate variable
ToDate = Format(Sheets("Sheet1").Range("B2").Value, "yyyy-mm-dd") 'Pass value from cell B2 to SellEndDate variable
MsgBox FromDate
MsgBox ToDate
'Pass the Parameters values to the stored procedure used in the data connection
With ActiveWorkbook.Connections("TestConnection").OLEDBConnection
.CommandText = "EXEC dbo.spr_TestProcedure '" & FromDate & "','" & ToDate & "'"
ActiveWorkbook.Connections("TestConnection").Refresh
End With
End Sub
Also, it may be helpful to follow the example from the link below.
https://www.mssqltips.com/sqlservertip/3436/passing-dynamic-query-values-from-excel-to-sql-server/
Post back if you are still having an issue with this.

Related

Error 2465 in MS Access when running a VBA code

Read through a few of the previously asked posts about this error but still cannot understand it.
The error text is "Run-time error '2465' CASREP reporting tool can't find the field '|1' referred to in your expression
I have a form to assign parts to certain supply reports. We have a form where users can manually hyperlink the parts to the request if they fall in the cracks. There is a check box feature, followed by the use of an "Assign" button to achieve this.
Every time a box is checked and a user selects "Assign" the error pops up. The string of code that pops up with the bug is as follows:
strSQL_del = "DELETE FROM [tbl_Temp_Assign] " & _
"WHERE [jcn_cd]= '" & Forms![Parts: Assign Unit].[tblTemp_Assign subform1].Form.[jcn.cd] & "'
AND [CASREP #] = '" & strCASREP & "' AND [doc_num_cd] = '" & Forms![Parts: Assign Unit].[tblTemp_Assign subform1].Form.[doc_num_cd] & "'
AND [last_updated_dte] = #" & Forms![Parts: Assign Unit].[tblTemp_Assign subform1].Form.[last_updated_dte] & "#
AND [PMOMsgDte] = #" & Forms![Parts: Assign Unit].[tblTemp_Assign Unit].Form.[PMOMsgDte] & "#" 'Intentionally left off AssignDte
Any help is greatly appreciated. I'm lost on what is wrong.
The error is related to the SQL string concatenation, but that string is quite long, it's hard to say if you have a space between ' and the first AND condition. Also, after the first continuation character _, is all that a single line?
Anyway, I would strongly advise to setup a delete query where you pass the form values as parameters and in VBA you just execute the query. It will be easier to update later on if needed.
The query:
PARAMETERS [prmTextField] Text (50), [prmDateField] DateTime, [prmNumberField] Long;
DELETE *
FROM T
WHERE T.TextField = [prmTextField]
AND T.DateField = [prmDateField]
AND T.NumberField = [prmNumberField];
Then, in VBA just execute the query.
With CurrentDb().QueryDefs("QueryName")
.Parameters("[prmTextField]").Value = '[Value from Form (text)]
.Parameters("[prmDateField]").Value = '[Value from Form (date)]
.Parameters("[prmNumberField]").Value = '[Value from Form (number)]
.Execute dbFailOnError
End With
By the way, do you really need to pass all those parameters to delete a record? Usually, just the record id is needed.

Why is my update query passing incorrect information to the table?

I have an SQL statement in VBA that when i run it, it updates my table with incorrect information. I've been struggling with this code for over a week trying workarounds and debugging but to no avail. I've searched online and found nothing even close to this.
DIM SQL as String
DIM periodStart as Date
DIM periodEnd as Date
periodStart = DateSerial(Year(Date), 12, 1)
periodEnd = DateSerial(Year(Date), 12, 15)
MsgBox "Period Start: " & periodStart & " Period End: " & periodEnd
SQL = "UPDATE EmpTime SET EmpTime.beginning = " & periodStart & " & EmpTime.ending = " & periodEnd & ";"
DoCmd.RunSQL SQL
The above code gives me a message box that shows me the periodStart and periodEnd variables are being built properly but then when i look to the table, the information is not the same as the Message box.
MsgBox
Table
Why is this happening and what can I do to fix it/avoid it ?
What I think is happening here is that your SQL is shaking out to be:
UPDATE EmpTime SET EmpTime.beginning = 12/1/2019, EmpTime.ending = 12/15/2019;
Access is not super amazing at guessing your intentions when you just send it math problems like this. Because it doesn't recognize your first date as a properly formatted string (12/01/2019 would be more appropriate) it is making the educated guess that you literally wanted to divide 12 by 1 by 2019. Which results in a decimal, or a very early time of the first date that MS Access can record: 12/30/1899 (like 12:05am, but there is no time dimension in play so it's dropped).
Instead try:
UPDATE EmpTime SET EmpTime.beginning = #" & Format(periodStart, "mm/dd/yyyy") & "# & EmpTime.ending = #" & Format(periodEnd, "mm/dd/yyyy") & "#;"
This does two things:
It formats (using the Format() function) your date into something access will recognize on its own.
It surrounds the date in # which is the microsoft office-y way of saying "This is explicitly a date, treat it as such or throw an error". Which is a much better scenario then "Guess what I meant when I send you this math/date"
Lastly, as Gordon mentions, and I also HIGHLY recommend is to switch this code over to use parameterized inputs in your SQL. here is a good write up of what that looks like. This solves two issues in your current code
Your malformed date would most likely error on being assigned to the correctly typed parameter before the SQL was executed alerting you that you have a bad date. (no guessing what went wrong and no bad data hitting your database)
You are protected from SQL Injection by users of your workbook. I assume this is not a super important facet of your workbook/application though since this is probably an internal company or personal thing and everyone using it can be trusted, but I am always in favor of hardening your code as best as possible since it's just good practice.
SQL = "UPDATE EmpTime SET EmpTime.beginning = #" & periodStart & "#, EmpTime.ending = #" & periodEnd & "#"

Insert Query/Select Query works in access, but not in vba

I have created a query that works great with no errors in Access, and while trying to translate this to my vba setup I can't figure out why I am not getting any values, even though the query clearly works in access, and causes no errors on the VBA side.
Pulling my hair out here, I have created a side table to see if I could "pseudo-insert" the calculated value, but I get the same issue as above - insert works with no errors in access, goes through in vba with no issues, but doesn't actually insert any data.
I have copied the string queries while pausing code to make sure EVERYTHING matches up between the Access query that works and the VBA query, and haven't found any differences.
I read somewhere since I am trying to pull a "first line" data piece that there may be some HDR setting that I could change, but when I tried to apply any fixes I found they opened another instance of excel and opened a dialogue box.
Please let me know what I am doing wrong here.
Public Function PullNextLineItemNumB(QuoteNum) As Integer
Dim strQuery As String
Dim ConnDB As New ADODB.Connection
Dim myRecordset As ADODB.Recordset
Dim QuoteModifiedNum As String
ConnDB.Open ConnectionString:="Provider = Microsoft.ACE.OLEDB.12.0; data
source=" & ThisWorkbook.Path & "\OEE Info.accdb"
'Query to try and make Access dump the value "18" into the table so I can
grab it after the query is finished, sidestepping excel not working
strQuery = "INSERT INTO TempTableColm (TempColm) SELECT
MAX(MID([Quote_Number_Line],InStr(1,[Quote_Number_Line]," & Chr(34) & "-"
& Chr(34) & ")+1)) AS MaxNum from UnifiedQuoteLog where Quote_Number_Line
like '" & QuoteNum & "*'"
ConnDB.Execute strQuery
'Original query, returns "18" as expected in Access, and null or empty in
the recordset
strQuery = "SELECT MAX(MID([Quote_Number_Line],InStr(1,
[Quote_Number_Line]," & Chr(34) & "-" & Chr(34) & ")+1)) from
UnifiedQuoteLog where Quote_Number_Line like '" & QuoteNum & "*'"
Set myRecordset = ConnDB.Execute(strQuery)
Do Until myRecordset.EOF
For Each fld In myRecordset.Fields
Debug.Print fld.Name & "=" & fld.Value
Next fld
myRecordset.MoveNext
Loop
myRecordset.Close
Set myRecordset = Nothing
ConnDB.Close
Set ConnDB = Nothing
End Function
Actual output from access is "18" which is expected, output from excel's vba recordset is always null or empty string.
It appears I solved the problem, while looking into this apparently the excel operator using ADODB with access is % for LIKE and NOT * (because reasons). As soon as I made that change everything started working.
Can someone explain why that is a thing? I really want to understand why this was a design choice.

Pass Through Query Won't Run From Command Line

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.

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.