Excel VBA to SQL Server without SSIS - sql-server

Excel problem: User clicks a button and VBA parses an input file, putting data into cells in the spreadsheet. Then she mails copies of the spreadsheet to people who do work with the data.
I am to replace this with SSRS or ASP or Sharepoint displaying the data from SQL Server.
In order to work on this without interrupting the current process, I'd like to have the Excel VBA, each time it writes a row to the spreadsheet, also insert it into the SQL Server DB via stored proc.
I can have it write the row in CSV to a file for later SSIS import, but I'd rather go direct to the DB.
I know how to do it in VB.Net but I've never written data in VBA (often read data into recordset but not written).
I'd prefer to pass the values as params to a stored proc, but I could generate the slower INSERT command for each row if I have to.

From VBA, the easiest data-access library to use is ADO. Add a reference to "Microsoft ActiveX Data Objects Library" so that you can use the ADODB.* objects.
To execute a stored proc (which in your case will add a record to a table), you could do it:
...the lazy way (creating SQL statements directly, without using Parameter objects; this is prone to SQL-injection hacks):
Public Sub AddFoo _
( _
strServer As String, _
strDatabase As String, _
strUsername As String, _
strPassword As String, _
lFooValue As Long _
)
' Build the connection string
Dim strConnectionString As String
strConnectionString = "Driver={SQL Server}" _
& ";Server=" & strServer _
& ";Database=" & strDatabase _
& ";UID=" & strUsername _
& ";PWD=" & strPassword
' Create & open the connection
Dim oConnection As Connection
Set oConnection = New Connection
oConnection.ConnectionString = strConnectionString
oConnection.Open
' Build the SQL to execute the stored procedure
Dim strSQL As String
strSQL = "EXEC AddFoo " & lFooValue
' Call the stored procedure
Dim oCommand As Command
Set oCommand = New Command
oCommand.CommandType = adCmdText
oCommand.CommandText = strSQL
oCommand.ActiveConnection = oConnection
oCommand.Execute
oConnection.Close
End Sub
...or the correct way (which deals with encoding of all parameters, and is thus not prone to SQL-injection hacks - either deliberate or accidental):
Public Sub AddFoo _
( _
strServer As String, _
strDatabase As String, _
strUsername As String, _
strPassword As String, _
lFooValue As Long _
)
' Build the connection string
Dim strConnectionString As String
strConnectionString = "Driver={SQL Server}" _
& ";Server=" & strServer _
& ";Database=" & strDatabase _
& ";UID=" & strUsername _
& ";PWD=" & strPassword
' Create & open the connection
Dim oConnection As Connection
Set oConnection = New Connection
oConnection.ConnectionString = strConnectionString
oConnection.Open
' Build the SQL to execute the stored procedure
Dim strSQL As String
strSQL = "EXEC AddFoo " & lFooValue
' Create the command object
Dim oCommand As Command
Set oCommand = New Command
oCommand.CommandType = adCmdStoredProc
oCommand.CommandText = "AddFoo"
' Create the parameter
Dim oParameter As Parameter
Set oParameter = oCommand.CreateParameter("foo", adParamInteger, adParamInput)
oParameter.Value = lFooValue
oCommand.Parameters.Add oParameter
' Execute the command
oCommand.ActiveConnection = oConnection
oCommand.Execute
oConnection.Close
End Sub

How do you read data with VBA?
If you use ADO recordsets: Have a look at the ADODB.Command class; this allows you to execute SQL or stored procedures and pass parameters to it (Google for ado command example).
If you use DAO recordsets: The Execute method of your DAO database allows you execute SQL statements.

In the long run, people are finally beginning to accept a better way: automation (not a button click) reads the file directly into the DB (SSIS), and people who need the data look at a report instead of an e-mailed Excel file.

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

vba ActiveX can't create odbc.connection object

