Using a Parameterized Query on a SQL Table in Excel using VBA - sql-server

I have some code that is supposed to run a parameterized query of the SQL table that I am query. The way that it does this is there is a designated cell (Z1) that is supposed to take in an input value from one of my columns and then automatically update the query to display the results in the excel table. I keep getting a run-time error: '1004' which says it's a General ODBC error, but I'm not sure what is happening. Here is the database that I am connection to: Database
I'm using SQL express, so the server is .\SQLEXPRESS
Here is the code that I have:
Sub ParameterQueryExample()
'---creates a ListObject-QueryTable on Sheet1 that uses the value in
' Cell Z1 as the ProductID Parameter for an SQL Query
' Once created, the query will refresh upon changes to Z1.
Dim sSQL As String
Dim qt As QueryTable
Dim rDest As Range
'--build connection string-must use ODBC to allow parameters
Const sConnect = "ODBC;" & _
"Driver={SQL Server Native Client 10.0};" & _
"Server=.\SQLEXPRESS;" & _
"Database=TSQL2012;" & _
"Trusted_Connection=yes"
'--build SQL statement
sSQL = "SELECT *" & _
" FROM TSQL2012.Production.Products Products" & _
" WHERE Products.productid = ?;"
'--create ListObject and get QueryTable
Set rDest = Sheets("Sheet1").Range("A1")
rDest.CurrentRegion.Clear 'optional- delete existing table
Set qt = rDest.Parent.ListObjects.Add(SourceType:=xlSrcExternal, _
Source:=Array(sConnect), Destination:=rDest).QueryTable
'--add Parameter to QueryTable-use Cell Z1 as parameter
With qt.Parameters.Add("ProductID", xlParamTypeVarChar)
.SetParam xlRange, Sheets("Sheet1").Range("Z1")
.RefreshOnChange = True
End With
'--populate QueryTable
With qt
.CommandText = sSQL
.CommandType = xlCmdSql
.AdjustColumnWidth = True 'add any other table properties here
.BackgroundQuery = False
.Refresh
End With
Set qt = Nothing
Set rDest = Nothing
End Sub

Open up the ODBC Data Source Admin program in Control Panel\System and Security\Administrative Tools and check that the driver you specified in the code "Driver={SQL Server Native Client 10.0};" matches a driver under the Drivers tab. A mismatch can give this error.

Related

How to overcome resource limitation of IN operator in Microsoft SQL Server

I am trying to pass over 37K values in the WHERE clause using IN operator through Excel VBA macro. However, due to resource limitation in Microsoft SQL Server, the query won't execute. I have tried to pass the values in an array in VBA as well as tried creating a list in in SQL. Neither are able to accommodate these many values. Can somebody help? Sharing the code I have tried below.
Dim i as Long
Dim str As String
Dim dict_pn
Set dict_pn = CreateObject("Scripting.Dictionary")
i = 1
With InputS
For i = 1 to 50000
str = Trim(.Cells(i, PN_Col).Value)
dict_pn.Add str, 0
Next
With rsPubs
' Assign the Connection object.
.ActiveConnection = cnPubs
.Open Worksheets("SQL Script").Range("A1") & "('" & Join(dict_pn.keys, "','") & "') " & Worksheets("SQL Script").Range("A2") & "('" & Join(dict_pn.keys, "','") & "') " & Worksheets("SQL Script").Range("A3") & "('" & Join(dict_pn.keys, "','") & "') "
ActiveWorkbook.Worksheets("SQL Results").Range("A3").CopyFromRecordset rsPubs
You should transmit data to SQL Server like in related post
Sub UpdateTable()
Dim cnn As Object
Dim wbkOpen As Workbook
Dim objfl As Variant
Dim rngName As Range
Workbooks.Open "C:\your_path_here\Excel_to_SQL_Server.xls"
Set wbkOpen = ActiveWorkbook
Sheets("Sheet1").Select
Set rngName = Range(Range("A1"), Range("A1").End(xlToLeft).End(xlDown))
rngName.Name = "TempRange"
strFileName = wbkOpen.FullName
Set cnn = CreateObject("ADODB.Connection")
cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strFileName & ";Extended Properties=""Excel 12.0 Xml;HDR=Yes"";"
nSQL = "INSERT INTO [odbc;Driver={SQL Server};Server=Server_Name;Database=[Your_Database].[dbo].[TBL]]"
nJOIN = " SELECT * from [TempRange]"
cnn.Execute nSQL & nJOIN
MsgBox "Uploaded Successfully"
wbkOpen.Close
Set wbkOpen = Nothing
End Sub
and then you can do any you want - use operator IN or LEFT JOIN whith check for null on SQL server side.
You can use temporary table if you will not close connection - temp table exists only in session level.
This is way from VBA code.
Second way - you can use SSIS package to work with excel files. In package you will have same steps - data frlow to transmit data from excel to server and then run sql code to join data. Or you can use join block inside SSIS package.
Third way that you can implement if data in SQL server less than excel row count limit. You can import data from SQL into Excel sheet, and than use VLOOKUP() function to join tables and find related data.

