Running SQL queries from inside spreadsheet cells - sql-server

I have an Excel spreadsheet with several SQL queries stored in different cells and I'd like to execute these queries on SQL Server to generate a new sheet where each cell is the query result from the original spreadsheet. The idea behind this is to preserve the sheet formatting when generating the results (conditional formatting and etc.).
Something like this:
Input spreadsheet:
Database
Information A
Information B
DB 1
SQL Query 1
SQL Query 2
DB 2
SQL Query 3
SQL Query 4
Output spreadsheet:
Database
Information A
Information B
DB 1
Result of Query 1
Result of Query 2
DB 2
Result of Query 3
Result of Query 4
I wasn't able to find ideas on how to do exactly this during my research of the subject, but I do believe it should be doable using either VBA or some scripting language.
Any thoughts on how should I approach this?

I've got it done using Power Query. It was way easier than I thought. Special thanks to Jacek Wróbel for providing the idea in the comments.

As an aside, you could do something like this.
Sub ADOExcelSQLServer()
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 = "EXCEL-PC\SQLEXPRESS" ' Enter your server name here
Database_Name = "Northwnd" ' Enter your database name here
User_ID = "" ' enter your user ID here
Password = "" ' Enter your password here
SQLStr = "SELECT * FROM Orders" ' 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
With Worksheets("Sheet1").Range("A1:Z500")
.ClearContents
.CopyFromRecordset rs
End With
rs.Close
Set rs = Nothing
Cn.Close
Set Cn = Nothing
End Sub
That sits in a VBA Module. Of course, you could store the SQL in an Excel cell, and do this...
SQLStr = Worksheets("Sheet1").Range("A1").Value
Also, you could loop through a bunch of cells and run a bunch of SQL jobs.
Your own imagination is your only limitation.

Related

Create refreshable Excel spreadsheet from SQL Server

I'm making an Excel report using 3 SQL Server queries one of which selects into a temp table and I want the result of these select statements into an Excel table. I am new to Excel what is a good way to display the query result as a table and be able to refresh the table with new data from these 3 queries? I've read about power query is this a good option?
my queries
Select into temp table
join temp table with table
join temp table with table
union above 2 into 1 result table
Ended up using Data->Get Data->From Database to load the SQL data into excel and the refresh button will update the table.
Can you try this?
Sub ImportFromSQLServer()
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 = "your_server_name"
Database_Name = "your_database_name"
'User_ID = "******"
'Password = "****"
SQLStr = "select distinct ID from mytable1"
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
With Worksheets("Sheet1").Range("A1")
.ClearContents
.CopyFromRecordset RS
End With
RS.Close
Set RS = Nothing
Cn.Close
Set Cn = Nothing
End Sub
Also, set a reference to Microsoft ActiveX Data Objects 2.8 Library (Tools > References).

while exporting data to excel from sql using openrowset getting error

I am getting error while exporting data from SQL to already created .xlsx file. I used openrowset.
It works fine most of times, but when the data comes in of the field as a large string, while inserting in excel it shows error as:
the statement has been terminated , string or binary data would be
truncated.
Data gets inserted in table but while inserting in excel this error comes.
Please help me find the solution.
So, going form SQL Server to Excel, you can do many things. Check out thins link:
https://www.excel-sql-server.com/excel-sql-server-import-export-using-vba.htm#Introduction
Also, here is some VBA code to move data from SQL Server to Excel:
Sub ADOExcelSQLServer()
' Carl SQL Server Connection
'
' FOR THIS CODE TO WORK
' In VBE you need to go Tools References and check Microsoft Active X Data Objects 2.x library
'
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 = "EXCEL-PC\EXCELDEVELOPER" ' Enter your server name here
Database_Name = "AdventureWorksLT2012" ' Enter your database name here
User_ID = "" ' enter your user ID here
Password = "" ' Enter your password here
SQLStr = "SELECT * FROM [SalesLT].[Customer]" ' 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("sheet1").Range("a1:z500") ' 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

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

Importing more than 1000 rows from Excel to SQL-server

