Using SQL in VBA

There are two files available:

The files demonstrates how to use SQL in Excel to:

  • create a database,
  • create a table and add data to it,
  • select data from a table,
  • delete a table,
  • delete a database.
13-Mar-2011 Author's note: The demo files have been updated and both now include a "Run All" procedure as a way of testing the overall functionality. For the DAO file the procedure is BygDao_RunAll and for ADO it's BygAdo_RunAll.You can find them either by inspecting the VBA code, or by clicking on VBA in the sheet, "05_CodeNotes".
 
Below is a short overview of the file and some of the code.
 
I have tried to make the code simple so you can follow what I am trying to achieve and consequently I have restricted error checking to a bare minimum. If you choose to use this code in your own application, please remember that more error checking will probably be required. 
 
Where ever possible I have used SQL code because it is widely known and more likely to make sense to anyone who has had database experience and now wants to use Excel as a front-end to an Access back-end. There are two cases, in this demonstration, where SQL code can't be used.
 
Below are lists of SQL data definition and manipulation commands.
Those in
BLUE are covered in the workbook.
 
Data Definition

CREATE TABLE
CREATE INDEX
ALTER TABLE
CONSTRAINT
DROP 

Data Manipulation

SELECT
SELECT … INTO
INSERT
INSERT … INTO
UPDATE
DELETE

INNER JOIN
LEFT JOIN, RIGHT JOIN
PARAMETERS
UNION

CREATE TABLE
The first task is to create a database. I use two routines: "CreateADatabase" to do the donkey work, and "CreateDb" as a cover which can be used anywhere in your code. 
 
(Please note: these examples are from the DAO workbook)
Sub CreateDb()
'' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
'' Purpose  : Cover to create an Access database
'' Written  : 20-Oct-1999 by Andy Wiggins, BygSoftware.com
'' Revised  : 11-Nov-2010 by Andy Wiggins, BygSoftware.com
''
Dim lStr_Db As String

    lStr_Db = ThisWorkbook.Path & Application.PathSeparator & gConStr_Db & ".mdb"
    
    '' Test for the demo database's existance
    If Len(Dir(lStr_Db)) > 0 Then
        '' If the database already exists, we don't need to create it
    Else
        '' Otherwise, create it
        CreateADatabase lStr_Db
    End If

End Sub
 
Sub CreateADatabase(aStr_DbName As String)
'' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
'' Purpose   : Create an Access database
'' Written   : 03-Jul-1997 by Andy Wiggins, BygSoftware.com
''
Dim lObj_Dbs As Database
Dim lStr_Message As String

On Error GoTo ErrorHandler
     
    '' See "CreateDatabase Method" in help for available options
    Set lObj_Dbs = Workspaces(0).CreateDatabase(aStr_DbName, dbLangGeneral, dbVersion30)  'dbVersion20) for Jet v2
    Set lObj_Dbs = Nothing
    
Exit Sub

ErrorHandler:

    lStr_Message = "Database creation error"
    lStr_Message = lStr_Message & _
        Chr(10) & _
        Chr(10) & "Error Number: " & Err & _
        Chr(10) & "Error Description: " & Error()
    
    MsgBox lStr_Message, vbInformation, gConStr_Byg

End Sub
 
INSERT
This routine does a lot of work. It opens the database so it is ready to receive new data, creates a new table, copies the data from an Excel range into the table, and closes the database.
Sub CreateTableAndAddData()
'' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
'' Purpose  : Create a table from a range on a sheet
'' Written  : 19-Oct-1999 by Andy Wiggins, BygSoftware.com
''
Dim lObj_Dbs As Database
Dim lLng_Cols As Long
Dim lLng_Rows As Long
Dim lLng_Count As Long
Dim lLng_RCount As Long
Dim lStr_WrapChar As String
Dim lStr_Sql As String
Dim lStr_Message As String