Using both Excel and Microsoft SQL Server Connection Strings

My task is to add new records from an excel table to a Microsoft SQL Server table, and to do this, I was planning on using ADODB objects; however, my SQL statement is not executing, and I think it has something to do with my connection strings.
In my code, I wrote down the SQL statement that I plan on using in the end, but when I tried:
sql = "SELECT * FROM [Provider=SQLOLEDB;Data Source=hpwfh-ssql01; _
Initial Catalog=HPW DataIntegrated Security=SSPI;Trusted_Connection=Yes].Hubspot_Data"
(a simple select statement) it didn't even work.
Sub update1()
Dim cn, rs As Object, path As String, name As String, sql As String, file As String
path = "T:\Marketing\Data Analytics\Hubspot data for SQL"
name = "Hubspot_Data"
file = path & "\" & name & ".xlsx"
Set cn = CreateObject("ADODB.Connection")
With cn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.connectionstring = "Data Source=" & file & ";Extended Properties=""Excel 12.0 Xml;HDR=YES;Readonly=false;IMEX=0"";"
.Open
End With
sql = "INSERT INTO [Provider=SQLOLEDB;Data Source=hpwfh-ssql01;Initial Catalog=Hubspot_Data;Integrated Security=SSPI;Trusted_Connection=Yes].Hubspot_Data " & _
"SELECT * FROM (SELECT * FROM [Provider=SQLOLEDB;Data Source=hpwfh-ssql01;Initial Catalog=Hubspot_Data;Integrated Security=SSPI;Trusted_Connection=Yes].Hubspot_Data" & _
"EXCEPT SELECT * FROM [hubspot-crm-exports-sql-data-20$])"
Set rs = cn.Execute(sql)
End Sub
Just a side note: the table is named the same thing as the database
For this code, I have gotten three different errors:
The Microsoft Access database engine could not fin the object 'Area' Make
sure the object exists and that you spell its name and the path name
correctly. (And I did not misspell Hubspot_Data)
External table is not in the expected format.
The Microsoft Acess database engine cannot open or write to the file
(My File Path)'\My Documents\Provider=SQLOLEDB.XLSX'. It is already opened
exclusively by another use, or you need permission to view and write its
data.
Clearly the computer is going to the wrong place to retrieve the table it needs, and I have no idea where I went wrong. Thanks for the help.
First of all you need 2 connections - one for SQLSvr and one for Excel.
Then query your source (Excel) and do a separate insert into SQLSvr. You are not going to be able to mix these into one query.
Sub SelectInsert()
Dim cn As Object, rs As Object, sql As String
Dim conSQL As Object, sInsertSQL As String
'---Connecting to the Data Source---
Set cn = CreateObject("ADODB.Connection")
With cn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.ConnectionString = "Data Source=" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & ";" & "Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
.Open
End With
Set conSQL = CreateObject("ADODB.Connection")
With cn
.Provider = "SQLOLEDB"
.ConnectionString = "Server=myServerAddress;Database=myDataBase;Trusted_Connection=True;"
.Open
End With
'---Run the SQL SELECT Query---
sql = "SELECT * FROM [Sheet1$]"
Set rs = cn.Execute(sql)
Do 'the insert. Each rs(n) represents an Excel column.
sInsertSQL = "INSERT INTO table VALUES(" & rs(0) & ";" & rs(1) & ";" & rs(2) & ")"
conSQL.Execute sInsertSQL
rs.MoveNext
Loop Until rs.EOF
'---Clean up---
rs.Close
cn.Close
conSQL.Close
Set cn = Nothing
Set conSQL = Nothing
Set rs = Nothing
End Sub
get properties of your database from "SQL Server Object explorer" and copy the exact same connection string. then copy it to the "appsettings.json" file of your project. It looks like this :
"connectionStrings": {
"ApiDbConnectionString": "Server=(localdb)\\mssqllocaldb;Database=ApiDB;Trusted_Connection=True;"
}
then you need to create an object in your connection string and open a connection to the database using that object, then write your SQL query to the database