I'm trying to create ODBC connection in order to be able to perform a simple sql query on one of the tables from my SQL DB.
Below is my code and I'm not sure what I'm doing wrong but I keep getting ActiveX can't create an object error and the following line is highlighted: Set con = CreateObject("ODBC.Connection").
Private Sub findBtn_Click()
Dim s
Dim con As Object 'OdbcConnection
Dim strCon
Dim rsSearch
Dim strSql
Dim mystring As String
Dim cmd 'As OdbcCommand
s = Me.findTxt
mystring = "Select * from CUSTOMER where CUSTOMER.FORENAME1 like '%" & s & "%';"
Set con = CreateObject("ODBC.Connection")
con.Open "ODBC;Driver={SQL Server};" & _
"Server=localhost;" & _
"Database=Customers23;" & _
"UID=admin;" & _
"PWD=admin;"
Set cmd = CreateObject("ODBC.Command")
cmd = mystring
Me.resTxt = "Connected!"
MsgBox ("Connected")
End Sub
Try to replace ODBC.Connection with ADODB.Connection.
Same with ODBC.Command
You can find an example here How do I setup an ADODB connection to SQL Server 2008 in Microsoft Access 2010?
Also see that link on how to use the Command object.

Import Excel Data into SQL using VB6

I'm completely new to Visual Basic and I now need to take a program that is entirely constructed in VB6 and add the ability to import a large set of records in bulk from an excel file into the current SQL Database. all of the examples I have found online are confusing and require hard-coding of the file name (ex. Using document As New Spreadsheet() document.LoadFromFile("SimpleReport.xls")) yet this needs to be called by a user anytime they get a new set of records so I need the excel file name to be specified at time of import.
How do I import from excel to SQL using VB6? Can I make a variable for the excel filename or does the string value of the filename have to be hard coded? If I can make a variable can/should I add set and get to it in order to specify the filename? Thanks
With a 32 bit Machine (O/S):
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\myfile.xls;" & _
"Extended Properties=Excel 8.0"
'Import by using Jet Provider.
strSQL = "SELECT * INTO [odbc;Driver={SQL Server};" & _
"Server=<server>;Database=<database>;" & _
"UID=<user>;PWD=<password>].MyTable " & _
"FROM [MySheet$]"
Debug.Print strSQL
cn.Execute strSQL, lngRecsAff, adExecuteNoRecords
Debug.Print "Records affected: " & lngRecsAff
cn.Close
Set cn = Nothing
Microsoft KB : 321686 has more ideas.

How to create linked tables from MDB to SQL Server

I have an app which is having problems with data-access to an MDB database over a wireless network.
Would a quick solution be to have a local MDB file on all workstations that links all its tables to a SQL Server database?
Would this be a way to avoid having to re-write all data-access code in the app?
Yes, that will do pretty well. We have many customers connected in this way.
However it's not an easy task. Not sure if all the effort required will pay for itself.
And you have some new maintenance and deploying problems.
The steps to follow are this:
1) Migrate your tables to SQLServer
2) Create an ODBC Data Source that will be used to connect to your backend database
3) Connect your tables
4) Rename your connected tables to remove the schema qualifier (eg. "dbo_") so your linked tables have the same name as before.
Now it's time to test all your code.
Hopefully you will not have to rewrite anything.
The real problems lies on client PCs where you need to create an ODBC data source that match your original one. Also if you redistribute your front-end database it's possibile you have to reconnect all the tables from the client PCs.
You need to call a function like this:
Public Function UpdateODBCTables() As Boolean
On Error GoTo Exit_On_Error
Dim dbs As DAO.Database
Dim tdf As DAO.TableDef
Dim sDSN As String
Dim sDB As String
Dim sComputer As String
Dim sDesc As String
Dim sApp As String
Dim strConnect As String
sDSN = "YOUR_DSN_NAME"
sDB = "YOUR_DATABASE_NAME"
sComputer = "YOUR_COMPUTER_NAME"
sApp = "YOUR_APP_NAME"
sDesc = "DESCRIPTION_OF_YOUR_APP"
strConnect = "ODBC;DSN=" & sDSN & ";" & _
"DATABASE=" & sDB & ";" & _
"WSID=" & sComputer & ";" & _
"TrustedConnection=Yes;" & _
"Description=" & sDesc & ";" & _
"APP=" & sApp ";"
Set dbs = CurrentDb
' Loop over tabledefs of ODBC type and reconnect
For Each tdf In dbs.TableDefs
If tdf.Connect <> "" And Left(tdf.Connect, 4) = "ODBC" And Left(tdf.Name, 1) <> "~" Then
tdf.Connect = strConnect
tdf.RefreshLink
End If
Next
dbs.TableDefs.Refresh
UpdateODBCTables = True
Exit_On_Return:
Set dbs = Nothing
Exit Function
Exit_On_Error:
MsgBox Err.Description, vbCritical, "YOUR_MESSAGE_TITLE"
Resume Exit_On_Return
End Function

Resources