In the previous post, we gave you some code to import from Excel into an existing table. That code is absolutely fine for most circumstances but we thought you might like to improve on it a little…
In this post, we add the ability to select your Excel file using a File Picker and a function that creates the table if it doesn’t already exist!
It is worth noting again that the success of an import from Excel is largely due to the preparation you give the Excel file.
The Code
Create a module called mod_Functions and add this code:
Option Compare Database Option Explicit Public Function getFilePath() As String 'The function will open up msoFileDialogFilePicker '(a standard windows file picker) that will enable 'the user to pick a file from their system On Error GoTo ErrorHandler With Application.FileDialog(msoFileDialogFilePicker) .AllowMultiSelect = False .Show getFilePath = .SelectedItems(1) End With ExitFunction: Exit Function ErrorHandler: getFilePath = "" Resume ExitFunction End Function Public Function getFolderPath() As String 'The function will open up msoFileDialogFolderPicker '(a standard windows file picker) that will enable 'the user to pick a folder from their system On Error GoTo ErrorHandler With Application.FileDialog(msoFileDialogFolderPicker) .AllowMultiSelect = False .Show getFolderPath = .SelectedItems(1) End With ExitFunction: Exit Function ErrorHandler: getFolderPath = "" Resume ExitFunction End Function Public Function getFileName(filePath As String) As String 'This function takes a full path to a file and returns just the 'name portion. 'e.g. C:\users\Robert\excel_file.xlsx will become excel_file.xlsx On Error GoTo ErrorHandler Dim posOfSlash As Integer Dim lenOfString As Integer Dim remChars As Integer posOfSlash = InStrRev(filePath, "\") lenOfString = Len(filePath) remChars = lenOfString - posOfSlash getFileName = Right(filePath, remChars) ExitFunction: Exit Function ErrorHandler: getFileName = "" Resume ExitFunction End Function Public Function MakeTable(strTableName As String, strFieldNames() _ As String) As Boolean 'This function takes a table name and an array of columns and 'creates a table with the relevant field names On Error GoTo ErrorHandler Dim strSQL As String Dim element As Variant strSQL = "CREATE TABLE " & strTableName & " (" For Each element In strFieldNames 'Debug.Print element strSQL = strSQL & element & " TEXT, " Next strSQL = Left(strSQL, Len(strSQL) - 2) & ")" CurrentDb.Execute strSQL, dbFailOnError MakeTable = True ExitFunction: Exit Function ErrorHandler: MakeTable = False Resume ExitFunction End Function
Now, create a module called mod_Excel_Importing and add this code:
Option Compare Database Option Explicit Public Sub GetData() On Error GoTo ErrorHandler Dim oExcel As Excel.Application Dim oWB As Workbook Dim oWS As Worksheet Dim strExcelFilePath As String Dim strExcelFileName As String Dim db As dao.Database Dim rs As dao.Recordset Dim i As Integer Dim j As Integer Dim lColumn As Long Dim lRow As Long Dim strFieldNames() As String Dim strTableName As String 'Select Excel file to import from 'This code will open up a standard Windows file picker MsgBox "Please select the Excel Workbook to import from" strExcelFilePath = getFilePath() strExcelFileName = getFileName(strExcelFilePath) 'Starts hourglass so user knows that the application is busy DoCmd.Hourglass True 'Starts Excel App in memory Set oExcel = New Excel.Application Set oWB = oExcel.Workbooks.Open(strExcelFilePath) 'Here we ask for the table name that we will be using strTableName = InputBox("Please provide the table name") '---------------------------------------------------------------- 'We check whether the supplied table name is the name of a table 'that already exists. If it doesn't exist, we create it. '---------------------------------------------------------------- If IsNull(DLookup("Name", "MSysObjects", "Name='" & _ strTableName & "'")) Then 'In order to create the table we need to know how many 'columns we require and the names of those columns 'For this we need to activate the Excel sheet and count 'the columns and retrieve their names With oWB .Activate 'Function to return number of columns lColumn = _ .Worksheets(1).Cells(1, Columns.Count).End(xlToLeft).Column 'We have an array called strFieldNames that we want 'to store the column names ReDim strFieldNames(lColumn - 1) 'add names of columns to strFieldNames by 'looping through the columns in the Excel 'sheet and retrieving the names For j = 0 To lColumn - 1 strFieldNames(j) = _ .Worksheets(1).Cells(1, j + 1).Value Next j End With 'We utilise the MakeTable function to create a table that 'we will be able to import into If MakeTable(strTableName, strFieldNames) = False Then _ Err.Raise -100, , "Unable to create table." End If '---------------------------------------------------------- 'Get data from Excel sheet '---------------------------------------------------------- 'Instantiate recordset - we will not be looping through here 'we will be using the recordset to add values as we go Set db = CurrentDb Set rs = db.OpenRecordset(strTableName) With oWB 'we will need to activate the workbook to 'reference its properties .Activate 'These two lines of code work out how many 'columns (lcolumn) and how many rows(lrow) of 'data there are to be imported in the Excel sheet lColumn = _ .Worksheets(1).Cells(1, Columns.Count).End(xlToLeft).Column lRow = _ .Worksheets(1).Cells(Rows.Count, 1).End(xlUp).Row 'add link to nested loops 'Here we will be using a nested loop 'to go to loop through the Excel sheet. 'Nested loops are necessary when looping 'through a grid of data such as a spreadsheet 'from 2nd row to last For i = 2 To lRow 'we tell the recordset that we will 'be adding a record here rs.AddNew 'From first column to last For j = 0 To lColumn - 1 'Here we are saying: 'Take the value of row i and column j 'and add it to the column 'that has an index of j!!! rs.Fields(j) = _ Nz(.Worksheets(1).Cells(i, j + 1).Value, "") Next j Debug.Print i 'This writes the update to the table rs.Update Next i 'close the recordset rs.Close End With DoCmd.Hourglass False MsgBox "Finshed" ExitSub: 'Always remember to set your objects to nothing 'when the procedure ends Set rs = Nothing Set db = Nothing Set oWB = Nothing Set oExcel = Nothing DoCmd.Hourglass False Exit Sub ErrorHandler: MsgBox "There has been an error. " & _ "Please reload the form and start again" Resume ExitSub End Sub
Using VBA to retrieve data from Excel is a little tricky at first as you need to familiarise yourself with the Excel object model. There are, however, definite rewards if you persist, as using Excel as a means of transferring information between databases is a very popular option!