JOIN an Access table and a SQL Server table in a single query from Excel VBA

I am using Excel 64-bit
I have a ms-access database and in this database I have normal ms-access table and some linked table from SQL Server, I have a query that is taking a reference of a linked table, and when I am firing that query from excel vba it is giving me an ODBC error, however I am successfully able to fetch non linked table from excel vba.
Now I am thinking about different approach, can it be possible to join ms-access and SQL Server table in a single query, I found some code from net and tried my luck, but it is not working and giving an error message "Could not find installable ISAM", below is the code that I am using.
Note:- table "PeopleMain" is a sql server table, and except this table all are ms-access table.
[code]
Sub FetchData3()
Dim rs As Object
Dim cn As Object
Dim ss As String
Dim conn As String
Dim accdb As Object
conn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=G:\Workflow Tools (Michael Cantor)\Tool For Fixing Bug From Michael Cantor\PI MDT Reconciliation Workflow Tool\PI Database.accdb;Persist Security Info=False;Mode=Read"
ss = "SELECT RM.ReconciliationID, RM.FirmID, RM.FirmName, RM.DateRequested, RM.DueDate, Rm.ExtendedDueDate, " & _
"Requestor.Name, SecondaryRequestor.Name FROM " & _
"((ReconciliationMaster RM INNER JOIN Reconciliation_Fund RF ON RF.ReconciliationID = RM.ReconciliationID) " & _
"LEFT JOIN (SELECT Preferred_Name + ' ' + Last_Name AS Name, People_ID FROM " & _
"[Provider=sqloledb;Server=servername;Database=database;Trusted_Connection=Yes].PeopleMain) Requestor " & _
"ON Requestor.People_ID = RM.PrimaryRequestor) LEFT JOIN (SELECT Preferred_Name + ' ' + Last_Name AS Name, " & _
"People_ID FROM [Provider=sqloledb;Server=servername;Database=database;Trusted_Connection=Yes].PeopleMain) " & _
"SecondaryRequestor ON SecondaryRequestor.People_ID = RM.SecondaryRequestor WHERE RM.ReconciliationID = 522;"
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
cn.Open conn
rs.Open ss, cn
Sheet1.Cells.ClearContents
Sheet1.Range("A1").CopyFromRecordset rs
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
MsgBox "done"
End Sub
Thanks
Kashif
Access allows querying and joining in ODBC data sources, not OLEDB data sources.
Change the connection string used inside your query to an ODBC string:
[ODBC;Driver={SQL Server};Server=servername;Database=database;Trusted_Connection=Yes].PeopleMain
When available, I recommend using a more up-to-date ODBC driver, of course.

runtime error 3704 on a opened object

