Excel form to save data in access db - ms-access

I have the below code for an excel form to currently save data in another excel.the only issue is that this doesn't work properly if more than 1 person are trying to send the data. Is it possible to make the code in a way that it sends data to an access db? Here my code.
Sub UpdateLogWorksheet()
Dim historyWks As Worksheet
Dim inputWks As Worksheet
Dim historyWb As Workbook '<~ target workbook
Dim nextRow As Long
Dim oCol As Long
Dim myRng As Range
Dim myCopy As String
Dim myCell As Range
'cells to copy from Input sheet - some contain formulas
myCopy = "D5,D7,D9,D11,D13"
Set inputWks = Worksheets("Input")
Set historyWb = Workbooks.Open("C:\reports\consolidated.xlsx") '<~ open target workbook and assign sheet
Set historyWks = historyWb.Worksheets("PartsData")
With historyWks
nextRow = .Cells(.Rows.Count, "A").End(xlUp).Offset(1, 0).Row
End With
With inputWks
Set myRng = .Range(myCopy)
If Application.CountA(myRng) <> myRng.Cells.Count Then
MsgBox "Please fill in all the cells!"
Exit Sub
End If
End With
With historyWks
With .Cells(nextRow, "A")
.Value = Now
.NumberFormat = "mm/dd/yyyy hh:mm:ss"
End With
.Cells(nextRow, "B").Value = Application.UserName
oCol = 3
For Each myCell In myRng.Cells
historyWks.Cells(nextRow, oCol).Value = myCell.Value
oCol = oCol + 1
Next myCell
End With
historyWb.Save '<~ save and close the target workbook
historyWb.Close SaveChanges:=False
'clear input cells that contain constants
With inputWks
On Error Resume Next
With .Range(myCopy).Cells.SpecialCells(xlCellTypeConstants)
.ClearContents
Application.GoTo .Cells(1) ', Scroll:=True
End With
On Error GoTo 0
End With
End Sub

You can use this code to put data from Excel to an AccessDB:
Option Explicit
Dim con, rst, t0, i, s, xx, n
Const adUseClient = 3
Const adOpenStatic = 3
Const adLockOptimistic = 3
Const useTransaction = True
Set con = CreateObject("ADODB.Connection")
con.CursorLocation = adUseClient
con.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=e:\0\a\db1.accdb;"
Set rst = CreateObject("ADODB.Recordset")
rst.Open "SELECT * FROM Table1", con, adOpenStatic, adLockOptimistic
If useTransaction Then
con.BeginTrans
End If
i = 1
For i = 1 To Range("Dati").Rows.Count
rst.AddNew
rst("FirstName").Value = Range("Dati").Cells(i, 1).Value
rst("LastName").Value = Range("Dati").Cells(i, 2).Value
rst("Birday").Value = Range("Dati").Cells(i, 3).Value
rst.Update
Next
If useTransaction Then con.CommitTrans
rst.Close
Set rst = Nothing
con.Close
Set con = Nothing
And put all the data inside Table1. All the data are taken from a Range named Dati.
I you have formula and you want to save formula use:
Range("Dati").Cells(i, 1).Formula
With This code you put ONLY the data from an Excel Files into a AccessDB file without check double data ...

Related

Column Headers to the last line of data entered to the HTMLBody

