I am using an Access Db to export some information to an Excel Workbook. I am using an input form to add dates to the query that creates the sheet. If I create 1 sheet the export works. If I create more than one sheet once the query goes to the second sheet the focus stays on the excel spreadsheet. If you enter a date it goes on cell A1 of the spreadsheet instead of the input box. Any help is appreciated.
Public Function ExportSpreadSheet(path As String)
Dim xlPath As String, I As Integer
Dim DB As Database
Dim myrs As Recordset ' Create a recordset to hold the data
Dim strSQL As String
Dim myExcel As New Excel.Application ' Create Excel with Early binding
Dim wrkbk As Object
Dim wrksht As Object
Dim targetworkbook As Excel.Workbook
Dim FileRange, name As String
Dim extraChar, queryForTransfer, searchSheet As String
Dim objXL As Object
Dim objAC As Object
Dim x As Integer
Dim myFileName As String
Dim sheetDate As String
Dim sheetName As String
Dim amtofsheets As Long
Dim s As Long
Dim ctlCurrentControl As Control
Dim strAnswer As String
On Error GoTo Err_ExportSpreadSheet
DoCmd.SetWarnings False
xlPath = path
amtofsheets = InputBox("Enter amount of sheets", "Amount of Sheets")
Set DB = CurrentDb
Set objAC = CreateObject("Access.application", "")
For s = 1 To amtofsheets
strAnswer = Forms("Browse1").txtFileSelection
sheetDate = InputBox("Enter Trade Date of Entries ex 10/04/2017", "Trade Date")
If s = 1 Then Set objXL = CreateObject("Excel.application", "")
If s = 1 Then objXL.Visible = True
If s = 1 Then objXL.DisplayAlerts = True
If s = 1 Then Set targetworkbook = objXL.Workbooks.Add
'Add worksheet if need more than three worksheets
strSQL = "SELECT FXOpenDeals.city, FXOpenDeals.[As of Date], FXOpenDeals.[Cnt Pty name], FXOpenDeals.[deal number], FXOpenDeals.value, FXOpenDeals.ccy1, FXOpenDeals.[ccy1 amt], FXOpenDeals.ccy2, FXOpenDeals.[ccy2 amt], FXOpenDeals.[unrealized G/L_PV] " _
& " FROM [A1-Internal_Customers] INNER JOIN FXOpenDeals ON [A1-Internal_Customers].[counterparty number] = FXOpenDeals.[counterparty number] " _
& " WHERE FXOpenDeals.[trade] = #" & Format(sheetDate, "mm/dd/yyyy") & "#" _
& " ORDER BY FXOpenDeals.[Cnt Pty name];"
Set myrs = DB.OpenRecordset(strSQL)
If amtofsheets = 1 Or amtofsheets = 2 Then
For I = 1 To targetworkbook.Worksheets.Count
sheetName = "Sheet" & I
Select Case sheetName
Case "Sheet2"
targetworkbook.Sheets("Sheet2").Delete
Case "Sheet3"
targetworkbook.Sheets("Sheet3").Delete
End Select
Next I
End If
If s > 3 Then
With targetworkbook
.Sheets.Add After:=Sheets(Worksheets.Count)
ActiveSheet.name = "Sheet" & s
End With
End If
'Get spreadsheet headers
x = 0
For Each Field In myrs.Fields 'RS being my Recordset variable
targetworkbook.Worksheets("Sheet" & s).Range("A1").Offset(0, x).Value = Field.name
x = x + 1
Next Field
targetworkbook.Worksheets("Sheet" & s).Range("A2").CopyFromRecordset myrs
targetworkbook.Worksheets("Sheet" & s).Columns("A:K").AutoFit
'Name Worksheet
sheetName = Format(sheetDate, "mm-dd")
targetworkbook.Sheets("Sheet" & s).name = sheetName
Next s
DoCmd.SetWarnings False
myFileName = "Internal Customer FX Deals"
targetworkbook.SaveAs FileName:=xlPath & myFileName, FileFormat:=xlWorkbookNormal
targetworkbook.Close SaveChanges:=False
DoCmd.SetWarnings True
If Not objXL Is Nothing Then
objXL.Quit
objXL.DisplayAlerts = True
Set objXL = Nothing
Set myrs = Nothing
End If
MsgBox "Internal Customer FX Deals Data successfully Exported", vbOKOnly
Exit_ExportSpreadSheet:
Exit Function
Err_ExportSpreadSheet:
Err.Clear
Resume Exit_ExportSpreadSheet
End Function
Seems to me that you are doing a whole lot of work for nothing. There's not need to automate Excel unless you want to do some formatting. Simply export the query to Excel via TransferSpreadsheet. Instead of the input box, use a parameter in the query, or better yet, a small form with a textbox.
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12Xml, "yourQueryName", "FileName", True, "SheetName"
Related
Am I performing the Index Match function in the wrong location?
Should I even be using IndexMatch?
My information in the table I am trying to get the information out of has CO number in column A.
Columns B has the information I am trying to populate my new worksheet with.
Sub AddWorkbooks()
Dim ChangeOrder As Range
Dim XCXX As Worksheet
Dim wb As Workbook
Dim CoForm As Worksheet
Dim CoFormCopy As Worksheet
Dim srNO As Variant
Set wb = ActiveWorkbook
Set XCXX = ActiveSheet
Set CoForm = wb.Worksheets("+CO Form+")
'Set wbNew = Workbooks.Add
srNO = XCXX.Range("D2").Value
'CoForm.Copy After:=Sheets(ActiveSheet.Index)
CoForm.Copy After:=XCXX
ActiveSheet.Name = "Proj" & " " & XCXX.Range("D2").Value
Set CoFormCopy = XCXX.Next 'the copy of +CO Form
With CoFormCopy
'Adds CO Number
Range("A6:D6").Value = XCXX.Range("D2").Value
'Adds CO Description from CO_List sheet based on CO Number
Range("A16").Value = Application.WorksheetFunction.Index(Sheets("CO_List").Range("B3:B"), Application.WorksheetFunction.Match(srNO, Sheets("CO_List").Range("A3:A"), 0))
'ActiveCell.FormulaR1C1 = XCXX.Range("D2").Value
End With
CoFormCopy.Move
End Sub
If no match is found WorksheetFunction.Match will fail. Application.Match will return #N/A error that you can test for with IsError().
Option Explicit
Sub AddWorkbooks()
Dim wb As Workbook, wbNew As Workbook
Dim srNo, desc As String
Dim v, lastrow As Long
' project number
srNo = ActiveSheet.Range("D2").Value
' find desc from CO_List sheet based on CO Number
Set wb = ActiveWorkbook
With wb.Sheets("CO_List")
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
v = Application.Match(srNo, .Range("A3:A" & lastrow), 0)
If IsError(v) Then
MsgBox "No Description for '" & srNo & "'", vbExclamation
desc = "Description for " & srNo
Else
desc = Application.Index(.Range("B3:B" & lastrow), v)
End If
End With
' create new workbbok
Set wbNew = Workbooks.Add(1)
With wbNew.Sheets(1)
.Name = "Proj" & " " & srNo
.Range("A6:D6").Value = srNo
.Range("A16") = desc
End With
MsgBox "New workbook created for " & srNo, vbInformation
'wbNew.Save
End Sub
Greeting!
I have a VBA that is in a Workbook with a Table containing strings for replacement. The VBA logic do the following:
Read files in folder
Create a separate process
Open a file from the folder in that separate process
In "Main" and "DataSpreadSheet" Worksheets look and replace values that are present in the Table.
Save the separate process workbook under another
Repeats the action on the other file in the folder.
This VBA proceeds the way I need, the only problem is that it takes so much time.
I have a bunch of files, over 100 to proceed regularly, and each file around 10-15 minutes to proceed, while the data for replacement is in range of B3:BB500 at most, with approximately 40% of cells in the range is actually filled with values.
The code is below, and do you have any suggestion on how to make it proceed faster? I have already disabled all calculations and updates while code is running.
The overall goal for the VBA is to translate Worksheets to another language using provided in Table translated strings arranged in columns for each language
I would appreciate help with rewriting the VBA.
Dim fileCollection As Collection
Sub TraversePath(path As String)
Dim currentPath As String, directory As Variant
Dim dirCollection As Collection
Set dirCollection = New Collection
currentPath = Dir(path, vbDirectory)
'Explore current directory
Do Until currentPath = vbNullString
Debug.Print currentPath
If Left(currentPath, 1) <> "." And (GetAttr(path & currentPath) And vbDirectory) = vbDirectory Then
dirCollection.Add currentPath
ElseIf Left(currentPath, 1) <> "." And (GetAttr(path & currentPath) And vbNormal) = vbNormal Then
fileCollection.Add path & currentPath
End If
currentPath = Dir()
Loop
'Explore subsequent directories
For Each directory In dirCollection
Debug.Print "---SubDirectory: " & directory & "---"
TraversePath path & directory
Next directory
End Sub
Sub String_Autosubstitution()
'Logic: Find & Replace a list of text/values throughout entire workbook from a table
Dim folderName As String, eApp As Excel.Application, fileName As Variant
Dim wb As Workbook, ws As Worksheet, currWs As Worksheet, currWb As Workbook
Dim fDialog As Object: Set fDialog = Application.FileDialog(msoFileDialogFolderPicker)
Dim inputRange As Range
Dim Var, s As String, t As String, c As Range
Dim newFolderFullName As String
Dim newfileName As String
Dim LangName As String
Dim fndList As Integer
Dim rplcList As Integer
Dim tbl As ListObject
Dim myArray As Variant
Dim LangColumn As Integer
Dim StartTime As Double
Dim MinutesElapsed As String
'Dim sws As Worksheet
Dim rg As Range
Dim Add As String
Dim AddStart As String
'Timer count: Remember time when macro starts
StartTime = Timer
Set currWb = ActiveWorkbook: Set currWs = ActiveSheet
'Turn off automatic calculation for the VBA conteining Master Workbook
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Application.ErrorCheckingOptions.BackgroundChecking = False
Application.DisplayAlerts = False
'Select folder in which all files are stored
fDialog.Title = "Select the folder with master files"
fDialog.InitialFileName = Left(currWb.path, InStrRev(currWb.path, "\") - 1)
If fDialog.Show = -1 Then
folderName = fDialog.SelectedItems(1)
End If
'Create a separate Excel process that is invisibile
Set eApp = New Excel.Application: eApp.Visible = True
'Search for all files in folder [replace *.* with your pattern e.g. *.xlsx]
Set fileCollection = New Collection
TraversePath folderName & "\"
For Each fileName In fileCollection
'Update status bar to indicate progress
Application.StatusBar = "Processing " & fileName
'Open file
Set wb = eApp.Workbooks.Open(fileName:=fileName, ReadOnly:=True)
'Turn off automatic calculation for the Slave Workbook
eApp.Calculation = xlCalculationManual
'eApp.ScreenUpdating = False
eApp.ErrorCheckingOptions.BackgroundChecking = False
eApp.DisplayAlerts = False
'Create variable to point to your table
Set tbl = ThisWorkbook.Sheets("LangLib").ListObjects("LangTable")
'Create an Array out of the Table's Data
Set TempArray = tbl.DataBodyRange
myArray = Application.Transpose(TempArray)
'Set langauge columnt variable
LangColumn = Application.Workbooks(ActiveWorkbook.Name).Worksheets("Scripts").Range("S6")
'Designate Columns for Find/Replace data
fndList = 1
rplcList = LangColumn
'Loop through each worksheet in ActiveWorkbook (skip sheet with table in it)
For Each ws In wb.Worksheets
If ws.Name = "Main" Or ws.Name = "DataSpreadsheet " Then
'Define and set range on each sheet for execution
Add = ws.Range("B1").SpecialCells(xlCellTypeLastCell).Address
AddStart = ws.Range("B1:" & Add).Address
Set rg = ws.Range(AddStart)
'Loop through each item in Array lists (Array is the library of strigs from LangLib sheet)
For x = LBound(myArray, 1) To UBound(myArray, 2)
If myArray(rplcList, x) <> "" Then
rg.Cells.Replace What:=myArray(fndList, x), Replacement:=myArray(rplcList, x), _
LookAt:=xlWhole, SearchOrder:=xlByRows, MatchCase:=False, _
SearchFormat:=False, ReplaceFormat:=False
End If
On Error Resume Next
Next x
End If
Next ws
'Sets name for file to be saved
LangName = Application.Workbooks(ActiveWorkbook.Name).Worksheets("UI").Range("I37")
newfileName = Left(fileName, Len(fileName) - 5) & LangName & ".xlsx"
eApp.Calculation = xlAutomatic
wb.SaveCopyAs fileName:=newfileName
wb.Close SaveChanges:=False
Debug.Print "Processed " & fileName 'Progress indication
Next fileName
eApp.DisplayAlerts = True
'eApp.Calculation = xlCalculationAutomatic
eApp.ErrorCheckingOptions.BackgroundChecking = True
eApp.Quit
Set eApp = Nothing
'Clear statusbar and notify of macro completion
Application.StatusBar = ""
Application.DisplayAlerts = True
'Application.ScreenUpdating = True
Application.Calculation = xlAutomatic
Application.ErrorCheckingOptions.BackgroundChecking = True
Application.DisplayAlerts = True
'Timer: Determines how many seconds code took to run
MinutesElapsed = Format((Timer - StartTime) / 86400, "hh:mm:ss")
'Notify user in seconds
MsgBox "Translation completed in " & MinutesElapsed & " minutes", vbInformation
'MsgBox "Translation completed"
End Sub
I have modified the code using approach #ENIAC suggested, yet need to fix error.
Dim fileCollection As Collection
Sub TraversePath(path As String)
Dim currentPath As String, directory As Variant
Dim dirCollection As Collection
Set dirCollection = New Collection
currentPath = Dir(path, vbDirectory)
'Explore current directory
Do Until currentPath = vbNullString
Debug.Print currentPath
If Left(currentPath, 1) <> "." And (GetAttr(path & currentPath) And vbDirectory) = vbDirectory Then
dirCollection.Add currentPath
ElseIf Left(currentPath, 1) <> "." And (GetAttr(path & currentPath) And vbNormal) = vbNormal Then
fileCollection.Add path & currentPath
End If
currentPath = Dir()
Loop
'Explore subsequent directories
For Each directory In dirCollection
Debug.Print "---SubDirectory: " & directory & "---"
TraversePath path & directory
Next directory
End Sub
Sub String_Autosubstitution()
'Logic: Find & Replace a list of text/values throughout entire workbook from a table
Dim folderName As String, eApp As Excel.Application, fileName As Variant
Dim wb As Workbook, ws As Worksheet, currWs As Worksheet, currWb As Workbook
Dim fDialog As Object: Set fDialog = Application.FileDialog(msoFileDialogFolderPicker)
Dim inputRange As Range
Dim Var, s As String, t As String, c As Range
Dim newFolderFullName As String
Dim newfileName As String
Dim LangName As String
Dim fndList As Integer
Dim rplcList As Integer
Dim tbl As ListObject
Dim myArray As Variant
Dim LangColumn As Integer
Dim StartTime As Double
Dim MinutesElapsed As String
'Dim sws As Worksheet
Dim rangeToCopy As Range
Dim Add As String
Dim AddStart As String
'Timer count: Remember time when macro starts
StartTime = Timer
Set currWb = ActiveWorkbook: Set currWs = ActiveSheet
'Turn off automatic calculation for the VBA conteining Master Workbook
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Application.ErrorCheckingOptions.BackgroundChecking = False
Application.DisplayAlerts = False
'Select folder in which all files are stored
fDialog.Title = "Select the folder with master files"
fDialog.InitialFileName = Left(currWb.path, InStrRev(currWb.path, "\") - 1)
If fDialog.Show = -1 Then
folderName = fDialog.SelectedItems(1)
End If
'Create a separate Excel process that is invisibile
Set eApp = New Excel.Application: eApp.Visible = True
'Search for all files in folder [replace *.* with your pattern e.g. *.xlsx]
Set fileCollection = New Collection
TraversePath folderName & "\"
For Each fileName In fileCollection
'Update status bar to indicate progress
Application.StatusBar = "Processing " & fileName
'Open file
Set wb = eApp.Workbooks.Open(fileName:=fileName, ReadOnly:=True)
'Turn off automatic calculation for the Slave Workbook
eApp.Calculation = xlCalculationManual
'eApp.ScreenUpdating = False
eApp.ErrorCheckingOptions.BackgroundChecking = False
eApp.DisplayAlerts = False
'Create variable to point to your table
Set tbl = ThisWorkbook.Sheets("LangLib").ListObjects("LangTable")
'Create an Array out of the Table's Data
Set TempArray = tbl.DataBodyRange
myArray = Application.Transpose(TempArray)
'Set langauge columnt variable
LangColumn = Application.Workbooks(ActiveWorkbook.Name).Worksheets("Scripts").Range("S6")
'Designate Columns for Find/Replace data
fndList = 1
rplcList = LangColumn
'Loop through each worksheet in ActiveWorkbook (skip sheet with table in it)
For Each ws In wb.Worksheets
If ws.Name = "Main" Or ws.Name = "DataSpreadsheet " Then
'Define and set range on each sheet for execution
Add = ws.Range("B1").SpecialCells(xlCellTypeLastCell).Address
AddStart = ws.Range("B1:" & Add).Address
Set rangeToCopy = ws.Range(AddStart)
'--------------new logic-------------
rangeToCopy.Select
Dim arrayFromSheet() As Variant
arrayFromSheet = rangeToCopy
'Loop through each item in Array lists (Array is the library of strigs from LangLib sheet)
For x = LBound(myArray, 1) To UBound(myArray, 2)
If myArray(rplcList, x) <> "" Then
arrayFromSheet.Replace What:=myArray(fndList, x), Replacement:=myArray(rplcList, x), _
LookAt:=xlWhole, SearchOrder:=xlByRows, MatchCase:=False, _
SearchFormat:=False, ReplaceFormat:=False
' Copy data from 2D array back to sheet.
rangeToCopy.Value = arrayFromSheet
'--------------new logic-------------
End If
On Error Resume Next
Next x
End If
Next ws
LangName = Application.Workbooks(ActiveWorkbook.Name).Worksheets("UI").Range("I37")
newfileName = Left(fileName, Len(fileName) - 5) & LangName & ".xlsx"
eApp.Calculation = xlAutomatic
wb.SaveCopyAs fileName:=newfileName
wb.Close SaveChanges:=False
Debug.Print "Processed " & fileName 'Progress indication
Next fileName
eApp.DisplayAlerts = True
'eApp.Calculation = xlCalculationAutomatic
eApp.ErrorCheckingOptions.BackgroundChecking = True
eApp.Quit
Set eApp = Nothing
'Clear statusbar and notify of macro completion
Application.StatusBar = ""
Application.DisplayAlerts = True
'Application.ScreenUpdating = True
Application.Calculation = xlAutomatic
Application.ErrorCheckingOptions.BackgroundChecking = True
Application.DisplayAlerts = True
'Timer: Determines how many seconds code took to run
MinutesElapsed = Format((Timer - StartTime) / 86400, "hh:mm:ss")
'Notify user in seconds
MsgBox "Translation completed in " & MinutesElapsed & " minutes", vbInformation
'MsgBox "Translation completed"
End Sub
Will post as an answer, in order to show a code and visualization.
You need a 2D array. This is the same worksheet (table). The difference is that you will have to use numbers when referring to the array's columns and rows (the same as for Cells property where you refer as Cells(row_number, column_number)).
Copy entire range that needs processing from the worksheet to a dynamic array. If you want the rows and column indices in the worksheet and in the array to be the consistent, start your range from the first cell (A1). This way, there will be no need in additional conversion from the worksheet cell indices and the array's ones because first row/column in the worksheet corresponds to the first row/column in the array. For example, array(4, 5) cell in the array refers to Cells(4, 5) cell in the worksheet.
Process the data in the array as required. Than, copy the data from the array back to the worksheet.
' Range that needs processing.
' I suggest starting the range from A1
' this way, the array row and column numbering
' will be the same as for the sheet
Dim rangeToCopy As Range
Set rangeToCopy = Sheet1.Range("A1:S20")
rangeToCopy.Select ' just to show range
' Copy data from sheet to 2D array.
' Note that is must be dynamic and of Variant type.
Dim arrayFromSheet() As Variant
arrayFromSheet = rangeToCopy
' Process needed part of array.
For r = Sheet1.Range("D6").Row To UBound(arrayFromSheet, 1)
For c = Sheet1.Range("D6").Column To UBound(arrayFromSheet, 2)
arrayFromSheet(r, c) = arrayFromSheet(r, c) + 1
Next c
Next r
' Copy data from 2D array back to sheet.
rangeToCopy.Value = arrayFromSheet
Hope this helps.
As to me, ADODB is something new for me that I am eager to learn. Here's a code that I tried my best but needs your ideas to make it appear more professional and more efficient. The problem in the code is that the data is grabbed from sheets in reverse order and not in the order of sheets. To make it clear, I have Sample.xlsx workbook with two sheets Sheet1 and New and the code is supposed to loop through t he sheets then search for specific header then to get the data from such a column. All this with the ADO approach. the code grabs the data from New sheet first then from Sheet1 .. While the order of the sheets is Sheet1 then New >> another point, how can I close the recordset properly. I mean is using .Close is enough or I have to set it to Nothing Set rs=Nothing.
Sub ImportFromClosedWorkbook()
Dim e, ws As Worksheet, cn As ADODB.Connection, rs As ADODB.Recordset, rsHeaders As ADODB.Recordset, b As Boolean, sFile As String, shName As String, strSQL As String, iCol As Long
sFile = ThisWorkbook.Path & "\Sample.xlsx"
'shName = "Sheet1"
Dim rsData As ADODB.Recordset
Set cn = New ADODB.Connection
cn.Open ConnectionString:="Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" & sFile & "';" & "Extended Properties=""Excel 12.0;HDR=YES;IMEX=1;"";"
'--------
Set ws = ThisWorkbook.ActiveSheet
Set rs = cn.OpenSchema(20)
Do While Not rs.EOF
sName = rs.Fields("Table_Name")
If Right(sName, 14) <> "FilterDatabase" Then
sName = Left(sName, Len(sName) - 1)
'Debug.Print sName
b = False
strSQL = "SELECT * FROM [" & sName & "$]"
Set rsHeaders = New ADODB.Recordset
rsHeaders.Open Source:=strSQL, ActiveConnection:=cn, Options:=1
For iCol = 0 To rsHeaders.Fields.Count - 1
'Debug.Print rsHeaders.Fields(iCol).Name
For Each e In Array("Ref No", "Reference", "Number")
If e = rsHeaders.Fields(iCol).Name Then
b = True: Exit For
End If
Next e
If b Then Exit For
Next iCol
If b Then
'Debug.Print e
strSQL = "SELECT [" & e & "] FROM [" & sName & "$]"
Set rsData = New ADODB.Recordset
Set rsData = cn.Execute(strSQL)
ws.Range("A" & ws.Cells(Rows.Count, 1).End(xlUp).Row + 1).CopyFromRecordset rsData
rsData.Close
'here I am stuck of how to get the data from the found column
End If
'rs.Close
End If
rs.MoveNext
Loop
'rs.Close
'------------------
' strSQL = "SELECT * FROM [" & shName & "$]"
' Set rs = New ADODB.Recordset
' Set rs = cn.Execute(strSQL)
' Range("A1").CopyFromRecordset rs
rs.Close: Set rs = Nothing
cn.Close: Set cn = Nothing
End Sub
the code grabs the data from New sheet first then from Sheet1 .. While the order of the sheets is Sheet1 then New
The tab order is an Excel feature. The Sheet names are extracted in alphabetical order when you use ADODB. This is the reason why you get New sheet first and then Sheet1.
Note: If the sheet names start with number or have spaces then they are given a priority first. Few examples
Example 1
Sheets names: 1, Sheet1, 1Sheet4, She et3, Sheet5
Returned as
'1$'
'1Sheet4$'
'She et3$'
Sheet1$
Sheet5$
Example 2
Sheets names: Sheet2, Sheet5, She et3, Sheet1, Sheet4
Returned as
'She et3$'
Sheet1$
Sheet2$
Sheet4$
Sheet5$
Example 3
Sheets names: 1, Sheet1, 2, Sheet2, 3, Sheet3
Returned as
'1$'
'2$'
'3$'
Sheet1$
Sheet2$
Sheet3$
Alternative to ADODB
If you want to extract the names of the sheets in the tab order then you can use DAO as shown by Andrew Poulsom in THIS link. Posting the code here in case the link dies...
Sub GetSecondSheetName()
' Requires a reference to Microsoft DAO x.x Object Library
' Adjust to suit
Const FName As String = "P:\Temp\MrExcel\Temp\SheetNames.xls"
Dim WB As DAO.Database
Dim strSheetName As String
Set WB = OpenDatabase(FName, False, True, "Excel 8.0;")
' TableDefs is zero based
strSheetName = WB.TableDefs(1).Name
MsgBox strSheetName
WB.Close
End Sub
Close is enough or I have to set it to Nothing Set rs=Nothing.
No you do not have to set it to nothing. VBA cleans it automatically when it exits the prodecure. But yes it is a good practice to flush the toilet.
Interesting Read:
You may want to read the post by #GSerg in the below link...
When should an Excel VBA variable be killed or set to Nothing?
For it to work with XLSX, use this (Requires a reference to Microsoft Office XX.XX Access database engine Object Library)
Option Explicit
'~~> Change this to the relevant file name
Const FName As String = "C:\Users\routs\Desktop\Delete Me later\TEXT.XLSX"
Sub Sample()
'Requires a reference to Microsoft Office XX.XX Access database engine Object Library
Dim db As DAO.Database
Set db = OpenDatabase(FName, False, False, "Excel 12.0")
Dim i As Long
For i = 0 To db.TableDefs.Count - 1
Debug.Print db.TableDefs(i).Name
Next i
db.Close
End Sub
In Action
#Siddharth Rout you have inspired me how to search for such new topic for me and I could use such a code to list all the worksheets in the order of tab using DAO but with late binding ( I am curious to know how to use early binding as I tried but with no success)
Sub Get_Worksheets_Using_DAO()
Dim con As Object, db As Object, sName As String, i As Long
Set con = CreateObject("DAO.DBEngine.120")
sName = ThisWorkbook.Path & "\Sample.xlsx"
Set db = con.OpenDatabase(sName, False, True, "Excel 12.0 XMl;")
For i = 0 To db.TableDefs.Count - 1
Debug.Print db.TableDefs(i).Name
Next i
db.Close: Set db = Nothing: Set con = Nothing
End Sub
I want to iterate through the values of a column in a table in a word file, and check if those values are in a column in a table in an Excel file. I have the following code:
Private Sub CompararColumnas_Click()
Dim wrdTbl As Table
'Set your table
With ActiveDocument
If ActiveDocument.Tables.Count >= 1 Then
Set wrdTbl = .Tables(InputBox("Table # to copy? There are " & .Tables.Count & " tables to choose from."))
End If
End With
Dim AD_UsersPath As String
AD_UsersPath = "C:\Users\" & Environ("Username") & "\Desktop\Comparar Columnas VBA\Animales.xlsx"
Dim AD_USERS As Object
Set AD_USERS = CreateObject("Excel.Application")
AD_USERS.Visible = False
AD_USERS.Application.Workbooks.Open AD_UsersPath
LastRow = ThisDocument.Tables(1).Columns(1).Cells.Count
Dim I As Integer
For I = 1 To LastRow
wVal = ThisDocument.Tables(1).Cell(I, 1)
User = AD_USERS.Cells(AD_USERS.Range("A:A").Find(What:=wVal).Row, 1).Text
wrdTbl.Cell(I, 2).Range.Text = User
Next I
End Sub
This code iterates in wVal the values from the first column in a table from Word and after that it goes to Excel to find those values in the first column of the Excel table. If it finds them, it copies the values in the second column of the word table. However, it gives me an error 91. If instead of Find(What:=wVal) I put something like Find(What:="Word") it does not give me an error and puts the word "Word" in every cell of the second column of the word table. How can I solve this?
Cell values in Word have a two-character "end of cell" marker (Chr(13) + Chr(7)) which you need to remove:
Private Sub CompararColumnas_Click()
Dim wrdTbl As Table
'Set your table
With ActiveDocument
If ActiveDocument.Tables.Count > 1 Then
Set wrdTbl = .Tables(InputBox("Table # to copy? There are " & _
.Tables.Count & " tables to choose from."))
Else
Set wrdTbl = .Tables(1) 'default to the only table
End If
End With
Dim AD_UsersPath As String, wb As Object, ws As Object
AD_UsersPath = "C:\Users\" & Environ("Username") & _
"\Desktop\Comparar Columnas VBA\Animales.xlsx"
Dim AD_USERS As Object
Set AD_USERS = CreateObject("Excel.Application")
AD_USERS.Visible = False
Set wb = AD_USERS.Workbooks.Open(AD_UsersPath)
Set ws = wb.Worksheets(1)
Dim LastRow As Long, I As Long, User
LastRow = wrdTbl.Columns(1).Cells.Count
For I = 1 To LastRow
wVal = TwrdTbl.Cell(I, 1)
Left(wVal, Len(wVal)-2) 'strip off "end of cell" marker
User = ws.Cells(ws.Range("A:A").Find(What:=wVal).Row, 1).Text
wrdTbl.Cell(I, 2).Range.Text = User
Next I
wb.Close False
AD_USERS.Quit
End Sub
I am creating an ADODB connection to a Sybase database, executing an SQL statement into a recordset, and then using the CopyFromRecordset method to paste the contents of the recordset to a range. This has been working fine but I recently moved PC's at work and now one of the columns is returning nothing.
When I run the same SQL in SQuirreL the column is not blank.
If I pause the VBA and try to look at one of the values in the column / field in question (ie ?rst.fields(1).value in the immediate Window) I get the following error message:
Run-time error '-2147467259 (80004005)': Unspecified error.
In the Squirrel results Metadata tab the column in question is described as:
ColumnIndex 2
getColumnName CommentText
getColumnTypeName text
getPrecision 2147483647
getScale 0
isNullable 0
getTableName xxxxxxx
getSchemaName
getCatalogName
getColumnClassName java.sql.Clob
getColumnDisplaySize 2147483647
getColumnLabel CommentText
getColumnType 2005
isAutoIncrement FALSE
isCaseSensitive FALSE
isCurrency FALSE
isDefinitelyWritable FALSE
isReadOnly FALSE
isSearchable FALSE
isSigned FALSE
isWritable TRUE
The code in question is below, but, as stated the code does not seem to be the problem as it has worked previously - any ideas?
Sub ImportComments()
Dim wsData As Worksheet
Dim rng As Range
Dim cn As ADODB.Connection
Dim rst As ADODB.Recordset
Dim x As Long
Dim rngSQL As Range
Dim cell As Range
Dim sSQL As String
Dim sProvider As String
Dim sDS As String
Dim sDataSource As String
Dim sUser As String
Dim sCatalog As String
Dim sPassword As String
Dim rngDS As Range
Dim rngThisDS As Range
Dim sConnect As String
Dim sInstance As String
Dim fSuccess As Boolean
Dim sError As String
On Error GoTo ProcExit
'delete previous comments if they exist
If SheetExists("Comments_Data_Import", ThisWorkbook) = True Then
Application.DisplayAlerts = False
ThisWorkbook.Sheets("Comments_Data_Import").Delete
Application.DisplayAlerts = True
End If
'create comments sheet
Set wsData = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Sheets("EWI_Data_Import"))
wsData.Name = "Comments_Data_Import"
'build sql string
Set rngSQL = Range(ThisWorkbook.Sheets("SQL").Range("A2"), _
ThisWorkbook.Sheets("SQL").Range("A2").End(xlDown))
For Each cell In rngSQL
sSQL = sSQL & cell.Value & " "
Next cell
'define login components
Set rngDS = ThisWorkbook.Worksheets("Login").Range("rngInstance").CurrentRegion
Set rngDS = rngDS.Offset(1, 0).Resize(rngDS.Rows.Count - 1)
sProvider = "Provider=ASEOLEDB.1;"
sUser = "User ID=" & ThisWorkbook.Worksheets("Login").Range("rngUsername").Value & ";"
sPassword = "Password=" & ThisWorkbook.Worksheets("Login").Range("rngPassword").Value
'try to log in to each instance exiting when succesful
Set cn = New ADODB.Connection
cn.CommandTimeout = 600
'turn off error hadling to allow for connection errors On Error Resume Next
For Each rngThisDS In rngDS.Rows
'complete connect string
Err = 0
sInstance = rngThisDS.Cells(1, 1)
sDS = "Data Source=" & rngThisDS.Cells(1, 2) & ";"
sCatalog = "Initial Catalog=" & rngThisDS.Cells(1, 3) & ";"
sConnect = sProvider & sDS & sUser & sCatalog & sPassword
'attempt to open
cn.Open sConnect
'If successful Then
If Err = 0 Then
'flag success
fSuccess = True
'execute SQL
On Error GoTo ProcError
Set rst = cn.Execute(sSQL)
'copy data into comments sheet
wsData.Range("A2").CopyFromRecordset rst
'Put in the headers
Set rng = wsData.Range("A1")
For x = 1 To rst.Fields.Count
rng.Offset(0, x - 1).Value = rst.Fields(x - 1).Name
Next x
FormatComments
Exit For
End If
Next rngThisDS
If fSuccess = False Then
MsgBox ("Unable to connect to Insight")
Else
MsgBox "Connected to and exported data from " & sInstance
End If
ProcExit:
Set wsData = Nothing
Set rng = Nothing
Set cn = Nothing
Set rst = Nothing
Set rngSQL = Nothing
Set cell = Nothing
Set rngDS = Nothing
Set rngThisDS = Nothing
Exit Sub
ProcError:
MsgBox "Error: " & Err.Description
Resume ProcExit
End Sub
According to the CopyFromRecordset() MSDN:
When this method copies the recordset to the worksheet, the results
will be truncated if you do not specify a range that is large enough
to hold the contents of the recordset.
Consider specifying the range with MoveFirst command reset:
' Copy data into comments sheet
rst.MoveLast
rst.MoveFirst
wsData.Range("A2:Z500").CopyFromRecordset rst
Or entire worksheet (starting at A1, of course inserting row for column headers)
wsData.Cells.CopyFromRecordset rst
But even then, CopyFromRecordset() is sensitive to data and cursory types even memory (since you pull all data and dump at once), so consider altogether replacing the method and iterate through records for the rows. Even other languages (PHP, Python, Java, etc.) run queries this way, opening cursor and iterating through resultset.
' Put in the headers
Set rng = wsData.Range("A1")
For x = 1 To rst.Fields.Count
rng.Offset(0, x - 1).Value = rst.Fields(x - 1).Name
Next x
' Put in rows
Dim col As Integer, row As Integer
rst.MoveLast
rst.MoveFirst
Set rng = wsData.Range("A2")
row = 0
Do While Not rst.EOF
For col = 0 To rst.Fields.Count - 1
rng.Offset(row, col).Value = rst(col)
Next col
row = row + 1
rst.MoveNext
Loop