I'm beginner in Excel VBA and your help is much appreciated.
Please advice how can I create a common function to Open and database connection, and another function to close it, to avoid duplication of coding?
Here is my code. I'm stuck on how to move on...
Const connection_string As String = "Provider=SQLOLEDB.1;Password=XXX;Persist Security `Info=True;User ID=sa;Initial Catalog=TESTDB;Data Source=XXXX;"
Sub DuplicateDBConnection()
'Declare variables
Set cn1 = New ADODB.Connection
Set cmd1 = New ADODB.Command
Set rs1 = New ADODB.Recordset
'Open Connection
cn1.ConnectionString = connection_string
cn1.Open
'Set and Excecute SQL Command
Set cmd1.ActiveConnection = cn1
cmd1.CommandText = "Select stock_code, name, sector_id from stock_master"
cmd1.CommandType = adCmdText
cmd1.Execute
'Open Recordset
Set rs1.ActiveConnection = cn1
rs1.Open cmd1
'Copy Data to Excel
ActiveSheet.Range("A1").CopyFromRecordset (rs1)
'Close Connection
rs1.Close
cn1.Close
'Throw Object
Set rs1 = Nothing
Set cn1 = Nothing
End Sub
My wish is to write common functions so that I don't need to keep writing code to connect and close connection.
Sub ConnectDB()
'Codes to connect DB
End Sub
Sub CloseConnnection()
'Codes to close connection
End Sub
Sub ExecuteCode()
ConnectDB
'Execute SQL command to manipulate data on excel and SQL database
CloseConnection
End Sub
Edit based on Kittoe's suggestions and works properly now. Thanks!
Class: a. Created a class called AdoDbHelper, Private Instancing b. In AdoDbHelper, change "Option Compare Database" to "Option Compare Text"
Module: Create a function like this.
Code below:
Const connection_string As String = "Provider=SQLOLEDB.1;Password=XXX;Persist Security `Info=True;User ID=sa;Initial Catalog=TESTDB;Data Source=XXXX;"
Sub Test()
Dim sourceDb As New AdoDbHelper
Dim sourceRs As New ADODB.Recordset
sourceDb.Connect (connection_string)
Set sourceRs = sourceDb.OpenRecordset("Select stock_code, name, sector_id from stock_master")
With sourceRs
'Do stuff!
ActiveSheet.Range("A1").CopyFromRecordset sourceRs
.Close
End With
sourceDb.Disconnect
Set sourceRs = Nothing
Set sourceDb = Nothing
End Sub
This type of stuff is best done in a class. Right click your VBA project in the "IDE" and go to Insert -> Class Module. Name your class something meaningful like clsAdoHelper (if Hungarian Notation is your thing), AdoDbHelper, or something. The following is an example of the code you'd put in this class:
Option Compare Database
Option Explicit
Private WithEvents conn As ADODB.Connection
Private WithEvents rs As ADODB.Recordset
Public Sub Connect(ConnectionString As String)
If Not conn Is Nothing Then
Debug.Print "A connection is already open."
Exit Sub
End If
If ConnectionString = CurrentProject.Connection.ConnectionString Then
Set conn = CurrentProject.Connection
Else
Set conn = New ADODB.Connection
conn.Open ConnectionString
End If
End Sub
Public Sub Disconnect()
If Not conn Is Nothing Then
If conn.State <> 0 Then
conn.Close
End If
Set conn = Nothing
End If
End Sub
Public Sub Execute(SQL As String)
If conn Is Nothing Then
Debug.Print "No connection open."
Exit Sub
End If
conn.Execute (SQL)
End Sub
Public Function OpenRecordset(SQL As String, Optional CursorLocation As ADODB.CursorLocationEnum = adUseClient, Optional CursorType As ADODB.CursorTypeEnum = adOpenForwardOnly, Optional LockType As ADODB.LockTypeEnum = adLockReadOnly) As ADODB.Recordset
If conn Is Nothing Then
Debug.Print "No connection open."
Exit Function
End If
If Not rs Is Nothing Then
Debug.Print "A recordset is already open."
Exit Function
End If
Set rs = New ADODB.Recordset
With rs
.CursorLocation = CursorLocation
.CursorType = CursorType
.LockType = LockType
.Open SQL, conn
End With
Set OpenRecordset = rs
End Function
Public Sub BeginTransaction()
conn.BeginTrans
End Sub
Public Sub CommitTransaction()
conn.CommitTrans
End Sub
Public Sub RollbackTransaction()
conn.RollbackTrans
End Sub
Private Sub conn_BeginTransComplete(ByVal TransactionLevel As Long, ByVal pError As ADODB.Error, adStatus As ADODB.EventStatusEnum, ByVal pConnection As ADODB.Connection)
Debug.Print "Transaction started."
End Sub
Private Sub conn_CommitTransComplete(ByVal pError As ADODB.Error, adStatus As ADODB.EventStatusEnum, ByVal pConnection As ADODB.Connection)
Debug.Print "Transaction committed."
End Sub
Private Sub conn_ConnectComplete(ByVal pError As ADODB.Error, adStatus As ADODB.EventStatusEnum, ByVal pConnection As ADODB.Connection)
End Sub
Private Sub conn_Disconnect(adStatus As ADODB.EventStatusEnum, ByVal pConnection As ADODB.Connection)
End Sub
Private Sub conn_ExecuteComplete(ByVal RecordsAffected As Long, ByVal pError As ADODB.Error, adStatus As ADODB.EventStatusEnum, ByVal pCommand As ADODB.Command, ByVal pRecordset As ADODB.Recordset, ByVal pConnection As ADODB.Connection)
Debug.Print "SQL execution complete."
End Sub
Private Sub conn_RollbackTransComplete(ByVal pError As ADODB.Error, adStatus As ADODB.EventStatusEnum, ByVal pConnection As ADODB.Connection)
Debug.Print "Transaction rolled back."
End Sub
Using your new class:
Dim sourceDb As New AdoDbHelper
Dim sourceRs as New ADODB.Recordset
sourceDb.Connect (<insert connection string here>)
Set sourceRs = sourceDb.OpenRecordSet(<insert SQL string here>)
With sourceRs
'Do stuff!
.Close
End With
sourceDb.Disconnect
Set sourceRs = Nothing
Set sourceDb = Nothing
It's not exactly the best code I've ever written but it should give you a decent start. If you have trouble understanding how the class works I encourage you to do a little research on OOP and classes in VBA. You'll notice that you still have a little bit of necessary biolerplate code here but the bulk of the normal work has been taken care of for you in the class methods. If you wanted to put the data manipulation logic into a function of it's own you could pass it the ADODB.Recordset object that you create using the class (this would replace the WITH
blocks).
I wouldn't suggest polluting the class with such logic as you want the class to handle all of your generic connect/disconnect/exception handling for any possible ADODB connections. That way you can reuse it in other projects =D.
Use the Microsoft ActiveX Data Objects Library x.x:
In your VBA window go to Tools> References > Microsoft ActiveX Data Objects Library x.x
I usually use 2.7 for downward compatibility. Now you can create ADODB objects to open connections, perform queries (select/update/delete/...) and use the query results (called record sets) to the rest of your excel, into tables, in specific cells.
To be sure to use the same connection all the time, create a Public connection object and refer to that in all your subroutines. In each subroutine first check if it is already set up by (conn
being my ADODB.Connection
object):
If conn = Nothing Then Call Setup_Connection
And the Subroutine Setup_Connection being something like:
Private Sub Setup_Connection
Dim strConnection as String
If conn = Nothing Then
'Choose your own database connection details
strConnection = "Provider=SQLOLEDB.1;Integrated Security=SSPI;" & _
"Persist Security Info=False;" & _
"Initial Catalog=DatabaseName;" & _
"Data Source=DATABASESERVER"
Set conn = New ADODB.Connection
With conn
.Open strConnection
.CommandTimeout = 30
End With
End If
End Sub
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With