Call SQL stored procedure from Access - sql-server

I have a SQL Server stored procedure (dbo.WiegenMain) as below:
ALTER PROCEDURE [dbo].[WiegenMain]
AS
BEGIN
insert into dbo.wiegen (Tag, Aufträge_anzahl, Wiegeraum)
select
dbo.datepart2(BUCHUNG_BIS) as Tag,
count(distinct AUFTRAGSNUMMER), Kurztext as Wiegeraum
from
dbo.tblZEITERFASSUNG
inner join
dbo.tblBELEGUNGSEINHEIT on tblZEITERFASSUNG.ID_BELEGUNGSEINHEIT = tblBELEGUNGSEINHEIT.ID
where
ID_BUCHUNGSART = 9
and ID_BELEGUNGSEINHEIT IN
(SELECT ID_BELEGUNGSEINHEIT
FROM dbo.tblPROZESS_BELEGUNGSEINHEIT
WHERE ID_PROZESS = 3)
and ABSCHLUSS = 1
AND dbo.DatePart2(BUCHUNG_BIS) = dbo.DatePart2(getdate())
group by
dbo.DatePart2(BUCHUNG_BIS), Kurztext
END
I want to call this stored procedure in Microsoft Access using VBA, I have tried the following :
First try:
Function InsertWiegen()
Dim conn As ADODB.Connection
Dim rcs As ADODB.Recordset
Dim strSQL As String
Dim strDel As String
Set conn = CurrentProject.Connection
strDel = "DELETE dbo.wiegen WHERE Tag = '" & Date & "'"
strSQL = "INSERT INTO dbo.wiegen ([Tag], [Aufträge_anzahl], [Wiegeraum]) " & _
"SELECT dbo.DatePart2([BUCHUNG_BIS]) as [Tag], count(distinct [AUFTRAGSNUMMER]) as [Aufträge_anzahl], Kurztext as [Wiegeraum] from dbo.tblZEITERFASSUNG inner join dbo.tblBELEGUNGSEINHEIT on tblZEITERFASSUNG.ID_BELEGUNGSEINHEIT=tblBELEGUNGSEINHEIT.ID where ID_BUCHUNGSART=9 and ID_BELEGUNGSEINHEIT in (SELECT ID_BELEGUNGSEINHEIT FROM dbo.tblPROZESS_BELEGUNGSEINHEIT WHERE ID_PROZESS = 3) and [ABSCHLUSS]=1 AND dbo.DatePart2([BUCHUNG_BIS])= dbo.DatePart2('" & Date & "') group by dbo.DatePart2([BUCHUNG_BIS]), [Kurztext]"
Set rcs = conn.Execute(strDel)
conn.Execute (strSQL)
Set rcs = Nothing
conn.Close
Exit Function
End Function
Second Try:
Function InsertWiegen()
Dim conn As ADODB.Connection
Dim rcs As ADODB.Recordset
Dim cmd As ADODB.Command
Dim strSQL As String
Dim strDel As String
Set conn = CurrentProject.Connection
'Set cmd.ActiveConnection = CurrentProject.Connection
Set cmd = New ADODB.Command
cmd.ActiveConnection = conn
cmd.CommandText = "WiegenMain"
cmd.CommandType = adCmdStoredProc
strDel = "DELETE dbo.wiegen WHERE Tag = '" & Date & "'"
Set rcs = conn.Execute(strDel)
cmd.Execute
Set rcs = Nothing
Set cmd = Nothing
conn.Close
Exit Function
End Function
dbo.datepart2() Function:
ALTER function [dbo].[DatePart2] (#date datetime)
returns datetime
as
begin
return(cast(CONVERT(varchar(12), #date, 101) AS datetime))
end
Problem: Both the methods give the error -
'The conversion of a char datatype to a datetime datatype resulted in
an out-of-range datetime value.'
The stored procedure is working perfectly in SQL Server Management Studio, but raises error in Microsoft Access. The strDel is working fine, it deletes the records from the database table sucessfully, problem is with the strSQL query. I would really appreciate, if anyone can find out what is causing the problem..

The text that you are inserting into your SQL statement for the Date will depend on your international settings. Try converting it to 'YYYY-MM-DD' like this:-
strDel = "DELETE dbo.wiegen WHERE Tag = '" & format (Date, "YYYY-MM-DD") & "'"

What data type is Tag in SQL?
If it is numeric then
strDel = "DELETE dbo.wiegen WHERE Tag = " & format (Date, "DD")

Solved the problem in another way:
strSQL = "INSERT INTO dbo.wiegen ([Tag], [Aufträge_anzahl], [Wiegeraum])
SELECT left([BUCHUNG_BIS],11) as [Tag], count(distinct [AUFTRAGSNUMMER]) as [Aufträge_anzahl], Kurztext as [Wiegeraum]
from dbo.tblZEITERFASSUNG
inner join
dbo.tblBELEGUNGSEINHEIT on tblZEITERFASSUNG.ID_BELEGUNGSEINHEIT=tblBELEGUNGSEINHEIT.ID
where ID_BUCHUNGSART=9 and ID_BELEGUNGSEINHEIT
in
(SELECT ID_BELEGUNGSEINHEIT FROM dbo.tblPROZESS_BELEGUNGSEINHEIT WHERE ID_PROZESS = 3)
and [ABSCHLUSS]=1 AND left([BUCHUNG_BIS],11)= left(GETDATE(), 11)
group by left([BUCHUNG_BIS],11), [Kurztext]"
Replaced my datepart2 function with left() function, now it executes successfully without any error.

Related

Excel VBA Runtime 3704 Operation is not allowed when object is closed

I have been using this code for some time and it works. As a matter of fact it works with a basic query. It just does not work with my new Stored Procedure. I can run the stored procedure manually. in SSMS and get my results. I thought that the error was when I was not getting data back so I added the . . . If myRS1.EOF Then . . . still getting the 3704 runtime error.
Here is my Excel (2013) Code
Private Sub cmdOK_Click()
Dim myStartDate, myEndDate
Dim myInsuranceCode
Dim objAD, objUser
Dim myDisplayName, myLastRow
Dim myMessage, myStyle, myTitle, myResult
Dim mySQL As String
Dim myConn
Dim myCmd
Dim myRS1
Dim myRange, myNamedRange, myCheckRange As Range
Dim X, Y, z
Dim myPercent, myLowEnd, myHighEnd
Dim myValue1, myValue2, myValue3, myValue4, myValue5, myValue6, myValue7, myValue8
Dim myCheckValue
Dim myHeaderRow, myDataRow, myLastColumn
'SET THESE ACCORDING TO THE REPORT. THE FIRST TWO MIGHT NOT NEED ANY CHANGES
myHeaderRow = 2
myDataRow = 3
myLastColumn = 22
'SETUP DATABASE OBJECTS
Set myConn = New ADODB.Connection
Set myCmd = New ADODB.Command
Set myRS1 = New ADODB.Recordset
Application.StatusBar = True
Application.StatusBar = "Connecting to SQL Server"
'GET DATES FROM TEH FORM AND SET SQL STATEMENT
myStartDate = frmMain.txtStartDate
myEndDate = frmMain.txtEndDate
'RUN INSURANCE STORE PROCEDURE
'SEPERATE THE INSURANCE CODE WITH A |
myInsuranceCode = "S19|S22"
mySQL = "dbo.BMH_rpt_PATIENTS_INSURANCE_LISTING '" & myStartDate & "', '" & myEndDate & "', '" & myInsuranceCode & "'"
'mySQL = "SELECT * FROM dbo.BETHESDA_ADMIT_SOURCE"
'HIDE THE FORM
frmMain.Hide
'GET THE USER THAT IS SIGNED IN
Set objAD = CreateObject("ADSystemInfo")
Set objUser = GetObject("LDAP://" & objAD.UserName)
myDisplayName = objUser.DisplayName
'OPEN CONNECTIONS TO THE DATABASE
myConn.ConnectionString = "Provider=SQLOLEDB;Data Source=mySQLServer;Initial Catalog=myDatabaseName;User ID=user;Password=xxxxxxxx;Connection Timeout=300;"
myConn.Open
'SET AND EXECUTE SQL COMMAND
Set myCmd.ActiveConnection = myConn
myCmd.CommandText = mySQL
myCmd.CommandType = adCmdText
Application.StatusBar = "Running Stored Procedure " & mySQL
myCmd.CommandTimeout = 3000
'OPEN RECORDSET
Set myRS1.Source = myCmd
myRS1.Open
'CHECK TO MAKE SURE WE ARE NOT AT THE BOTTOM OF THE SHEET COULD MEAN THERE WAS NOT DATA LAST TIME.
'THIS SAME CODE WILL REPEAT FOR THE DATA TAB
'*********** DATA *************
'CHECK TO MAKE SURE THERE IS DATA
If myRS1.EOF Then <---- THIS IS THE LINE I AM GETTING THE ERROR
Cells(myDataRow, 1).Value = "No Data Qualifies"
myMessage = "No data qualifing for your request " & mySQL
myTitle = "No Data"
myStyle = vbCritical + vbOKOnly
myResult = MsgBox(myMessage, myStyle, myTitle)
Exit Sub
End If
'SELECT THE SHEET TO CLEAR OUT THE OLD data on DATA
'IF THIS IS NOT SET ON THE SEEHET IT WILL FAIL
Set myTable = Sheets("DATA").ListObjects("DATA")
If Cells(myDataRow, 1).Value <> "" Then
myTable.DataBodyRange.Rows.Delete
End If
'COPY THE DATA TO EXCEL
Application.StatusBar = "Copying the new data."
Sheets("DATA").Cells(myDataRow, 1).CopyFromRecordset myRS1
Cells(1048576, 1).Select
Selection.End(xlUp).Select
myLastRow = ActiveCell.Row
'Application.StatusBar = "Naming the new DATA range"
'ActiveWorkbook.Names.Add Name:=myNamedRange, RefersTo:=Range(Cells(myHeaderRow, 1), Cells(myLastRow, myLastColumn))
myTable.Resize Range(Cells(myHeaderRow, 1), Cells(myLastRow, myLastColumn))
End Sub
*** This is all the VBA Code now. It is failing on the myRS1.EOF line so none of the other code even runs.
As you can see I have two mySQL statements. The first one is not working, but the second one works no issue.
If I run the SP from SSMS or even take the mySQL that is generated it runs fine in SSMS.
Here is the SP
--EXAMPLE
-- dbo.BMH_rpt_PATIENTS_INSURANCE_LISTING '11/01/2020', '11/30/2020', 'S19|S22'
ALTER PROCEDURE [dbo].[BMH_rpt_PATIENTS_INSURANCE_LISTING]
#StartDate AS DATETIME,
#EndDate AS DATETIME,
#Insurance AS VARCHAR(MAX)
AS
/** GET THE INSURANCE CODES **/
SELECT VALUE
INTO #INSURANCE
FROM STRING_SPLIT(#Insurance, '|')
/** GET THE PATIENTS FOR THE LIST **/
SELECT vv.pt_id AS 'Patient Account',
vv.alt_med_rec_no AS 'MRN'
FROM smsdss.vst_v AS vv
WHERE vv.pyr_cd IN (SELECT * FROM #INSURANCE)
AND vv.start_full_date BETWEEN #StartDate AND #EndDate
AND vv.tot_bal_amt <> 0

Passing Dynamic Query Values from Excel to SQL

Here is my stored Procedure. I am calling StartDate, EndDate as parameters from Excel. I had VBA executed for command button. The problem is I have to pass StartDate and EndDate to get the info. Is there any way I can pull data for a particular day either from StartDate or EndDate? And sometimes I pull data from both parameters? Not sure how the logic works.
CREATE PROCEDURE dbo.ProductListPrice #SellStartDate as Date, #SellEndDate as Date
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT
PR.[Name] ProductName
,PS.Name SubCategory
,PC.NAME ProductCategory
,PM.Name ProductModel
,[StandardCost]
,[ListPrice]
,CAST([SellStartDate] AS DATE) SellStartDate
,CAST([SellEndDate] AS DATE) SellEndDate
FROM [AdventureWorks2014].[Production].[Product] PR
INNER JOIN [AdventureWorks2014].[Production].[ProductSubcategory] PS
ON PR.[ProductSubcategoryID]=PS.[ProductSubcategoryID]
INNER JOIN [AdventureWorks2014].[Production].[ProductCategory] PC
ON PS.ProductCategoryID=PC.ProductCategoryID
INNER JOIN [AdventureWorks2014].[Production].[ProductModel] PM
ON PR.ProductModelID=PM.ProductModelID
WHERE SellStartDate>=#SellStartDate AND SellEndDate<=#SellEndDate
ORDER BY SellStartDate,productname
END
VBA
Private Sub CommandButton1_Click()
Dim SellStartDate As Date 'Declare the SellStartDate as Date
Dim SellEndDate As Date 'Declare the SellEndDate as Date
SellStartDate = Sheets("Sheet1").Range("B3").Value 'Pass value from cell B3 to SellStartDate variable
SellEndDate = Sheets("Sheet1").Range("B4").Value 'Pass value from cell B4 to SellEndDate variable
'Pass the Parameters values to the Stored Procedure used in the Data Connection
With ActiveWorkbook.Connections("AdventureWorksConnection").OLEDBConnection
.CommandText = "EXEC dbo.ProductListPrice '" & SellStartDate & "','" & SellEndDate & "'"
ActiveWorkbook.Connections("AdventureWorksConnection").Refresh
End With
End Sub
Assuming you want the result sets from your stored procedure into excel you can use something like this in your VBA Module.
Have your dates in a couple of cells on your spreadsheet let's assume you have the in cell A1 and A2
On your click button use the following VBA : (this is what I use, you can modify this to suit)
Sub your_sub_name()
Dim con As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim par As String
Dim WSP1 As Worksheet
Set con = New ADODB.Connection
Set cmd = New ADODB.Command
Set rs = New ADODB.Recordset
Application.DisplayStatusBar = True
Application.StatusBar = "Contacting SQL Server..."
' Remove any values in the cells where we want to put our Stored Procedure's results.
Dim rngRange As Range
Set rngRange = Range("A3:H299")
ActiveSheet.Range("A3:H299").ClearContents
ActiveSheet.Select
Range("A3:H299").Select
Selection.ClearContents
' Log into our SQL Server, and run the Stored Procedure
con.Open "Provider=SQLOLEDB;Data Source=your_server_name;Initial Catalog=your_database_name;Integrated Security=SSPI;Trusted_Connection=Yes;"
cmd.ActiveConnection = con
Dim prmstation As ADODB.Parameter
Dim prmDate As ADODB.Parameter
Dim prmShift As ADODB.Parameter
' Set up the parameter for our Stored Procedure
' (Parameter types can be adVarChar,adDate,adInteger)
cmd.Parameters.Append cmd.CreateParameter("SellStartDate", adDate, adParamInput, 10, Range("A1").Text)
cmd.Parameters.Append cmd.CreateParameter("SellEndDate", adDate, adParamInput, 10, Range("A2").Text)
Application.StatusBar = "Running stored procedure..."
cmd.CommandText = "ProductListPrice "
Set rs = cmd.Execute(, , adCmdStoredProc)
' Copy the results to cell B7 on the first Worksheet
Set WSP1 = ActiveSheet
WSP1.Activate
If rs.EOF = False Then WSP1.Cells(3, 1).CopyFromRecordset rs
rs.Close
Set rs = Nothing
Set cmd = Nothing
con.Close
Set con = Nothing
Application.StatusBar = "Data successfully updated for : " & Range("AS36").Text
End Sub
You also need to modify your WHERE clause like this
where
( #SellStartDate <>'' and #SellEndDate <>'' and SellStartDate>=#SellStartDate AND SellEndDate<=#SellEndDate )
or
(#SellStartDate <>'' and #SellEndDate ='' and SellStartDate>=#SellStartDate)
or
(#SellStartDate ='' and #SellEndDate <>'' and SellEndDate<=#SellEndDate )

Importing MS Access to MS SQL Server

Currently trying to update an SQL Server database from an Access db, it works importing new records but fails on when I reimport the file and there is a duplicate - in looking for it to insert the row if it's not there (working), but skip if it already exists. The first column has the primary key set.
Dim table As DataTable = New DataTable
Dim accConnection As New OleDb.OleDbConnection(
"Provider=Microsoft.JET.OLEDB.4.0; Data Source='C:\Tester.mdb';User Id=admin; Password=;")
Dim sqlConnection As New SqlClient.SqlConnection(
"Data Source=10.75.24.94;Initial Catalog=CTData;User ID=sql;Password=")
Try
'Import the Access data
accConnection.Open()
Dim accDataAdapter = New OleDb.OleDbDataAdapter(
"SELECT * FROM Import_test", accConnection)
accDataAdapter.Fill(table)
accConnection.Close()
'Export to MS SQL
For Each row As DataRow In table.Rows
row.SetAdded()
Next
sqlConnection.Open()
Dim sqlDataAdapter As New SqlClient.SqlDataAdapter(
"SELECT * FROM Import_test", sqlConnection)
Dim sqlCommandBuilder As New SqlClient.SqlCommandBuilder(sqlDataAdapter)
sqlDataAdapter.InsertCommand = sqlCommandBuilder.GetInsertCommand()
sqlDataAdapter.UpdateCommand = sqlCommandBuilder.GetUpdateCommand()
sqlDataAdapter.DeleteCommand = sqlCommandBuilder.GetDeleteCommand()
sqlDataAdapter.Update(table)
sqlConnection.Close()
Catch ex As Exception
If accConnection.State = ConnectionState.Open Then
accConnection.Close()
End If
If sqlConnection.State = ConnectionState.Open Then
sqlConnection.Close()
End If
MessageBox.Show("Import failed with error: " &
Environment.NewLine & Environment.NewLine &
ex.ToString)
End Try
The error I'm presented with is:
Violation of Primary key. Cannot insert duplicate key in object.
I think you can remove VB from the equation (I like to make things as simple as possible, without over-simplifying it). You have several options available.
INSERT INTO Table
SELECT * FROM #Table xx
WHERE NOT EXISTS (SELECT 1 FROM Table rs WHERE rs.id = xx.id)
Or . . .
DELETE FROM Table
WHERE (ID NOT IN (SELECT MAX(ID) AS Expr1
FROM Table
AS Table_1 GROUP BY NAME,ADDRESS,CITY,STATE,ZIP,PHONE,ETC.))
There are a lot of other ways to handle this as well. Is you need to incorporate VB, you can do something like this.
Dim cmd As New OleDbCommand
Dim con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\your_path\DB.accdb")
Dim queryResult As Integer
Dim sqlQRY As String = "SELECT COUNT(*) AS FROM ESRRegister WHERE ID = '" & IDtxt.Text & "'"
con.Open()
cmd.Connection = con
cmd.CommandType = CommandType.Text
If queryResult > 0 Then
cmd.CommandText = "insert into ESRRegister (Dt,ID)VALUES ('" & Dttxt.Text & "' , '" & IDtxt.Text & "')"
queryResult = cmd.ExecuteScalar()
MsgBox("Added Successfuly")
Else
MessageBox.Show("Already Exists!", "ALI ENTERPRISES", MessageBoxButtons.OK, MessageBoxIcon.Information)
End If

Access VBA Parameter in passthrough query to SQL Server

I have several queries in an MS Access database. Some of these use parameters. I use the following code in VBA to provide the query with these parameters:
VBA
Dim startDate As Date
Dim endDate As Date
Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef
Dim rst As DAO.Recordset
If IsNull(Me.dpFrom) Or IsNull(Me.dpTo) Then
MsgBox "Please select a date!"
ElseIf (Me.dpFrom.Value > Me.dpTo.Value) Then
MsgBox "Start date is bigger than the end date!"
Else
startDate = Me.dpFrom.Value
endDate = Me.dpTo.Value
Set dbs = CurrentDb
'Get the parameter query
Set qdf = dbs.QueryDefs("60 Dec")
'Supply the parameter value
qdf.Parameters("startDate") = startDate
qdf.Parameters("endDate") = endDate
'Open a Recordset based on the parameter query
Set rst = qdf.OpenRecordset()
'Check to see if the recordset actually contains rows
If Not (rst.EOF And rst.BOF) Then
rst.MoveFirst 'Unnecessary in this case, but still a good habit
Do Until rst.EOF = True
'Save contact name into a variable
Me.tbBUDdec.Value = rst!Som
rst.MoveNext
Me.tbLEYdec.Value = rst!Som
rst.MoveNext
Me.tbMDRdec.Value = rst!Som
rst.MoveNext
Me.tbODCdec.Value = rst!Som
rst.MoveNext
Loop
Else
MsgBox "There are no records in the recordset."
End If
rst.Close 'Close the recordset
Set rst = Nothing 'Clean up
Access Query
PARAMETERS startDate DateTime, endDate DateTime;
SELECT WarehouseCode, COUNT(DeliveryPoint) AS Som
FROM [50 resultaat]
WHERE EntryDate between [startDate] and [endDate]
GROUP BY WarehouseCode;
This is working fine. However, I am now trying to use the same code to call a passthrough query to a SQL server. This query uses a different syntax to declare and set the parameters:
SQL Server query
DECLARE #InvLineEntryDateBegin AS date
DECLARE #InvLineEntryDateEnd AS date
SET #InvLineEntryDateBegin = '2017-01-01'
SET #InvLineEntryDateEnd = '2017-05-31'
Select WarehouseCode, Count(PickOrderNr) as Som
FROM ( bla bla bla ...
I can't get my VBA code to work with the different SQL syntax. I've read several options but couldn't find anything concrete. Does anyone have experience with this query structure?
In other words: How can I, in VBA, insert parameters in a stored procedure that queries on a SQL server?
Consider building a named stored procedure that resides in SQL Server and have MS Access call it passing parameters using ADO as opposed to your current DAO method since you require parameterization. Then bind results to a recordset:
SQL Server Stored Proc
CREATE PROCEDURE myStoredProc
#InvLineEntryDateBegin DATE = '2017-01-01',
#InvLineEntryDateEnd DATE = '2017-05-31'
AS
BEGIN
SET NOCOUNT ON;
SELECT WarehouseCode, Count(PickOrderNr) as Som
FROM ( bla bla bla ... ;
END
VBA
' SET REFERENCE TO Microsoft ActiveX Data Object #.# Library
Dim conn As ADODB.Connection, cmd As ADODB.Command, rst As ADODB.Recordset
Dim startDate As Date, endDate As Date
If IsNull(Me.dpFrom) Or IsNull(Me.dpTo) Then
MsgBox "Please select a date!", vbCritical, "MISSING DATE"
Exit Sub
End if
If (Me.dpFrom.Value > Me.dpTo.Value) Then
MsgBox "Start date is bigger than the end date!", vbCritical, "INCORRECT RANGE"
Exit Sub
End if
startDate = Me.dpFrom.Value: endDate = Me.dpTo.Value
' OPEN CONNECTION
Set conn = New ADODB.Connection
conn.Open "DRIVER={SQL Server};server=servername;database=databasename;UID=username;PWD=password;"
' OPEN/DEFINE COMMAND OBJECT
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = conn
.CommandText = "myStoredProc"
.CommandType = adCmdStoredProc
' BIND PARAMETERS
.Parameters.Append .CreateParameter("#InvLineEntryDateBegin", adDate, adParamInput, 0, startDate)
.Parameters.Append .CreateParameter("#InvLineEntryDateEnd", adDate, adParamInput, 0, endDate)
En With
' BIND RESULTS TO RECORDSET
Set rst = cmd.Execute
...
Simply create a pass-though query in Access and save it.
Ensure that the PT query works. It will likely look like:
Exec MySpName '2017-01-01', '2017-05-31'
Again: 100% Make sure the query works when you click on it in Access. At this point you not written any VBA code.
Once you have above pass through query working, then in VBA you can do this:
Dim strStartDate As String
Dim strEndDate As String
Dim strSQL As String
strStartDate = "'" & Format(Me.dpFrom, "yyyy-mm-dd") & "'"
strEndDate = "'" & Format(Me.dpTo, "yyyy-mm-dd") & "'"
strSQL = "exec MyStoreProc " & strStartDate & "," & strEndDate
With CurrentDb.QueryDefs("QryMyPass")
.SQL = strSQL
Set rst = .OpenRecordset
End With
If I remember right, in a pass-through query, you are passing the query definition directly to the engine in which it is going to run. So, you will have to use the SQL Server syntax for your query instead of the Access VBA syntax. Give that a try.
Also, the same goes for a Stored procedure. Use the syntax like you were to execute through SSMS.
"exec sp_mysp var1 var2" and so on.

Excel VBA - SQL Call - Operation is not allowed when the object is closed

I have a couple macros to make calls to SSMS 2014 to run a query and return the results in a defined cell in my worksheet. They work successfully, but when I try to use certain queries with temp tables I get the following error message:
I have researched online and the best answer I can find is to add SET NOCOUNT ON at the beginning of my query. I tried that, and still got the same message.
The piece of code that the Debug brings me to is as follows:
bqr.Range("B6").CopyFromRecordset rst
The meat and potatoes of my code, along with the variable setups that matter, is as follows:
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim ConnectionString As String
Dim StrQuery As String
Dim SOURCE As String
Dim DATABASE As String
Dim QUERY As String
Dim intColIndex As Integer
Dim sDate As String
Dim eDate As String
Dim qt As Worksheet
Dim qtr As Worksheet
Dim bqr As Worksheet
Dim bp As Worksheet
ConnectionString = "Provider=SQLOLEDB;Data Source=" & SOURCE & "; Initial Catalog=" & DATABASE & "; Integrated Security=SSPI;"
cnn.Open ConnectionString
cnn.CommandTimeout = 900
StrQuery = QUERY
rst.Open StrQuery, cnn
bqr.Range("B6").CopyFromRecordset rst
For intColIndex = 0 To rst.Fields.Count - 1
Range("B5").Offset(0, intColIndex).Value = rst.Fields(intColIndex).Name
Next
The most confusing part is that the error suggests that my rst recordset is closed, even though it is opened just before I use the CopyFromRecordset
I've tried adding DROP TABLE at the end of my query, the SET NOCOUNT ON function at the beginning, and even tested some smaller simple temp tables as tests.
For example, I set my QUERY variable to:
QUERY = "CREATE TABLE #Test1 (TestID INT, TestValue VARCHAR(20))"
QUERY = QUERY + " INSERT INTO #Test1"
QUERY = QUERY + " VALUES (1, 'Pass'), (2, 'Fail'), (3, 'Try Again')"
QUERY = QUERY + " SELECT * INTO #Test2 FROM #Test1 WHERE TestID = 1"
QUERY = QUERY + " SELECT * FROM #Test2"
Then ran the code to extract and past into Excel, and it worked.
Therefore, I am stumped. Maybe there is a limit to how long the query can be? Right now it's 180 lines long, so it's pretty big...
Any suggestions are appreciated!
EDIT: Full macro below (less the actual query):
Private Sub CommandButton1_Click()
If TextBox1.Value = "i.e. 20160101" Or TextBox2.Value = "i.e. 20160131" Then
MsgBox "Please fill out all fields before proceeding"
ElseIf Len(TextBox1.Value) <> 8 Or Len(TextBox2.Value) <> 8 Or Not IsNumeric(TextBox1.Value) Or Not IsNumeric(TextBox2.Value) Then
MsgBox "Please use correctly formatted Datekeys (i.e. yyyymmdd)"
Else
Application.DisplayAlerts = False
Sheets(ActiveWorkbook.Sheets.Count).Select
While ActiveSheet.Name <> "[worksheet I want to keep]"
ActiveSheet.Delete
Sheets(ActiveWorkbook.Sheets.Count).Select
Wend
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim ConnectionString As String
Dim StrQuery As String
Dim SOURCE As String
Dim DATABASE As String
Dim QUERY As String
Dim intColIndex As Integer
Dim sDate As String
Dim eDate As String
Dim qtr As Worksheet
Dim bqr As Worksheet
Dim bp As Worksheet
Set qtr = Sheets([sheet name])
Sheets.Add after:=qtr
Set bqr = ActiveSheet
bqr.Name = "[sheet name]"
Sheets.Add after:=bqr
Set bp = ActiveSheet
bp.Name = "[sheet name]"
SOURCE = "[server]"
DATABASE = "[database]"
sDate = UserForm1.TextBox1.Value
eDate = UserForm1.TextBox2.Value
QUERY = "[beginning of query]"
QUERY = QUERY + " [more query here]" 'This gets repeated a lot for each additional line in the query'
qtr.Select
Range("B6").Select
While ActiveCell.Value <> ""
QUERY = QUERY + " " + ActiveCell.Value
ActiveCell.Offset(1, 0).Select
Wend
QUERY = QUERY + " [more query here]" 'This gets repeated a lot for the remaining lines in the query'
ConnectionString = "Provider=SQLOLEDB;Data Source=" & SOURCE & "; Initial Catalog=" & DATABASE & "; Integrated Security=SSPI;"
cnn.Open ConnectionString
cnn.CommandTimeout = 2000
StrQuery = QUERY
rst.Open StrQuery, cnn
bqr.Range("B6").CopyFromRecordset rst
For intColIndex = 0 To rst.Fields.Count - 1
Range("B5").Offset(0, intColIndex).Value = rst.Fields(intColIndex).Name
Next
End If
Application.DisplayAlerts = True
End Sub
Start your T-SQL query with set nocount on;
QUERY = "set nocount on;"
QUERY = QUERY & "declare #Test1 table (TestID INT, TestValue VARCHAR(20))"
QUERY = QUERY & " INSERT INTO #Test1"
QUERY = QUERY & " VALUES (1, 'Pass'), (2, 'Fail'), (3, 'Try Again')"
QUERY = QUERY & " SELECT * FROM #Test1 WHERE TestID = 1"
Then it should work. The next example will also work and is a bit closer to your example (yet using table variables).
set nocount on;
declare #Test1 table (TestID INT, TestValue VARCHAR(20))
declare #Test2 table (TestID INT, TestValue VARCHAR(20))
INSERT INTO #Test1
VALUES (1, 'Pass'), (2, 'Fail'), (3, 'Try Again')
insert into #Test2
select *
from #Test1 WHERE TestID = 1
select * from #Test2

Resources