On Error GoTo ErrorHandler
    
    ThisWorkbook.Activate
    
    '' - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    '' Open the database
    Set lObj_Dbs = OpenDatabase(ThisWorkbook.Path & Application.PathSeparator & gConStr_Db)
    
    '' - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    '' Go to the top left corner of the range
    Application.GoTo reference:=Range("rtlData")
    
    ''Get some info about the range
    With ActiveCell.CurrentRegion
        lLng_Cols = .Columns.Count
        lLng_Rows = .Rows.Count
    End With

    '' - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    '' Ensure the target table does not exist - careful, there's no recovery
    '' if you delete a table that you wanted.
    '' This users an error-handling routine to check for the table's existance
    On Error Resume Next
    lStr_Sql = ""
    lStr_Sql = lStr_Sql & " DROP TABLE " & gConStr_Sheet
    lObj_Dbs.Execute lStr_Sql
    On Error GoTo ErrorHandler

    '' - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    '' Create the table
    '' Go to the top left cell in the current range
    ActiveCell.CurrentRegion.Cells(1, 1).Select
      
    lStr_Sql = ""
    lStr_Sql = lStr_Sql & " CREATE TABLE " & gConStr_Sheet & " ("

    '' Loop around each column to create the SQL code
    '' Column names must not contain spaces
    With ActiveCell.CurrentRegion
        For lLng_Count = 1 To lLng_Cols
            lStr_Sql = lStr_Sql & .Cells(1, lLng_Count) & "x " & fGetCellFormat(.Cells(2, lLng_Count))
            If lLng_Count <> lLng_Cols Then
                lStr_Sql = lStr_Sql & ", "
            Else
                lStr_Sql = lStr_Sql & ")"
            End If
        Next
    End With
    
    '' This has created the following SQL code ...
    
    ''CREATE TABLE DataSource
    ''  (Staff_Nox NUMBER,
    ''     Salaryx CURRENCY,
    ''       Namex TEXT,
    ''      Boolyx BIT,
    ''     Regionx NUMBER,
    ''       Datex DATETIME)
        
    ''.. which is exexcuted in the database
    lObj_Dbs.Execute lStr_Sql

    '' Note: I have concatenated an "x" to the field name to try
    ''       and avoid reserved word conflicts in Access, e.g., if
    ''       a column was called "Date"

    '' - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    '' Insert data into the table
    With ActiveCell.CurrentRegion
        For lLng_RCount = 2 To lLng_Rows
            
            lStr_Sql = ""
            lStr_Sql = lStr_Sql & " INSERT INTO " & gConStr_Sheet
            lStr_Sql = lStr_Sql & " VALUES ("

            For lLng_Count = 1 To lLng_Cols
                Select Case fGetCellFormat(.Cells(2, lLng_Count))
                    Case "TEXT"
                        lStr_WrapChar = """"
                    Case "DATETIME"
                        lStr_WrapChar = "#"
                    Case Else
                        lStr_WrapChar = ""
                End Select
                
                lStr_Sql = lStr_Sql & lStr_WrapChar & .Cells(lLng_RCount, lLng_Count) & lStr_WrapChar
                
                If lLng_Count <> lLng_Cols Then
                    lStr_Sql = lStr_Sql & ","
                Else
                    lStr_Sql = lStr_Sql & ")"
                End If
            Next
            lObj_Dbs.Execute lStr_Sql
        Next
    End With

    '' - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    '' Close and tidy up
lbTidy:
    lObj_Dbs.Close
    Set lObj_Dbs = Nothing

Exit Sub

    '' - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ErrorHandler:

    lStr_Message = "Table and data creation error"
    lStr_Message = lStr_Message & _
        Chr(10) & _
        Chr(10) & "Error Number: " & Err & _
        Chr(10) & "Error Description: " & Error()
    
    MsgBox lStr_Message, vbInformation, gConStr_Byg

    Resume lbTidy

End Sub
     
SELECT
Sub SelectAndReturnRecords()
'' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
'' Purpose  : Select records from a table
'' Written  : 19-Oct-1999 by Andy Wiggins, BygSoftware.com
''
Dim lObj_Dbs As Database
Dim lObj_Rs As Recordset
Dim lStr_Sql As String
Dim lLng_NumberOfRows As Long

On Error GoTo ErrorHandler
    
    ThisWorkbook.Activate
    
    '' - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    '' Open the database
    Set lObj_Dbs = OpenDatabase(ThisWorkbook.Path & Application.PathSeparator & gConStr_Db)
    
    '' - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    '' The Execute method is valid only with action queries.
    '' Select queries contain a SELECT statement and can return records - action queries do not.
    lStr_Sql = ""
    lStr_Sql = lStr_Sql & " SELECT * "
    lStr_Sql = lStr_Sql & " FROM " & gConStr_Sheet
    lStr_Sql = lStr_Sql & " WHERE Namex Like 'R*'"

    Set lObj_Rs = lObj_Dbs.OpenRecordset(lStr_Sql)

    With ThisWorkbook.Sheets(gConStr_Target)
        With .Cells(1, 1)
            .CurrentRegion.Clear
            '' Copies the contents of a DAO Recordset object onto a worksheet
            lLng_NumberOfRows = .CopyFromRecordset(lObj_Rs)
        End With
    End With

    '' The number of rows returned, but ..
    '' MsgBox lLng_NumberOfRows

    '' .. here's an alternative
''     With lObj_Rs
''         .MoveFirst                  ''Ensure we are at the first record before we go into the loop
''         .MoveLast                   ''Access/Jet thing - go here before counting
''         fRecordCount = .RecordCount ''Count the number of records
''     End With

    '' - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    '' Close and tidy up
lbTidy:
    lObj_Dbs.Close
    
    Set lObj_Dbs = Nothing
    Set lObj_Rs = Nothing

Exit Sub
     

Published: 2003
Last edited: 13-Mar-2011 18:43