After so many hours in that field, I could be able to get data from all the worksheets in closed workbook and could get data from specific columns using ADODB.
#Siddharth Rout helped me to be able to get the sheet names in the order of tab.
The following code works fine for only one closed workbook. But in fact I am trying to do the same and get all the data from the specific column (Reference - Ref No - Number ..) from several workbooks
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"
Dim con As Object
Set con = CreateObject("DAO.DBEngine.120")
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
Dim db As Object, i As Long
Set db = con.OpenDatabase(sFile, False, True, "Excel 12.0 XMl;")
For i = 0 To db.TableDefs.Count - 1
sName = db.TableDefs(i).Name
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
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
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
End If
Next i
db.Close: Set db = Nothing
Set con = Nothing
cn.Close: Set cn = Nothing
End Sub
Is it suitable to build a public procedure or what's the best approach in that case and how can I release the objects in correct way?
I would break out your code even more - there are distinct activities which could be factored out into reusable methods.
FYI your tableDefs objects already contains the field names, so there's no need to separately query for those.
Eg:
Sub ImportFromClosedWorkbook()
Dim sFile As String, sheetName As String, colName As String, rs As ADODB.Recordset
Dim cols As Collection, col
sFile = ThisWorkbook.FullName
Set cols = FindColumns(sFile, Array("Ref", "Reference", "RefNo"))
'loop found columns
For Each col In cols
sheetName = col(0)
colName = col(1)
Debug.Print "##", sheetName, colName
Set rs = WorkBookQuery(sFile, "Select [" & colName & "] from [" & sheetName & "]")
If Not rs.EOF Then
' ActiveSheet.Cells(Rows.Count, "A").End(xlUp).CopyFromRecordset rs
End If
Next col
End Sub
'given a workbook path, find all column headings matching andname in arrNames
'returns a collections of [sheetName, columnName] arrays
Function FindColumns(wbFullPath As String, arrNames) As Collection
Dim tabledefs As Object, td As Object, f As Object, rv As New Collection
Set tabledefs = CreateObject("DAO.DBEngine.120") _
.OpenDatabase(wbFullPath, False, True, "Excel 12.0 XMl;").tabledefs
For Each td In tabledefs
For Each f In td.Fields
'Debug.Print td.Name, f.Name
If Not IsError(Application.Match(f.Name, arrNames, 0)) Then
rv.Add Array(td.Name, f.Name)
End If
Next f
Next td
Set FindColumns = rv
End Function
'run a SQL query against a workbook
Function WorkBookQuery(wbFullPath As String, SQL As String) As ADODB.Recordset
Dim rs As ADODB.Recordset
With New ADODB.Connection
.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" & wbFullPath & "';" & _
"Extended Properties=""Excel 12.0;HDR=YES;IMEX=1;"";"
Set WorkBookQuery = .Execute(SQL, Options:=1)
End With
End Function
There seems to be a logical error in the process of cycling through the fields. It would be nice to use a user-defined function that checks if the field name exists.
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
Dim sField As String
sFile = ThisWorkbook.Path & "\Sample.xlsx"
Dim con As Object
Set con = CreateObject("DAO.DBEngine.120")
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
Dim db As Object, i As Long
Set db = con.OpenDatabase(sFile, False, True, "Excel 12.0 XMl;")
For i = 0 To db.TableDefs.Count - 1
sName = db.TableDefs(i).Name
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
' 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
sField = rsHeaders.Fields(iCol).Name
If isField(sField) Then
strSQL = "SELECT [" & sField & "] 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
End If
Next iCol
Next i
db.Close: Set db = Nothing
Set con = Nothing
cn.Close: Set cn = Nothing
End Sub
Function isField(sField As String) As Boolean
Dim vName As Variant, e As Variant
vName = Array("Ref No", "Reference", "Number")
For Each e In vName
If e = sField Then
isField = True
Exit Function
End If
Next e
End Function
If all the files have the same structure and are in a folder, you could use the FileSystemObject reference as below:
"https://stackoverflow.com/questions/10380312/loop-through-files-in-a-folder-using-vba"
and you could run the existing code in a loop in the file system code, hope that works
I have written a VBA code to update a column but getting Automation Error while running the program at line 41 which is Set rsf = cmd.Execute. Is the way of writing update statement incorrect in my code? Not getting what is the issue here. I'd appreciate any help towards a solution for my problem.
Private Sub Update_Visibility_Flag_Click()
Dim fldrpath As String
Dim currDate As String
Dim mePrgTrck As String
Dim wkb1 As Workbook
Dim sht1 As Worksheet
Dim cnf As ADODB.Connection
Dim rsf As ADODB.Recordset
Dim sqlstr As String
fldrpath = "\\lp99dfd\groups$\Record Extracts\New folder\New folder\" & Format(Date, "yyyymm")
currDate = "PI_202008"
mePrgTrck = fldrpath & "\LE\Progress_Tracker_" & Format(Date, "yyyymm") & "_LE.xlsx"
Set wkb1 = Workbooks.Open(mePrgTrck)
Set sht1 = wkb1.Sheets(currDate)
Set cnf = New ADODB.Connection
Set rsf = New ADODB.Recordset
cnf.Open ( _
"User ID=AI_ZK_DTA" & _
";Password=aizkdta" & _
";Data Source=POIUY" & _
";Provider=OraOLEDB.Oracle")
For Each cell In sht1.Range("A2:A28")
If cell.Offset(0, 3).Value = "Success" Then
sqlstr = "UPDATE AI_" & cell.Value & "_DTA SET VISIBLE = 'Y'"
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
Set cmd.ActiveConnection = cnf
cmd.CommandType = adCmdText
cmd.Properties("PLSQLRSet") = True
cmd.CommandText = sqlstr
Set rsf = cmd.Execute
cmd.Properties("PLSQLRSet") = False
cell.Offset(0, 8).Value = cell.Offset(0, 8).Value & "| Done"
End If
Next cell
wkb1.Close True
Set rsf = Nothing
Set cnf = Nothing
End Sub
I need a small help. I have an Access file name "DB_MLL.accdb" with table name "tblMLL" total 31 columns including primary key. I'm using front-end Excel and back-end access to fetch the data. I have two buttons to pull data from Acess and push back to access. Pulling data from access is working fine but pushing back is not working. I'm using the below codes. request you please guide me where I am doing wrong.
Sub PushTableToAccess()
Dim cnn As ADODB.Connection
Dim MyConn
Dim rst As ADODB.Recordset
Dim i As Variant, j As Variant
Dim Rw As Long
Sheets("Data").Activate
Rw = Range("A65536").End(xlUp).Row
Set cnn = New ADODB.Connection
MyConn = ThisWorkbook.Path & Application.PathSeparator & TARGET_DB
With cnn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.Open MyConn
End With
Set rst = New ADODB.Recordset
rst.CursorLocation = adUseServer
rst.Open Source:="tblMLL", ActiveConnection:=cnn, _
CursorType:=adOpenDynamic, LockType:=adLockOptimistic, _
Options:=adCmdTable
'Load all records from Excel to Access.
For i = 3 To Rw
rst.AddNew
For j = 1 To 31
If Cells(i, j).Value = "" Then
rst(Cells(2, j).Value) = ""
Else
rst(Cells(2, j).Value) = Cells(i, j).Value
End If
Next j
rst.Update
Next i
' Close the connection
rst.Close
cnn.Close
Set rst = Nothing
Set cnn = Nothing
MsgBox "Data Upload Completed successfully."
End Sub
Your code seems to have a bit of a fix.
Sub PushTableToAccess()
Dim cnn As ADODB.Connection
Dim MyConn
Dim rst As ADODB.Recordset
Dim i As Variant, j As Variant
Dim Rw As Long
Dim strConn As String
Sheets("Data").Activate
Rw = Range("A65536").End(xlUp).Row
Set cnn = New ADODB.Connection
MyConn = ThisWorkbook.Path & Application.PathSeparator & TARGET_DB
strConn = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & MyConn
cnn.Open strConn
Set rst = New ADODB.Recordset
wirh rst
.CursorLocation = adUseServer
.Source = "tblMLL"
.Options = adCmdTable
.ActiveConnection = strConn
.CursorType = adOpenDynamic
.LockType = adLockOptimistic
.Open
'Load all records from Excel to Access.
For i = 3 To Rw
.AddNew
For j = 1 To 31
If Cells(i, j).Value = "" Then
.Fields(Cells(2, j).Value) = ""
Else
.Fields(Cells(2, j).Value) = Cells(i, j).Value
End If
Next j
.Update
Next i
End With
' Close the connection
rst.Close
cnn.Close
Set rst = Nothing
Set cnn = Nothing
MsgBox "Data Upload Completed successfully."
End Sub
I'm having problems to specify a value to start adding fields to my table, i need to insert all the values with the condition of this specific value in the MOD_CODE column from Excel to be inserted in this way to Access.
.Fields("MOD_CODE") = Sheets(wsName).Cells(iX, 2).Value
It inserts all the fields correctly from Excel to Access but i can not make that picks a specific value in this field
Dim Conn As ADODB.Connection, RecSet As ADODB.Recordset
Dim fila As Long, primerFila As Integer, ultimaFila As Long, iX As Long
Dim dataSource As String, Tabla As String
Dim wsName As String
Dim rFound As Range
dataSource = Sheets("parametros").[B1]
Tabla = Sheets("parametros").[B2]
wsName = Sheets("parametros").[B3]
primerFila = Sheets("parametros").[B4]
Set Conn = New ADODB.Connection
Conn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source= " & dataSource & ";"
'Conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source= " & dataSource & ";"
Set RecSet = New ADODB.Recordset
RecSet.Open Tabla, Conn, adOpenKeyset, adLockOptimistic, adCmdTable
ultimaFila = WorksheetFunction.CountA(Sheets(wsName).Range("A:A"))
For iX = primerFila To ultimaFila
With RecSet
.AddNew
.Fields("PLANT") = Sheets(wsName).Cells(iX, 1).Value
.Fields("MOD_CODE") = Sheets(wsName).Cells(iX, 2).Value
.Fields("BOM_KEY") = Sheets(wsName).Cells(iX, 3).Value
.Fields("ASSY_ADDRESS") = Sheets(wsName).Cells(iX, 4).Value
.Update
End With
Next iX
RecSet.Close
Set RecSet = Nothing
Conn.Close
Set Conn = Nothing
End Sub
I have created a form in which when I click a button(subMnuPrintStaff), it should open an Excel file(WorkerNames.xls). The Excel file gets its records from my database(Employee.mdb). However, the problem is that when I update my databasefile(Employee.mdb), the records on my Excel file does not get updated. How do I fix this?
I am using flexgrid.
BUTTON CODE:
Private Sub subMnuPrintStaff_Click()
'On Error GoTo er
Dim oExcel As Object
Set oExcel = CreateObject("Excel.Application")
Dim oWorkBook As Object
Dim oWorkSheet As Object
Dim i As Integer, k As Integer
Dim lRow As Long
Dim LastRow As Long
Dim LastCol As Long
oExcel.Visible = False
oExcel.Workbooks.Open App.Path & "\WorkerNames.xls"
Set oWorkSheet = oExcel.Workbooks("WorkerNames.xls").Sheets("WorkerNames")
i = 2 'Row in Excel
LastRow = DataGrid1.Row 'Save Current row
LastCol = DataGrid1.Col 'and column
DataGrid1.Row = 0 'Fixed Row is -1
Do While DataGrid1.Row <= DataGrid1.VisibleRows - 1
For k = 1 To DataGrid1.Columns.Count - 1
DataGrid1.Col = k 'Fixed Column is -1
oWorkSheet.Cells(i, k).Font.Bold = False
oWorkSheet.Cells(i, k).Font.Color = vbBlack
oWorkSheet.Cells(i, k).Value = DataGrid1.Text
Next
i = i + 1
If DataGrid1.Row < DataGrid1.VisibleRows - 1 Then
DataGrid1.Row = DataGrid1.Row + 1
Else
Exit Do
End If
Loop
DataGrid1.Row = LastRow 'Restore original Row
DataGrid1.Col = LastCol 'and Column
oExcel.Workbooks("WorkerNames.xls").Save
oExcel.Workbooks("WorkerNames.xls").Close savechanges:=True
oExcel.Quit
'cmdView.Enabled = True
'er:
'If err.Number = 1004 Then
'Exit Sub
'End If
On Error GoTo ErrHandler
Dim xlApp As Object
Dim xlWB As Object
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = True
Set xlWB = xlApp.Workbooks.Open("WorkerNames.xls")
Exit Sub
ErrHandler:
MsgBox "There is a problem opening that workbook!", vbCritical, "Error!"
End Sub
FORM LOAD CODE:
Dim oRs As New ADODB.Recordset
Dim adoConn2 As ADODB.Connection
Set adoConn2 = New ADODB.Connection
adoConn2.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source = " & App.Path & "\Employee.mdb"
adoConn2.Open
oRs.CursorLocation = adUseClient
oRs.Open "select * from employeeName", adoConn2, adOpenKeyset, adLockPessimistic
Set DataGrid1.DataSource = oRs
DataGrid1.Refresh
Any help would be greatly appreciated. Database and Excel files are in the same directory with the project.
CODE FOR SAVING DATA INTO MY DATABASE - using text boxes
Dim adoConn As New ADODB.Connection Dim constr, curSql As String constr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source= " & App.Path & "\employee.mdb;Persist Security Info=False"
Set adoConn = New ADODB.Connection
adoConn.ConnectionString = constr adoConn.Open
If txtFirstName.Text = "" Or txtLastName.Text = "" Then
MsgBox "Some fields are empty!", vbInformation + vbOKOnly, "Empty Fields"
Else curSql = "INSERT INTO employeename(Firstname, LastName) VALUES ("curSql = curSql & "'" & Replace(txtFirstName.Text, "'", "''") & "'," curSql = curSql & "'" & Replace(txtLastName.Text, "'", "''") & "')"
adoConn.Execute curSql
adoConn.Close
MsgBox "Data successfully added!", vbOKOnly, "Success!"
txtFirstName.Text = ""
txtLastName.Text = ""