I am struggling with this situation
I have a query that when i run in MSSQL server management studio it gives me 18 rows, it it stored in a cell. The database is connected to a live server and we would like to create Excel dashboards out of them so it get refreshed with live data and create graph etc....
***** EDIT *****
I tried a very simple query and it works i can get for example
select max(datetime)from table and i do have the latest sync.
The thing is: my query has
1) A Declared table for validation
2) A temporary table "with table as( ) ;" that sorts all data and rank them with some filtering "RowNumber" that is called later in with a where statement that take only some row numbers to avoid repeats
I think that in between the connection must close, can it be?
Normally this code works out but for this server i get:
"runtime error 3704 operation is not allowed when the object is closed"
I've searched the forum and the google with no luck
Dim con As ADODB.Connection
Dim rs As ADODB.Recordset
Dim query As String
Set con = New ADODB.Connection
Set rs = New ADODB.Recordset
strCon = "Provider=SQLOLEDB.1;" _
& "Password=*******;" _
& "Persist Security Info=True;" _
& "User ID=********;" _
& "Initial Catalog=*******;" _
& "Data Source=***.**.**.**;" _
& "Use Procedure for Prepare=1;" _
& "Auto Translate=True;Packet Size=4096;" _
& "Use Encryption for Data=False;" _
& "Tag with column collation when possible=False"
con.Open (strCon)
rs.ActiveConnection = Con 'modified with suggestion below
strSQLQuery = Worksheets("Query").Range("B2").Value
rs.Open strSQLQuery
For i = 0 To rs.Fields.Count - 1
Sheet2.Cells(1, i + 1) = rs.Fields(i).Name
Next i
Worksheets("Result").Range("A2").CopyFromRecordset rs
rs.Close
Set rs = Nothing
con.Close
Set cn = Nothing
Can a magician help me out? because now im doing it with excel VBA as a demo but i would like to promote it to a VB tool and want to make sure it is not a server related issue.
Thank you in advance
con.Open (strCon)
rs.ActiveConnection = strCon
should be
con.Open strCon
rs.ActiveConnection = con
ie. you should set ActiveConnection to the Connection object you just opened, not to the connection string.

SQL query that uses a range in excel as the criteria

I use external data from an SQL query in excel to pull data onto a spreadsheet then the spreadsheet can be sent to one of my colleges in say the sales department and they can view the queried information.
I want to be able to have a cell that they can enter data into and press a refresh button.
So I need to do some thing like this:
SELECT Customer.CustomerCode, Customer.Name,
OrderHeader.OrderType, OrderHeader.OrderNumber
FROM Customer INNER JOIN
OrderHeader ON Customer.CustomerID = OrderHeader.CustomerID
WHERE (OrderHeader.OrderType = 2) AND (OrderHeader.OrderNumber = Range("A1").Value)
Not sure how or if this is possible and the reason I need to do this is because i'm going through lines from all the Quotes and if there is over 65536 then i'll have a problem.
This is what I have at the moment the SQL is different but that doesn't matter
The easiest way is to pull the values for the parameters into VBA, and then create the SQL statement as a string with the parameter values, and then populate the commandtext of the query.
Below is a basic example of the parameter in cell A1.
Sub RefreshQuery()
Dim OrderNo As String
Dim Sql As String
' Gets value from A1
OrderNo = Sheets("Sheet1").Range("A1").Value
'Creates SQL Statement
Sql = "SELECT Customer.CustomerCode, Customer.Name, " & _
"OrderHeader.OrderType , OrderHeader.OrderNumber " & _
"FROM Customer " & _
"INNER Join OrderHeader ON Customer.CustomerID = OrderHeader.CustomerID " & _
"WHERE (OrderHeader.OrderType = 2) And (OrderHeader.OrderNumber = " & OrderNo & ") "
With ActiveWorkbook.Connections(1).ODBCConnection
.CommandText = Sql
.Refresh
End With
End Sub
This assumes you have the query in Excel to begin with, and that it's the only query. Otherwise you'll have to define the name of the query as below:
With ActiveWorkbook.Connections("SalesQuery").ODBCConnection
I hope that helps :)
Further to #OWSam's example using ODBC, we can also use ADO to pull back query results from SQL Server. Using ADO, you cannot use windows verification and you will need the user to input their password somehow, to be able to run the query.
Personally I create a userform which has UserName and Password. Username pre-populated using Environ, and then they can type their password into the relevant TextBox.
Sub sqlQuery()
Dim rsConn As ADODB.Connection, rsData As ADODB.Recordset
Dim strSQL As String, winUserName As String, pwd As String
winUserName = UCase(Environ("username"))
pwd = "mypassword" 'password needed here.
strSQL = "SELECT * FROM mydatabase" 'query
Set rsConn = New ADODB.Connection
With rsConn
.ConnectionString = "Provider = sqloledb;" & _
"Data Source = [server name here];" & _
"Initial Catalog = [initial database];" & _
"Integrated Security=SSPI;" & _
"User ID = " & winUserName & ";" & _
"Password = " & pwd & ";"
.Open
End With
Set rsData = rsConn.Execute(strSQL)
Range("A1").CopyFromRecordset rsData
End Sub
Edit: You must go into references and turn on the Microsoft ActiveX Data Objects Recordset 6.0 library (or equivalent within your VBE).

Resources