Save text in access when clicking on a hyperlink in Excel - excel

I have an Excel sheet with a code that gives every row a hyperlink at the end.
What should be happening next is: Once i click this hyperlink, "Data is confirmed" should be saved to an Access file.
For example: There are 10 rows, thanks to the current code, a hyperlink gets added to every single row. If i click on this hyperlink on row 8 , "Data is confirmed" should be added to the Access file on row 8 (and only row 8!)
Thanks to Basodre, i currently have this code but can't figure out a way to get a text saved in Access. Any ideas?
Private Sub Worksheet_FollowHyperlink(ByVal Target As Hyperlink)
'Confirm that this is a hyperlink in column 3
If Not Intersect(Target.Range, Columns(3)) Is Nothing Then
MsgBox SaveData(Target.Range)
End If
End Sub
Private Function SaveData(rng As Range) As Boolean
Debug.Print rng.Address & " has been saved."
SaveData = True
End Function

I have an class module I use for creating DB objects. It's name is AccessBackEnd.
Option Explicit
' ConnectModeEnum
'Private Const adModeRead = 1
'Private Const adModeReadWrite = 3
Private Const adModeShareDenyNone As Long = 16
' adStateEnum
'Const adStateClosed As Long = 0 'Indicates that the object is closed.
Const adStateOpen As Long = 1 'Indicates that the object is open.
'Const adStateConnecting As Long = 2 'Indicates that the object is connecting.
'Const adStateExecuting As Long = 4 'Indicates that the object is executing a command.
'Const adStateFetching As Long = 8 'Indicates that the rows of the object are being retrieved.
' CursorTypeEnum
Const adOpenStatic As Long = 3
' LockTypeEnum
Const adLockOptimistic As Long = 3
Private dataSource As Object
Public Property Get Connection() As Object
If dataSource Is Nothing Then
Set dataSource = CreateObject("ADODB.Connection")
With dataSource
.Provider = "Microsoft.ACE.OLEDB.12.0"
.Mode = adModeShareDenyNone
End With
End If
Set Connection = dataSource
End Property
Private localFileName as string
Public Property Get FileName() As String
FileName = localFileName
End Property
Public Property Set FileName(newFileName As String) As String
localFileName = newFileName
End Property
Public Sub Connect(ByVal dataBaseName As String)
Connection.Open "Data Source=" & dataBaseName & ";"
End Sub
''' Recordset command is used to access table data
Public Function Record(ByVal sqlQuery As String) As Object
If Not ((Connection.state And adStateOpen) = adStateOpen) Then
Connect FileName
End If
Set Record = CreateObject("ADODB.Recordset")
Record.Open Source:=sqlQuery, ActiveConnection:=Connection, CursorType:=adOpenStatic, LockType:=adLockOptimistic
End Function
Public Sub Dispose()
If dataSource Is Nothing Then
Debug.Print "You disposed of nothing..."
Else
If (Connection.state And adStateOpen) = adStateOpen Then dataSource.Close
Set dataSource = Nothing
End If
End Sub
This example shows how you can update an Access field from Excel.
Dim thisDB As AccessBackEnd
Set thisDB = New AccessBackEnd
thisDB.FileName = "Your DB full path goes here.accdb"
With thisDB.Record("SELECT * FROM yourTable WHERE ID=" & PrimaryKey & ";")
If Not (.EOF Or .BOF) Then
.Fields("Your Field to update goes here").Value = rng.Address
.Update
End If
End With
thisDB.Dispose

Related

Adding columns gives error Run-time error '1004' Application-defined or object-defined error

This is odd, this code worked yesterday to add columns today it errors. Below is all there is of the code.
Option Explicit
'Workbook, worksheets setting
Public WbName As Workbook
Public WsName1 As Worksheet, WsName2 As Worksheet, WsName3 As Worksheet, WsName4 As Worksheet
Const SPSITE = "xxxxxxxxxxxx.sharepoint.com/teams/xxxxxxTeam"
Const SRCLIST = "{57FDE37F-5EBD-ZZZZ-XXXX-EBE432345E2B}"
Public Src(0 To 1) As Variant
Dim MyTableName As String
Public ObjListTable As ListObject
Public LastRowEquip As Long
Public LastColEquip As Long
Dim Wrk As String, TableTxt As String
Sub Headache()
Set WbName = ThisWorkbook
Windows(ThisWorkbook.Name).Activate
Set WsName3 = WbName.Sheets("Sheet3")
Set WsName4 = WbName.Sheets("Sheet4")
'Delete all off sheet
WsName4.Cells.Delete
'download Table
Src(0) = "https://" & SPSITE & "/_vti_bin"
Src(1) = SRCLIST
WsName4.ListObjects.Add xlSrcExternal, Src, True, xlYes, WsName4.Range("A1")
'Once table is open
Set ObjListTable = WsName4.ListObjects(1)
'Done this way to prove List objects could be read
LastRowEquip = ObjListTable.ListRows.Count
LastColEquip = ObjListTable.ListColumns.Count
TableTxt = ObjListTable.Name
MsgBox TableTxt & " Last row " & LastRowEquip & " Last column " & LastColEquip 'just proof
'add columns
ObjListTable.ListColumns.Add(LastColEquip + 1).Range.Resize(, 2).Insert '******* guilty line *******'
'copy in data
WsName4.Range("P1:S" & LastRowEquip).Value = WsName3.Range("A1:D" & LastRowEquip).Value '**** Temporary till Sharepoint updated
End Sub
The line that causes the error is the one that says "guilty".
I am suspected it got disconnected from Sharepoint. I found that if I hit the unlink button then the code will work.

VBA code equivalent to "SELECT * FROM [query] where [column] = combobox

I have a data connection in my xlsm file, which is called "DATA".
I created my combo box and input the value from a range.
Now I need to return a result set based on the value from the combo box (drop down list). e.g. if the value in the dropdown list is "CompanyXYZ", then my query from "DATA" needs to be returned but only the data for CompanyXYZ.
The sql equivalent is:
"SELECT * FROM [query] where [column] = combobox
Issue #1
Below is my sheet("DATA"). It has a table returned by the SQL query. One of the columns is Debtor_Name. It has more than 8500 rows but only 90 are unique.
In my other sheet, I have an ActiveX ComboBox that needs to return all the unique values from DATA.Debtor_name column (the 90 unique values).
Sample VBA for issue #1:
Sub Populate_Combobox_Worksheet()
'The Excel workbook and worksheets that contain the data, as well as the range placed on that data
Dim wbBook As Workbook
Dim wsSheet As Worksheet
Dim rnData As Range
'Variant to contain the data to be placed in the combo box.
Dim vaData As Variant
'Initialize the Excel objects
Set wbBook = ThisWorkbook
Set wsSheet = wbBook.Worksheets("DATA")
'Set the range equal to the data, and then (temporarily) copy the unique values of that data to the L column.
With wsSheet
Set rnData = .Range(.Range("D1"), .Range("D10000").End(xlUp))
rnData.AdvancedFilter Action:=xlFilterCopy, _
CopyToRange:=.Range("X1"), _
Unique:=True
'store the unique values in vaData
vaData = .Range(.Range("X2"), .Range("X10000").End(xlUp)).Value
'clean up the contents of the temporary data storage
.Range(.Range("X1"), .Range("X10000").End(xlUp)).ClearContents
End With
'display the unique values in vaData in the combo box already in existence on the worksheet.
With wsSheet.OLEObjects("ComboBox1").Object
.Clear
.List = vaData
.ListIndex = -1
End With
End Sub
Issue #2.
Now the end user will need to select a debtor_name from the combo box, then click on refresh data. This DATA REFRESH will need to only pull the data from SQL where debtor_name = [selected value in combo box]
I asked about for issue #2 because I did not know I had an issue with my combo box (issue #1); however, I can handle that somehow; only need help with issue #2 now.
You can use SQL to populate the ComboBox with unique values.
Option Explicit
Sub Populate_Combobox_Worksheet()
Dim con As ADODB.Connection, rs As ADODB.Recordset, SQL As String
Set con = GetConnection
' query
SQL = " SELECT DISTINCT [Debtor_name] FROM [DATA$]" & _
" WHERE [Debtor_name] IS NOT NULL" & _
" ORDER BY [Debtor_Name]"
Set rs = con.Execute(SQL)
With Sheet2.ComboBox1
.Clear
.List = Application.Transpose(rs.GetRows)
.ListIndex = -1
End With
con.Close
End Sub
Sub RefreshData()
Dim con As ADODB.Connection, rs As ADODB.Recordset, SQL As String
Set con = GetConnection
' query
SQL = " SELECT * FROM [DATA$]" & _
" WHERE [Debtor_name] = '" & Sheet2.ComboBox1.Value & "'"
Set rs = con.Execute(SQL)
Sheet2.Range("A1").CopyFromRecordset rs
con.Close
End Sub
Function GetConnection() As ADODB.Connection
Dim wb As Workbook, sCon As String
Set wb = ThisWorkbook
sCon = "Data Source=" & wb.FullName & "; " & _
"Extended Properties=""Excel 12.0;HDR=Yes;"";"
' connect
Set GetConnection = New ADODB.Connection
With GetConnection
.Provider = "Microsoft.ACE.OLEDB.12.0;"
.ConnectionString = sCon
.Open
End With
End Function

Sub or Function Not Defined Error - Sub in Class Module

I am attempting to pass values from an ADODB.Recordset into a Class Module and am receiving the Sub or Function Not Defined Error when I call Call PopulateJHAData(GeneralInfo.Range("genLoanProg"), CStr(nm)) from within the function to get the data from the recordset; I know i dont need Call in front of the sub; I was just seeing if it made any difference. I can already imagine that there are a host of other items that are wrong with this code since I am just now getting into how to use Class Modules.
'---Class Loan Info
Public LoanNumber As String
Public InterestRate As String
Public OriginalAmount As Double
Public OriginationDate As String
Public MaturityDate As Date
Public NextPaymentDate As Date
Public PaymentAmount As Double
Public Census As String
Public RateNumber As Long
Public Margin As String
Public RoundTo As String
Public RateCeiling As String
Public RateChangeDate As Date
Public ARMNotice As String
Public QualifiedMortgageCode As String
Public ln1098 As String
Public CallReportCode As String
Public CollateralCode As String
Public PurposeCode As String
Public HPML As String
Public LoanTypeCode As String
Public Flood As String
Public CLTV As String
Public Branch As Long
Public FHLBElig As String
Public RepToCB As String
Public Occupancy As String
Public tName As String
Public eNumber As Long
Public Sub PopulateJHAData(ByVal LoanProg As String, ByVal TableName As String, ByVal JHALoanInfo As ADODB.Recordset)
Select Case Left(LoanProg, 4)
Case Is = "FHLB", "Cons", "15yr"
InterestRate = Trim(JHALoanInfo.Fields("Rate").Value)
LoanAmount = Trim(JHALoanInfo.Fields("OrigAmnt").Value)
LoanDate = Trim(JHALoanInfo.Fields("OrigDate").Value)
MaturityDate = Trim(JHALoanInfo.Fields("MatDate").Value)
NextPaymentDate = Trim(JHALoanInfo.Fields("NextPmtDate").Value)
PaymentAmount = Trim(JHALoanInfo.Fields("PaymentAmt").Value)
Census = Trim(JHALoanInfo.Fields("Census").Value)
QualifiedMortgageCode = Trim(JHALoanInfo.Fields("QMCode").Value)
ln1098 = Trim(JHALoanInfo.Fields("ln1098").Value)
CallReportCode = Trim(JHALoanInfo.Fields("CallRep").Value)
CollateralCode = Trim(JHALoanInfo.Fields("ColCode").Value)
PurposeCode = Trim(JHALoanInfo.Fields("PurpCode").Value)
HPML = Trim(JHALoanInfo.Fields("HPML").Value)
LoanTypeCode = Trim(JHALoanInfo.Fields("LnTypeCode").Value)
Flood = Trim(JHALoanInfo.Fields("Flood").Value)
CLTV = Trim(JHALoanInfo.Fields("CombLTV").Value)
Branch = Trim(JHALoanInfo.Fields("Branch").Value)
FHLBElig = Trim(JHALoanInfo.Fields("EligFHLV").Value)
RepToCB = Trim(JHALoanInfo.Fields("RepCB").Value)
Occupancy = Trim(JHALoanInfo.Fields("Occupancy").Value)
Case Else
InterestRate = Trim(JHALoanInfo.Fields("Rate").Value)
LoanAmount = Trim(JHALoanInfo.Fields("OrigAmnt").Value)
LoanDate = Trim(JHALoanInfo.Fields("OrigDate").Value)
MaturityDate = Trim(JHALoanInfo.Fields("MatDate").Value)
NextPaymentDate = Trim(JHALoanInfo.Fields("NextPmtDate").Value)
PaymentAmount = Trim(JHALoanInfo.Fields("PaymentAmt").Value)
Census = Trim(JHALoanInfo.Fields("Census").Value)
RateNumber = Trim(JHALoanInfo.Fields("RateNum").Value)
Margin = Trim(JHALoanInfo.Fields("Margin").Value)
RoundTo = Trim(rs.Fields("RoundTo").Value)
RateCeiling = Trim(rs.Fields("RateCeiling").Value)
RateChangeDate = Trim(rs.Fields("RateChangeDate").Value)
ARMNotice = Trim(rs.Fields("ArmNot").Value)
QualifiedMortgageCode = Trim(JHALoanInfo.Fields("QMCode").Value)
ln1098 = Trim(JHALoanInfo.Fields("ln1098").Value)
CallReportCode = Trim(JHALoanInfo.Fields("CallRep").Value)
CollateralCode = Trim(JHALoanInfo.Fields("ColCode").Value)
PurposeCode = Trim(JHALoanInfo.Fields("PurpCode").Value)
HPML = Trim(JHALoanInfo.Fields("HPML").Value)
LoanTypeCode = Trim(JHALoanInfo.Fields("LnTypeCode").Value)
Flood = Trim(JHALoanInfo.Fields("Flood").Value)
CLTV = Trim(JHALoanInfo.Fields("CombLTV").Value)
Branch = Trim(JHALoanInfo.Fields("Branch").Value)
FHLBElig = Trim(JHALoanInfo.Fields("EligFHLV").Value)
RepToCB = Trim(JHALoanInfo.Fields("RepCB").Value)
Occupancy = Trim(JHALoanInfo.Fields("Occupancy").Value)
End Select
End Sub
Sub LoanInfoGrab()
uName = Environ("username")
empName = StrConv(Left(uName, Len(uName) - 1), vbProperCase)
Dim lnNum As String
lnNum = GeneralInfo.Range("genLoanNumber")
msgCap = "Hello " & empName & "," & vbCrLf & _
"The data for " & lnNum & " is not available, or unable to be retrieved." & _
"This loan will need to be manually checked."
Dim LoanRecordGrab As clsLoanInfo
'passing in all potential table names/sources in array
Set LoanRecordGrab = getLoanInfoRecord(Array(CNCTTP08, BHSCHLP8))
Dim nm
If LoanRecordGrab Is Nothing Then
MsgBox msgCap, vbExclamation, "Error Getting Data"
Else
rem not sure if this should be the sub from the class module or if it should be LoanRecordGrab.
'PopulateJHAData GeneralInfo.Range("genLoanProg"), CStr(nm) yet.
End If
JHACheckFormat
Dim lnData As Range, cData1 As Range, cData2 As Range
Set lnData = JHACheck.Range("H7:H32")
Set cData1 = JHACheck.Range("H35:H41")
Set cData2 = JHACheck.Range("K35:K41")
If loanData.Range("CIF_2") = vbNullString Then
CompareJHACheck lnData, cData1
Else
CompareJHACheck lnData, cData1, cData2
End If
End Sub
Function getLoanInfoRecord(arrNames) As clsLoanInfo
Dim conn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim SQL As String, nm, okSql As Boolean
Dim LoanRecordGrab As clsLoanInfo
Dim lNum As Range: Set lNum = GeneralInfo.Range("genLoanNumber")
conn.Open CONNSTR
'try each provided name: exit loop on successful query
For Each nm In arrNames
SQL = getLoanDBGrabSQL(CStr(nm), lNum)
On Error Resume Next
rs.Open SQL, conn 'try this name
If Err.Number = CONNECTIONERROR Then
okSql = False
Else
okSql = True
End If
On Error GoTo 0 'cancel on error resume next
If okSql Then
If rs.EOF Then
'rs.MoveFirst
Do While Not rs.EOF
Set LoanRecordGrab = New clsLoanInfo 'create an instance to populate
Call PopulateJHAData(GeneralInfo.Range("genLoanProg"), CStr(nm)) 'Sub or Function not Defined happens here
rs.MoveNext
Loop
End If
Exit For 'done trying names
End If
Next nm
If rs.State = adStateOpen Then rs.Close
If conn.State = adStateOpen Then conn.Close
Set getLoanInfoRecord = LoanRecordGrab
End Function

VBA adodb. Would I be overwriting the connections? Does it naturally timeout?

I recently coded something for an assignment and I lost marks for not closing a connection and I'm curious about two things. First do ADODB connections for VBA naturally timeout after a few seconds and would I be overwriting the connection for my code included below or would I end up having multiple ADODB connections? In essence, did I do anything wrong by not closing the connections? Thanks.
Option Explicit
'Declaring all necessary variables - Global saves me from redeclaring and allows to be carried
Public dbMyDatabase As String, CnctSource As String, Src As String
Public rstNewQuery As ADODB.Recordset, cntStudConnection As ADODB.Connection
Public Selected1st As String
Private Sub Cancel_Click()
Unload Me
Worksheets("Question3").Range("D4:E9").Clear
End Sub
Private Sub Clear_Click()
Worksheets("Question3Products").Range("C3:H42").Clear
End Sub
Private Sub UserForm_Initialize()
'Get database and links it
dbMyDatabase = ThisWorkbook.Path & "\SalesOrders.mdb"
Set cntStudConnection = New ADODB.Connection
CnctSource = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & dbMyDatabase & ";"
cntStudConnection.Open ConnectionString:=CnctSource
'Commence Query for Categories
Set rstNewQuery = New ADODB.Recordset
rstNewQuery.Open Source:="Categories", ActiveConnection:=cntStudConnection
Range("D4").CopyFromRecordset rstNewQuery
Range("D4:E9").Name = "BufferRange"
TheList.RowSource = "BufferRange"
TheList.Selected(1) = True
'Input Into Listbox
'Decided that clearing the values for connections would be redundant and wasteful.
End Sub
Private Sub FindInfo_Click()
Dim i As Integer
'Switching Sheets and Clearing Previous Variables
Worksheets("Question3Products").Activate
Range("C3:H42").Clear
'Selecting Value user wishes to search for
For i = 0 To TheList.ListCount - 1
If TheList.Selected(i) Then
Selected1st = TheList.List(i)
End If
Next i
'Commence query to search. Decided not to make a function to call upon due to different variables and only 2 instances of use
dbMyDatabase = ThisWorkbook.Path & "\SalesOrders.mdb"
Set cntStudConnection = New ADODB.Connection
CnctSource = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & dbMyDatabase & ";"
cntStudConnection.Open ConnectionString:=CnctSource
Set rstNewQuery = New ADODB.Recordset
Dim StringUse As String
StringUse = "SELECT* From Products WHERE CategoryID = " & Selected1st
rstNewQuery.Open Source:=StringUse, ActiveConnection:=cntStudConnection
Range("C3").CopyFromRecordset rstNewQuery
Range("F3:F42").Style = "Currency"
End Sub

Parse ADO Recordset to Individual Excel Sheets

I'm trying to take an ADO Recordset and then loop through it to parse individual rows to different worksheets within an Excel workbook. Unfortunately, as I step through my code, I get the following error: Run-time error '13': Type mismatch. This occurs when I call the sub in my code - it never actually steps into the sub. I'm wondering if I'm somehow not passing the Recordset in correctly or if it's a problem somewhere within my loop.
Regardless, here's my code - any help is greatly appreciated!
Sub SplitData(ByVal rs As ADODB.Recordset)
' Instantiate count variables for each result type
' Start at 2 to give room for Table headers on sheets
Dim NewAppsCount, BadLogCount, MatNotesCount, ZeroBalCount As Integer
NewAppsCount , BadLogCount, MatNotesCount, ZeroBalCount = 2
' Row Counter
Dim Count As Long
Count = 0
' Loop through the recordset and parse rows to appropriate worksheets
Do While Not rs.EOF
If CStr(rs.Fields("Maturity Date")) = "" Then
If CStr(rs.Fields("Log_Date")) = "" Then
' Applications that have not been properly logged
Sheet4.Range("A" & CStr(BadLogCount)) = rs.Fields(Count).Value
Count = Count + 1
BadLogCount = BadLogCount + 1
Else
' New Applications
Sheet6.Range("A" & CStr(NewAppsCount)) = rs.Fields(Count).Value
Count = Count + 1
NewAppsCount = NewAppsCount + 1
End If
Else
If Month(rs.Fields("Maturity Date")) < Month(Date) Then
' Maturing Notes with Zero Outstanding Balance
Sheet7.Range("A" & CStr(ZeroBalCount)) = rs.Fields(Count).Value
Count = Count + 1
ZeroBalCount = ZeroBalCount + 1
Else
' Maturing Notes
Sheet8.Range("A" & CStr(MatNotesCount)) = rs.Fields(Count).Value
Count = Count + 1
MatNotesCount = MatNotesCount + 1
End If
End If
rs.MoveNext
Loop
End Sub
Here is the sub that call GetData:
Sub GetData(ByVal Update As Boolean)
Dim conn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim query As String
Dim path As String
Dim prompt, result As Integer
Dim day, today As String
' ...skipping stuff not related to the issue...
' Set the UNC Path
path = "\\this\is\the\path"
' Instantiate ADO Objects
Set conn = New ADODB.Connection
Set rs = New ADODB.Recordset
' Connect to data source
conn.Open "Provider=Microsost.JET.OLEDB.4.0;Data Source=" & path & ";"
' The Query
query = "This is a big 'ol query that I won't repost here"
'Run the query and populate the Recordset object
rs.CursorLocation = adUseClient
rs.Open query, conn, adOpenStatic, adLockReadOnly
'Parse contetns of Recordset to worksheet
Application.ScreenUpdating = False
Me.SplitData(rs)
'Close the ADO Objects, set them to null, and exit sub
rs.Close
conn.Close
Set rs = Nothing
Set conn = Nothing
Exit Sub
End Sub
Try changing:
Me.SplitData(rs)
to:
Me.SplitData rs
Unnecessary parentheses often cause problems in VBA.
(NB I'm assuming that the two Sub shown are in a context where Me makes sense - e.g. class module, ThisWorkbook module, worksheet module, backing a UserForm etc)

Resources