The process is run in the environment of Excel VBA 2010 and MS SQL Server 2008.
Assume that there is a simple one column data with 1500 rows in an Excel-sheet and we want to export it to the database with SQL-queries in VBA code (SQL procedure in VBA exports maximum 1000 rows at once in default mode).
There is one limitation in this problem: the export procedure must be with dbclass-connection instead of ADODB connection. (The code-owner is not me. The code-owner is using dbclass for a quite big VBA code, so probably he wouldn't accept to change the whole code).
I found an option like lngRecsAff for ADODB.Connection which is used like:
Sub test()
Dim cn As ADODB.Connection
Dim strSQL As String
Dim lngRecsAff As Long
Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\test.xls; Extended Properties=Excel 8.0"
strSQL = "Insert INTO [odbc;Driver={SQL Server};Server=SQL09;Database=Tom;UID=userID;PWD=password].tbl_test1 Select * FROM [Sheet1$]"
cn.Execute strSQL, lngRecsAff
cn.Close
Set cn = Nothing
End Sub
I tried to implement that lngRecsAff in my dbclass execution like:
Sub test()
Dim connOk As Boolean
Dim rs As New ADODB.Recordset
Set dbclass = New clsDB
Dim Value1() As Variant
Dim lngRecsAff As Long
Dim strSQL as String
Dim mstrErr as Boolean
dbclass.Database = "database_name"
dbclass.ConnectionType = SqlServer
dbclass.DataSource = "server_name"
dbclass.UserID = Application.UserName
connOk = dbclass.OpenConnection(False, True)
If connOk = False Then
MsgBox "Unsuccessful connection!"
Else
MsgBox "Successful connection"
End If
strSQL = "INSERT INTO [dbo].[table1](Column1) Values('" & Value1 & "')"
mstrErr = dbclass.ExecuteSQL(strSQL, lngRecsAff) ' The result mstrErr is a Boolean
' Some closing options here
End Sub
I got en error like lngRecsAff is not suitable for my ExecuteSQL procedure. Normally my execution mstrErr = dbclass.ExecuteSQL(strSQL) works without any problem.
Maybe I can do the SQL-procedure with a for-loop, then I can send the data in small pieces. But I want to find a more efficient, "nicer" solution which sends the whole array at once.
So is there any special option for dbclass which can send more than 1000 rows from Excel to the database?
You can query the Excel-Sheet directly using liked server.
In your Management Studio click to "Server Objects" and then right click onto "linked server". There you'll be able to add a new linked server.
If you need further help you can find tuorials easily. One is here:
https://www.mssqltips.com/sqlservertip/2018/using-a-sql-server-linked-server-to-query-excel-files/

Updating SQL SERVER Database from EXCEL

I have an excel sheet with some data:
1. Inventory item number
2. Description
3. Inventory Database ID (PRIMARY KEY)
I have about 1000 rows. I want to delete the item numbers in the database that match the item number in my excel list. I can write an application to do that in .NET, but that just seems overly complicated.
Is there an easy way through excel or SQL Server to run a sql statement to delete item numbers in my excel sheet with out the trouble of creating an application?
For quick updates. I find this to be the best method.
Add a column to Excel and construct your update statement as a formula, ie:
="DELETE Table1 WHERE ItemNumber='"&A1&"' AND InventoryId = "&C1
Copy the formula down, and copy/paste the result into an SQL window and run it.
Pro tip, if you have a lot of apostrophes to deal with, it might be worth it to do a global find/replace beforehand. Or you can deal with them from the formula. ie:
="DELETE Table1 WHERE ItemNumber='"&SUBSTITUTE(A1,"'","''")&"' AND InventoryId = "&C1
If you do not want to go through a SQL interface, you can run the attached code from excel, after updating the connection string obviously.
Sub ExecuteSQLCommand()
'Execute the SQL string passed through
Dim conn As ADODB.Connection, strConn As String, sSQLCommand As String
Dim cmd As ADODB.Command, lLoop As Long, lLastRow As Long
Set conn = New ADODB.Connection
conn.ConnectionString = "Provider=SQLOLEDB;" & _
"Data Source=DCC08SQL;" & _
"Initial Catalog=HarvestPress;" & _
"Integrated Security=SSPI;" & _
"Database=HarvestPress;" & _
"Trusted_Connection=True;"
conn.Open
Set cmd = New ADODB.Command
lLastRow = Cells(Rows.Count, 1).End(xlUp).Row
With cmd
.ActiveConnection = conn
.CommandType = adCmdText
For lLoop = 1 To lLastRow
sSQLCommand = "DELETE FROM Table1 WHERE ItemNumber='" & Cells(lLoop, 1) & "' AND InventoryId = " & Cells(lLoop, 1)
.CommandText = sSQLCommand
.Execute
Next lLoop
End With
conn.Close
Set conn = Nothing
Set cmd = Nothing
End Sub

Resources