I've included the last line of data entered to my HTML body. However the column headers are not showing, what am I doing wrong?
Private Sub cmdEmail_Click()
'Declare Outlook Variables
Dim OLApp As Outlook.Application
Dim OLMail As Object
Dim MyData As Object
'Open the Outlook Application and Start a new mail
Set OLApp = New Outlook.Application
Set OLMail = OLApp.CreateItem(0)
Set MyData = ThisWorkbook.Worksheets("Database").Cells(Rows.count, 1).End(xlUp).Resize(, 13)
OLApp.Session.Logon
With OLMail
.To = ""
.CC = ""
.BCC = ""
.Subject = "Quality Alert"
.HTMLBody = "<P><font size='6' face='Calibri' color='black'>Quality Issue Found<br><br> Please reply back with what adjustments have been made to correct this issue. </font></P>" & ConvertRangeToHTMLTable(ThisWorkbook.Worksheets("Database").Cells(Rows.count, 1).End(xlUp).Resize(, 13))
Dim ws As Worksheet
Set ws = ActiveWorkbook.Sheets("Database")
Dim wb As Workbook
ws.Copy
Set wb = ActiveWorkbook
wb.SaveAs "C:\Temp\Database.xlsx" 'Change Path
.Display
' .Send
wb.Close SaveChanges:=False
Kill "C:\Temp\Database.xlsx"
End With
'Clearing Memory
Set OLMail = Nothing
Set OLApp = Nothing
End Sub
Only the 1st 13 columns of the last row are being targeted.
ThisWorkbook.Worksheets("Database").Cells(Rows.count, 1).End(xlUp).Resize(, 13)
I order to include all the data, you'll have to extend the range from the first cell to the last row.
With ThisWorkbook.Worksheets("Database")
Set MyData = .Range(.Cells(1, 1), .Cells(Rows.Count, 1).End(xlUp).Resize(, 13))
End With
Breaking up the code into smaller bites will allow you to easily isolate and test your code.
Extracting the code that targets the data range into its own function (in a public module) allows use Application.Goto to visibly inspect the range.
Application.Goto EmailData
Private Sub cmdEmail_Click()
Dim HTMLBody As String
HTMLBody = EmailHTMLFirstAndLastRow
SendEmail HTMLBody
CreateACopyOfTheDatabaseSaveItCloseKillItButNeverDoAnythingWithit
End Sub
Place this code in a public module:
Sub SendEmail(HTMLBody As String)
'Declare Outlook Variables
Dim OLApp As Outlook.Application
Dim OLMail As Object
Dim MyData As Object
'Open the Outlook Application and Start a new mail
Set OLApp = New Outlook.Application
Set OLMail = OLApp.CreateItem(0)
OLApp.Session.Logon
With OLMail
.To = ""
.CC = ""
.BCC = ""
.Subject = "Quality Alert"
.HTMLBody = "<P><font size='6' face='Calibri' color='black'>Quality Issue Found<br><br> Please reply back with what adjustments have been made to correct this issue. </font></P>" & HTMLBody
.Display
' .Send
End With
'Clearing Memory
Set OLMail = Nothing
Set OLApp = Nothing
End Sub
Function EmailHTMLFirstAndLastRow() As String
Dim Target As Range
Set Target = EmailData
With Target
.EntireRow.Hidden = msoTrue
.Rows(1).Hidden = msoFalse
.Rows(.Rows.Count).Hidden = msoFalse
.EntireRow.Hidden = msoFalse
End With
EmailHTMLFirstAndLastRow = RangetoHTML(Target.Rows(Target.Rows.Count))
End Function
Function EmailData() As Range
With ThisWorkbook.Worksheets("Database")
Set EmailData = .Range(.Cells(1, 1), .Cells(Rows.Count, 1).End(xlUp).Resize(, 13))
End With
End Function
Sub CreateACopyOfTheDatabaseSaveItCloseKillItButNeverDoAnythingWithit()
Dim ws As Worksheet
Set ws = ActiveWorkbook.Sheets("Database")
Dim wb As Workbook
ws.Copy
Set wb = ActiveWorkbook
wb.SaveAs "C:\Temp\Database.xlsx" 'Change Path
wb.Close SaveChanges:=False
Kill "C:\Temp\Database.xlsx"
End Sub
Edit
I edited the code to create html for only the header and last rows, as per the OP's request. Since RangetoHTML() ignores hidden rows, I define the range of data, hid all but the fist and last rows, the passed the range to RangetoHTML() and assigned its value to a variable, the unhid the range.

How to hide columns in dynamic subranges before converttohtml in emailbody in Outlook?

