SQL query that uses a range in excel as the criteria - sql-server

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).

Related

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.

Pulling SQL info into Excel

I have been able in the past to create connections and pull in whole tables or even just a column or two from SQL into Excel.
Now what I want to for a user to input an ID into a Userform and then the VBA to run SQL code grabbing the cooresponding ID, FirstName, LastName. It should then paste that info into the first blank row of A,B,C on the "Entry" sheet.
I am getting an error on this line of code stating: Run-time error '1004' Application-defined or object-defined error.
With ActiveSheet.ListObjects.Add(SourceType:=0, Source:=Array("OLEDB;Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=True;Data Source=xxx.xxx.xxx.xxx;Use Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;Use Encryption for Data=False;Tag with column collation when possible=False;Initial Catalog=DBName"), Destination:=Sheets("Entry").Range("A1").End(xlDown).Offset(1, 0)).QueryTable
Most of this I do not understand it is simply some hand me down code that I am trying to re-purpose. The old code which still works is this:
With ActiveSheet.ListObjects.Add(SourceType:=0, Source:=Array( _
"OLEDB;Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=True;Data Source=xxx.xxx.xxx.xxx;Use Procedure for Prepare=1;Auto " _
, _
"Translate=True;Packet Size=4096;Use Encryption for Data=False;Tag with column collation when possibl" _
, "e=False;Initial Catalog=DBName"), Destination:=Range("Database!$A$1")). _
QueryTable
The difference between these is that instead of just dropping it in one set cell with the code pulling over couple hundred thousand lines of data is I want the code to be in the first blank row and only pull over that one record. But each time it runs it needs to go to the next row.
With the old code it made an actual table which I am guessing is related to the fact that at the end it states QueryTable. I would rather just have the data and not the table format. If there is a way to change it to do this that would be great.
Also in the previous version of this the query only pulled from one table and the .SourceConnectionFile = _ link to the file. The new code will need to link to two tables so there are two files as I was unable to have it make a connection file with two tables selected. If you can help with that as well that would be great.
I am using Excel 2013 Standard and SQL Server 2012. Please let me know if you need any more info.
So This is what I have so far trying the ADO method suggested by #Kyle. The OCR is the variable input from the Userform in previous code. When this runs it gives no error but it paste no data.
Sub Code()
Sheets("Entry").Select
On Error Resume Next
Const adOpenStatic = 3
Const adLockOptimistic = 3
Const adCmdText = &H1
Set objConnection = CreateObject("ADODB.Connection")
Set Objrecordset = CreateObject("ADODB.Recordset")
ConnectionString = "Provider=SQLOLEDB;Data Source=xxx.xxx.xxx.xxx;Initial Catalog=DBName;User ID=MyUN;Password=MyPW"
objConnection.Open
Objrecordset.Open "Select B.ID, B.Firstname, B.Lastname From TableA as A Join TableB as B on A.ID = B.ID Where A.Cardnumber =" & OCR, objConnection, adOpenStatic, adLockOptimistic, adCmdText
If Not Objrecordset.EOF Then
Sheets("Entry").Range("A1").End(xlDown).Offset(1, 0).CopyFromRecordset Objrecordset
Objrecordset.Close
Else
MsgBox "Did not Work"
End If
End Sub
So I was able to get it to work with this:
Sub Code()
Sheets("Entry").Select
Dim Cn As ADODB.Connection
Dim Server_Name As String
Dim Database_Name As String
Dim User_ID As String
Dim Password As String
Dim SQLStr As String
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
Server_Name = "" ' Enter your server name here
Database_Name = "" ' Enter your database name here
User_ID = "" ' enter your user ID here
Password = "" ' Enter your password here
SQLStr = "SELECT B.ID, B.FirstName, B.LastName From Table A Join Table B as B on A.ID = B.ID Where A.CardNumber ='" & OCR & "'" ' Enter your SQL here
Set Cn = New ADODB.Connection
Cn.Open "Driver={SQL Server};Server=" & Server_Name & ";Database=" & Database_Name & _
";Uid=" & User_ID & ";Pwd=" & Password & ";"
rs.Open SQLStr, Cn, adOpenStatic
' Dump to spreadsheet
With Worksheets("Entry").Range("A1").End(xlDown).Offset(1, 0) ' Enter your sheet name and range here
.ClearContents
.CopyFromRecordset rs
End With
' Tidy up
rs.Close
Set rs = Nothing
Cn.Close
Set Cn = Nothing
End Sub

VBA sql query based off combobox

I've been searching hard the past few days and have come across numerous examples that outline what I'm trying to do. However, I can't seem to get this working. I have a combobox that populates data (a company name) from a table when the form initializes. I then want to take the value chosen in the combo box and run another query to cross reference an id number in that same table.
Private Sub CommandButton1_Click()
Dim myCn As MyServer
Set myCn = New MyServer
Dim rs As ADODB.recordset
Set rs = New ADODB.recordset
Dim sqlStr As String
Dim CompField As String
'CompField = ComboBox1.Value
sqlStr = "SELECT DISTINCT [acctno] FROM client WHERE [company] = '" & ComboBox1.Text & "'"
'sqlStr = "Select DISTINCT [company] FROM client;"
' sqlStr = "SELECT DISTINCT [acctno] FROM client WHERE [company] = " & UserForm1.ComboBox1.Value & ";"
'sqlStr = "SELECT DISTINCT [acctno] FROM client WHERE [company] = " & UserForm1.ComboBox1.Text & ";"
'sqlStr = "SELECT DISTINCT [acctno] FROM client WHERE [company] = 'Company XYZ';"
'sqlStr = "SELECT DISTINCT [acctno] FROM client WHERE company = " & CompField & ""
rs.Open sqlStr, myCn.GetConnection, adLockOptimistic, adCmdText
MsgBox sqlStr
'MsgBox ComboBox1.Value
'MsgBox rs(0)
rs.Close
myCn.Shutdown
Set rs = Nothing
Set myCn = Nothing
End Sub
Currently with the combobox value encased in single quotes i get the entire sql string returned. If I remove the single quotes I get a syntax error referencing part of the combobox value. All other efforts have resulted in run-time errors that have led me nowhere.
I know my query works because I've tested it in SQL Studio and if I hard code a text value in this code I also get the Account ID I'm looking for. Not sure what I'm missing here.
Well I figured it out. I was expecting to be able to MsgBox the variable assigned to the SQL query and see my results. But it doesn't work that way. I had to use ADO GetString method for that and assign another variable. Oh and you were right about escaping, I had to add delimters to properly handle the ComboBox value in the query which ultimately looked like this
sqlStr = "SELECT DISTINCT [acct_no] FROM client WHERE [company] = " & Chr(39) & Me.ComboBox1.Value & Chr(39)
Thanks for your help on this

Using a Parameterized Query on a SQL Table in Excel using VBA

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.

Resources