I am doing a macro that is formatting a data base into a table, and then select ranges from this table in order to send to different persons depending of the range.
But depending of the range sometimes I can have several column empty, I would like to add in my loop that when creating the temporary workbook, to copy paste my subtable that I wanna send, a function or a part that check if the column is empty (I have headers) and if it's the case, hide the columns concerned only for this range and then convert to HTML in my body email the range without my empty column now hidden and after the loop keeps going through my whole table.
Thanks to a previous post, my VBA code is running smoothly but as soon as I add the part which is supposed to hide column, it's not working anymore, I guess, that I am not adding it in the right place but I don't know,
I tried to add it, just after RangeToEmail and in the function that is creating the tempWB, RangetoHTML but it's not working. (see both codes after)
The code I used on a static range and which is working, to hide the column is
Dim iFirstCol As Integer, iLastCol As Integer, i As Integer`
'variables to hold the first and last column numbers
iFirstCol = Range("A2").Column
iLastCol = Range("W2").Column
LastRow = Range(Range("A2"), Range("A2").End(xlDown))
'count backwards through columns
For i = iLastCol To iFirstCol Step -1
'if all cells are blank, hide the column
If WorksheetFunction.CountA(Range(Cells(1, i), Cells(LastRow, i))) = 0 Then
Columns(i).EntireColumn.Hidden = True
End If
Next i
and here is the code I use to go from my table to the different subtable and then through TemporaryWB convert to html in my email body
Option Explicit
Sub GetNames()
Dim NameArray() As String
Dim NameRange As Range
Dim C As Range
Dim Counter As Integer
Dim NameFilter As Variant
Dim RangeToEmail As Range
Dim EmailAddress() As String
'Email Stuff
Dim objOutlook As Object
Set objOutlook = CreateObject("Outlook.application")
Dim objEmail As Object
Set NameRange = Range(Range("H2"), Range("H2").End(xlDown))
ReDim NameArray(1 To Range(Range("H2"), Range("H2").End(xlDown)).Rows.Count) ReDim EmailAddress(1 To Range(Range("H2"), Range("H2").End(xlDown)).Rows.Count)
Counter = 0
For Each C In NameRange
Counter = Counter + 1
NameArray(Counter) = C.Value
EmailAddress(Counter) = C.Offset(, 3)
Next
NameArray = ArrayRemoveDups(NameArray)
EmailAddress = ArrayRemoveDups(EmailAddress)
Counter = 0
For Each NameFilter In NameArray
Counter = Counter + 1
ActiveSheet.Range("A1").AutoFilter Field:=8, Criteria1:=NameFilter Set RangeToEmail = ActiveSheet.ListObjects("DataTable").Range
Set objEmail = objOutlook.CreateItem(olMailItem)
With objEmail .To = EmailAddress(Counter)
.Subject = "TestSubject"
.HTMLBody = "Hello, <br><br>Please see the latest report:<br><br>" & RangetoHTML(RangeToEmail)
.Display
End With
Set objEmail = Nothing
Next
ActiveSheet.Range("A1").AutoFilter
End Sub
Function ArrayRemoveDups(MyArray As Variant) As Variant
Dim nFirst As Long, nLast As Long, i As Long
Dim item As String
Dim arrTemp() As String
Dim Coll As New Collection
'Get First and Last Array Positions
nFirst = LBound(MyArray)
nLast = UBound(MyArray)
ReDim arrTemp(nFirst To nLast)
'Convert Array to String
For i = nFirst To nLast
arrTemp(i) = CStr(MyArray(i))
Next i
'Populate Temporary Collection
On Error Resume Next
For i = nFirst To nLast
Coll.Add arrTemp(i), arrTemp(i)
Next i
Err.Clear
On Error GoTo 0
'Resize Array
nLast = Coll.Count + nFirst - 1
ReDim arrTemp(nFirst To nLast) '
Populate Array
For i = nFirst To nLast
arrTemp(i) = Coll(i - nFirst + 1)
Next i
'Output Array
ArrayRemoveDups = arrTemp
End Function
Function RangetoHTML(rng As Range)
Dim fso As Object
Dim ts As Object
Dim TempFile As String
Dim TempWB As Workbook
TempFile = Environ$("temp") & "/" & Format(Now, "dd-mm-yy h-mm-ss") & ".htm"
' Copy the range and create a workbook to receive the data.
rng.Copy
Set TempWB = Workbooks.Add(1)
With TempWB.Sheets(1)
.Cells(1).PasteSpecial Paste:=8
.Cells(1).PasteSpecial xlPasteValues, , False, False
.Cells(1).PasteSpecial xlPasteFormats, , False, False
.Cells(1).Select
Application.CutCopyMode = False
On Error Resume Next
.DrawingObjects.Visible = True
.DrawingObjects.Delete
On Error GoTo 0
End With
' Publish the sheet to an .htm file.
With TempWB.PublishObjects.Add( _ SourceType:=xlSourceRange, _ Filename:=TempFile, _ Sheet:=TempWB.Sheets(1).Name, _ Source:=TempWB.Sheets(1).UsedRange.Address, _ HtmlType:=xlHtmlStatic)
.Publish (True)
End With
' Read all data from the .htm file into the RangetoHTML subroutine.
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.GetFile(TempFile).OpenAsTextStream(1, -2)
RangetoHTML = ts.ReadAll
ts.Close RangetoHTML = Replace(RangetoHTML, "align=center x:publishsource=", _ "align=left x:publishsource=")
' Close TempWB. TempWB.Close savechanges:=False
' Delete the htm file.
Kill TempFile
Set ts = Nothing
Set fso = Nothing
Set TempWB = Nothing
End Function
First LastRow is not declared as variable properly and therfore you didn't see that
LastRow = Range(Range("A2"), Range("A2").End(xlDown))
is actually writing an array of values into LastRow. Actually your first code cannot work properly. Make sure you use Option Explicit (I recommend always to activate Option Explicit: In the VBA editor go to Tools › Options › Require Variable Declaration).
The issue is probably if your empty columns have headers too then
WorksheetFunction.CountA(Range(Cells(1, i), Cells(LastRow, i)))
will never be 0 because you included your header row 1 Cells(1, i) in your range. So if you want to exclude the header you need to change it to start with row 2 like Cells(2, i).
Finally all this code applies to ActiveSheet which is not very reliable because the active sheet can change by a single mouse click. If you can specify the worksheet precisely by a name, do so. If it really has to run on multiple sheets (so you really want to use the active one) at least make sure the active sheet does not change during the code excecutes by reading it only once into a variable Set ws = ThisWorkbook.ActiveSheet.
I would use
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1") 'name your sheet here!
'or if it really is the active sheet do
'Set ws = ThisWorkbook.ActiveSheet 'and make sure you only use `ws` from now!
'variables to hold the first and last column numbers
Dim iFirstCol As Long
iFirstCol = ws.Columns("A").Column
Dim iLastCol As Long
iLastCol = ws.Columns("W").Column
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlDown).Row
'count backwards through columns
Dim i As Long
For i = iLastCol To iFirstCol Step -1
'if all cells are blank, hide the column
If Application.WorksheetFunction.CountA(ws.Range(ws.Cells(2, i), ws.Cells(LastRow, i))) = 0 Then
ws.Columns(i).EntireColumn.Hidden = True
End If
Next i
Apply the same to the rest of your code to make it more reliable.

Access VBA to open, edit and save Excel doc

I have an Access DB to open, edit and save an Excel doc that works fine the first time run but if I try to alter more than one file (or the same file twice) it fails with "Run-time error '1004': Method 'Cells' of object '_Global' failed"
If I close the DB then re-open it, it again works fine for the first file altered.
Although I am not new to VBA I would say that I am a novice. Here is a snippit of the code I am using:
Code:
'Open spreadsheet and make it visible
Set xl = CreateObject("Excel.Application")
strInputFile = varItem
xl.Workbooks.Open strInputFile
xl.Visible = True
'Trying to get row count here but not working yet
'Set myRange = xl.Sheets("Sheet1").Range("C:C")
'lRowCount = Excel.Application.WorksheetFunction.CountA("Sheet1").Range("C:C")
'lRowCount = xl.WorksheetFunction.CountA(Worksheets("Sheet1").Cells(C, C))
'Debug.Print lRowCount
'strMyRange = "C:C"
'lRowCount = xl.WorksheetFunction.CountA(strMyRange)
'Debug.Print lRowCount
'lRowCount = Excel.Application.WorksheetFunction.CountA(Workbooks(strInputFile).Sheets("Sheet1").Range("C:C"))
'Debug.Print lRowCount
'Make the changes
j = 0
If Left(strFile, 4) = "xxxx" Then
myPath = "\\a\path\for\xxxx"
If InStr(1, strFile, "IQ") Then
For i = 1 To 500 'Row count not working yet
If InStr(1, Cells(i, "C").Value, myVariable) > 0 Then
Cells(i, "B") = "New Value"
j = j + 1
End If
Next
End If
End If
'Clean up
xl.Quit
Set xl = Nothing
Set objInputFile = Nothing
The Excel VBA code for using in Access should be modified. You cannot use direct calls of Excel library methods like Cell. Declare variables for Excel.Application, Workbook and Worksheet and use them for referencing worksheet cells. Avoid using Activate methods. So, in your case the code will be like this:
Dim xl As Excel.Application
Dim wb As Excel.Workbook
Dim ws As Excel.Worksheet
Dim lRowCount As Long
Dim myRange As Excel.Range
Set xl = CreateObject("Excel.Application")
strInputFile = varItem
Set wb = xl.Workbooks.Open(strInputFile)
Set ws = wb.Sheets("Sheet1")
lRowCount = ws.UsedRange.Rows.Count
'Make the changes
j = 0
If Left(strFile, 4) = "xxxx" Then
myPath = "\\a\path\for\xxxx"
If InStr(1, strFile, "IQ") Then
For i = 1 To lRowCount
If InStr(1, ws.Cells(i, "C").Value, myVariable) > 0 Then
ws.Cells(i, "B") = "New Value"
j = j + 1
End If
Next
End If
End If
wb.Save
'Clean up
xl.Quit
Set xl = Nothing
Don't forget to add a reference to Microsoft Excel library

Export Excel Range to Access table VBA

I want to have a button on the Excel spreadsheet and have the data copied to the Access table.
The range is an auto-populated field from another sheet in the same workbook.
I tried few codes to make this happen, but I either get an error 1004: application-defined or object-defined error, or no error but data not being copied in Access DB.
My code is copied below.
Sub Export_Data()
Dim cnn As ADODB.Connection
Dim rst As ADODB.Recordset
Dim dbPath
Dim x As Long, i As Long
dbPath = "H:\RFD\RequestForData.accdb"
Set cnn = New ADODB.Connection
cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & dbPath
Set rst = New ADODB.Recordset 'assign memory to the recordset
rst.Open Source:="tblRequests", ActiveConnection:=cnn, _
CursorType:=adOpenDynamic, LockType:=adLockOptimistic, _
Options:=adCmdTable
rst.AddNew
For i = 1 To 13
rst(Cells(1, i).Value) = Cells(x, i).Value
Next i
rst.Update
rst.Close
cnn.Close
Set rst = Nothing
Set cnn = Nothing
MsgBox " The data has been successfully sent to the access database"
Set rst = Nothing
Set cnn = Nothing
End Sub
Looking at your Subroutine I see two things that can make it not to work:
rst(Cells(1, i).Value) = Cells(x, i).Value <- Where is 'x' initialized?
There is only one loop that moves over the fields but I think it should be another loop for the rows in the Excel.
With this two changes, the loop when the records are save could become something like this:
For x = 1 TO lastRow ' Last row has to be calculated somehow
rst.AddNew
For i = 1 To 13
rst(Cells(1, i).Value) = Cells(x, i).Value
Next i
rst.Update
Next x
Hope it helps.

Access TransferSpreadsheet - Replace Data

I am exporting query from Access to an Excel sheet calles "tempIcIn". When the sheet is already existing in the file, TransferSpreadsheet will just create another sheet with the same name followed by a 1.
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12, "tempIcIn", outputPath, True
I would like to overwrite the data which is already in the created sheet.
http://btabdevelopment.com/export-a-table-or-query-to-excel-specific-worksheet-on-specific-workbook/
Public Function SendTQ2XLWbSheet(strTQName As String, strSheetName As String, strFilePath As String)
' strTQName is the name of the table or query you want to send to Excel
' strSheetName is the name of the sheet you want to send it to
' strFilePath is the name and path of the file you want to send this data into.
Dim rst As DAO.Recordset
Dim ApXL As Object
Dim xlWBk As Object
Dim xlWSh As Object
Dim fld As DAO.Field
Dim strPath As String
Const xlCenter As Long = -4108
Const xlBottom As Long = -4107
On Error GoTo err_handler
strPath = strFilePath
Set rst = CurrentDb.OpenRecordset(strTQName)
Set ApXL = CreateObject("Excel.Application")
Set xlWBk = ApXL.Workbooks.Open(strPath)
ApXL.Visible = True
Set xlWSh = xlWBk.Worksheets(strSheetName)
xlWsh.Activate
xlWSh.Range("A1").Select
For Each fld In rst.Fields
ApXL.ActiveCell = fld.Name
ApXL.ActiveCell.Offset(0, 1).Select
Next
rst.MoveFirst
xlWSh.Range("A2").CopyFromRecordset rst
xlWSh.Range("1:1").Select
' This is included to show some of what you can do about formatting. You can comment out or delete
' any of this that you don't want to use in your own export.
With ApXL.Selection.Font
.Name = "Arial"
.Size = 12
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
End With
ApXL.Selection.Font.Bold = True
With ApXL.Selection
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlBottom
.WrapText = False
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.MergeCells = False
End With
' selects all of the cells
ApXL.ActiveSheet.Cells.Select
' does the "autofit" for all columns
ApXL.ActiveSheet.Cells.EntireColumn.AutoFit
' selects the first cell to unselect all cells
xlWSh.Range("A1").Select
rst.Close
Set rst = Nothing
Exit_SendTQ2XLWbSheet:
Exit Function
err_handler:
DoCmd.SetWarnings True
MsgBox Err.Description, vbExclamation, Err.Number
Resume Exit_SendTQ2XLWbSheet
End Function
The link is just the code that should do the trick.