Excel VBA User-Defined Function to query an Access Database - sql

I have an Access 365 database that has Invoice Numbers, Due Dates, and Amounts Due. I'm trying to create an Excel UDF, whereby I input the Due Date and Invoice Number, and the function queries the database and returns the Amount Due.
The formula result is #Value and there's no compiler error, though there appears to be an error when it attempts to open the record set (I set up a error message box for this action). Perhaps there's an issue with my SQL? I'd appreciate any assistance with this matter.
I've found several discussions of similar topic, but I've been unable to get this code to work. I'd appreciate any assistance with this matter.
https://www.mrexcel.com/board/threads/need-help-creating-user-defined-functions-in-excel-to-query-from-a-database.943894/
Here's the code:
Function CLLData(inpDate As Long, inpInvoiceNum As String)
Dim conn As Object
Dim rs As Object
Dim AccessFilePath As String
Dim SqlQuery As String
Dim sConnect As String
'Disable screen flickering.
Application.ScreenUpdating = False
'Specify the file path of the accdb file.
AccessFilePath = ThisWorkbook.Path & "\" & "CRDD.accdb"
'Create the connection string.
sConnect = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & AccessFilePath
On Error Resume Next
'Create the Connection object.
Set conn = CreateObject("ADODB.Connection")
'Check if the object was created.
If Err.Number <> 0 Then
MsgBox "Connection was not created!", vbCritical, "Connection Error"
'Exit Sub
End If
On Error GoTo 0
On Error Resume Next
'Open the connection.
conn.Open sConnect
'Check if the object was created.
If Err.Number <> 0 Then
MsgBox "Connection was not opened!", vbCritical, "Connection Open Error"
'Exit Sub
End If
On Error GoTo 0
'SQL statement to retrieve the data from the table.
SqlQuery = "SELECT [Value] FROM tblRawCallData WHERE (([DueDate] = '" & inpDate & "') AND ([Invoice] = '" & inpInvoiceNum & "'));"
On Error Resume Next
'Create the ADODB recordset object
Set rs = CreateObject("ADODB.Recordset")
'Check if the object was created.
If Err.Number <> 0 Then
Set rs = Nothing
Set conn = Nothing
MsgBox "Recordset was not created!", vbCritical, "Recordset Error"
'Exit Sub
End If
On Error GoTo 0
On Error Resume Next
'Open the recordset.
rs.Open SqlQuery, conn
'Check if the recordset was opened.
If Err.Number <> 0 Then
Set rs = Nothing
Set conn = Nothing
MsgBox "Recordset was not opened!", vbCritical, "Recordset open error"
'Exit Sub
End If
On Error GoTo 0
' Check there is data.
If Not rs.EOF Then
' Transfer result.
CLLData = rs!Value
MsgBox "Records: ", vbCritical, "Records"
' Close the recordset
Else
'Not found; return #N/A! error
CLLData = CVErr(xlErrNA)
MsgBox "No records in recordset!", vbCritical, "No Records"
End If
rs.Close
' Clean up
If CBool(conn.State And adStateOpen) Then conn.Close
Set conn = Nothing
Set rs = Nothing
'Enable the screen.
Application.ScreenUpdating = True
End Function

You need two or three corrections, as date values always should be handled as DateTime, and your invoice number most likely is numeric:
Function CLLData(inpDate As Date, inpInvoiceNum As String)
' <snip>
'SQL statement to retrieve the data from the table.
SqlQuery = "SELECT [Value] FROM tblRawCallData WHERE (([DueDate] = #" & Format(inpDate, "yyyy\/mm\/dd") & "#) AND ([Invoice] = " & inpInvoiceNum & "));"
Edit for numeric "date" and alpha-numeric invoice:
SqlQuery = "SELECT [Value] FROM tblRawCallData WHERE (([DueDate] = #" & Format(inpDate, "####\/##\/##") & "#) AND ([Invoice] = '" & inpInvoiceNum & "'));"

Seems like your function could be significantly less complex.
Comment out the error handler until you get it working when called from a Sub.
Function CLLData(inpDate As Long, inpInvoiceNum As String)
Dim conn As Object
Dim rs As Object
Dim AccessFilePath As String
Dim SqlQuery As String
Dim sConnect As String
AccessFilePath = ThisWorkbook.path & "\" & "CRDD.accdb"
sConnect = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & AccessFilePath
On Error GoTo haveError
Set conn = CreateObject("ADODB.Connection")
conn.Open sConnect
SqlQuery = "SELECT [Value] FROM tblRawCallData WHERE [DueDate] = " & inpDate & _
" AND [Invoice] = '" & inpInvoiceNum & "'"
Set rs = CreateObject("ADODB.Recordset")
rs.Open SqlQuery, conn
If Not rs.EOF Then
CLLData = rs.Fields("Value").Value
Else
CLLData = CVErr(xlErrNA)
End If
rs.Close
Exit Function
haveError:
CLLData = "Error:" & Err.Description
End Function

Related

Do sql request if there are no erros / Retrieve data

In my Excel VBA code, I open a connection with other workbook.
With CreateObject("ADODB.Connection")
.CommandTimeout = 500
.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" _
& path & ";" & "Extended Properties=""Excel 12.0;HDR=NO;Readonly=true"";"
.Open
I want to do this kind of line :
ThisWorkbook.Worksheets("Test").Range("H306:307").CopyFromRecordset .Execute("select * from [values$S8:S8]")
But, it is possible that the sheet "values" doesn't exist, it is why I want to do this line only if there are no erros or if "values" exist, but I don't know how do that.
If your idea is to check whether a worksheet exists, then do it. And forget about the SQL, it is non-relevant:
Public Function worksheetExists(wb As Workbook, sh As Worksheet) As Boolean
worksheetExists = IsError(wb.sh.Range("A1"))
End Function
And if you want to put the openning of the file in the function, then:
Public Function worksheetExists(path As String, sh As Worksheet) As Boolean
On Error GoTo worksheetExists_Error
Dim wb As Workbook
Set wb = Workbooks.Open(path)
worksheetExists = IsError(wb.sh.Range("A1"))
wb.Close False
On Error GoTo 0
Exit Function
worksheetExists_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") "
End Function
Another option is to use On Error Resume Next really carefully, because it would ignore any error. However, you can do it on one line and put On Error GoTo 0, which stops the action. At the end, before assigning values to the new worksheet, check whether rs is not Nothing:
Public Sub TestMe()
Dim path As String: path = "C:\Source.xlsx"
Dim rs As Object
With CreateObject("ADODB.Connection")
.CommandTimeout = 500
.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" _
& path & ";" & _
"Extended Properties=""Excel 12.0;HDR=NO;Readonly=true"";"
.Open
On Error Resume Next
Set rs = .Execute("SELECT * FROM [Sheet12$A1:B4]")
On Error GoTo 0
End With
If Not rs Is Nothing Then
With ThisWorkbook.Worksheets(1).Range("A1")
.CopyFromRecordset rs
End With
End If
End Sub

How to store the Query result into an Integer In Excel VBA

I have written a query inside the combobox1_change event
Private Sub ComboBox1_Change()
On Error GoTo UserForm_Initialize_Err
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim result As Integer
cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=C:\Users\inkapb\Desktop\EPC Database\EPC TOOL.mdb"
rst.Open "SELECT [Project_Id] FROM [Project Details] WHERE [Project Name] = '" & Me.ComboBox2.Value & "' ;", _
cnn, adOpenStatic
UserForm_Initialize_Exit:
On Error Resume Next
rst.Close
cnn.Close
Set rst = Nothing
Set cnn = Nothing
Exit Sub
UserForm_Initialize_Err:
MsgBox Err.Number & vbCrLf & Err.Description, vbCritical, "Error!"
Resume UserForm_Initialize_Exit
End Sub
The result of the above query is integer, could any one please tell me how to store the query result into result(int) variable.
You can read like so:
rst.Open ....
dim value as long
if not rst.eof then
value = rst.collect(0)
else
''no rows
end if

SQL query to extract employee details from access table

I am new to Excel VBA. I have a user form in which I am trying to populate names of those employees who are AMO. I have a database called Ofc. Under which I have a table EmployeeDetails. Primary key is PeoplesoftId.
Here is the structure and the contents of the Employee table:
PeoplesoftId Nameofemployee RacifId Employeeid Designation
43243309 Maddala V43309 99651823 AMO
43243310 Abhishek A43301 99651824 AMO
43243311 Atanu A43311 99651825 MO
43243312 Rajiv R43312 99651826 CSE
This is the code I've written so far:
Dim cnn As ADODB.Connection 'dim the ADO collection class
Dim rs As ADODB.Recordset 'dim the ADO recordset class
Dim dbPath As String
Dim SQL As String
Dim i As Integer
Dim var
'add error handling
On Error GoTo errHandler:
'Disable screen flickering.
Application.ScreenUpdating = False
dbPath = "E:\office_hsbc\ofc.accdb"
var = "AMO"
Set cnn = New ADODB.Connection ' Initialise the collection class variable
cnn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & dbPath
cnn.Open
SQL = "SELECT Nameofemployee FROM EmployeeDetails where Designation= '" & var & "'"
Set rs = New ADODB.Recordset 'assign memory to the recordset
rs.Open SQL, cnn
If rs.EOF And rs.BOF Then
rs.Close
cnn.Close
'clear memory
Set rs = Nothing
Set cnn = Nothing
'Enable the screen.
Application.ScreenUpdating = True
MsgBox "There are no records in the recordset!", vbCritical, "No Records"
Exit Sub
End If
For i = 0 To rs.Fields.Count - 1
comboamo.AddItem rs.Fields(i).Value, i
Next
rs.Close
cnn.Close
Set rs = Nothing
Set cnn = Nothing
MsgBox "Congratulation the data has been successfully Imported", vbInformation, "Import successful"
'error handler
On Error GoTo 0
Exit Sub
errHandler:
'clear memory
Set rs = Nothing
Set cnn = Nothing
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure Import_Data"
You need to move through each record in the recordset. Currently you are trying to read all of the fields from a single record but your query only returns one field. Try this instead:
MsgBox "There are no records in the recordset!", vbCritical, "No Records"
Exit Sub
End If
i = 0
Do Until rs.EOF
comboamo.AddItem rs.Fields("Nameofemployee").Value, i
rs.MoveNext
i = i + 1
Loop
rs.Close

How to pass the table name to sql query in VBA

I'm using the below code to load a table from an MDB database to an excel worksheet. I'm trying to define the table name as variable and pass it to query but I'm getting an error with the code below. How can I do this in VBA?
Public Sub ReadMdb()
Dim cn As Object, rs As Object
Dim intColIndex As Integer
Dim DBFullName As String
Dim TargetRange As Range
DBFullName = Application.GetOpenFilename()
On Error GoTo Oops
Application.ScreenUpdating = False
Set TargetRange = Sheets("Sheet1").Range("A1")
Set cn = CreateObject("ADODB.Connection")
cn.Open "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & DBFullName
Set rs = CreateObject("ADODB.Recordset")
Dim tableName As String
tableName = "Students"
rs.Open "SELECT * FROM tableName", cn, , , adCmdText
' Write the field names
For intColIndex = 0 To rs.Fields.Count - 1
TargetRange.Offset(1, intColIndex).Value = rs.Fields(intColIndex).Name
Next
' Write recordset
TargetRange.Offset(1, 0).CopyFromRecordset rs
LetsContinue:
Application.ScreenUpdating = True
On Error Resume Next
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
On Error GoTo 0
Exit Sub
Oops:
MsgBox "Error Description :" & Err.Description & vbCrLf & _
"Error at line :" & Erl & vbCrLf & _
"Error Number :" & Err.Number
Resume LetsContinue
End Sub
you can insert table name into SQL:
rs.Open "SELECT * FROM [" & tableName & "]", cn, , , adCmdText
Considering your returning all the rows and all the columns, you could use the command type adCmdTable then you don't need any SQL you simply name the table that you want.

ADODB connection to ACCDB file -- unrecognized database format error

I have a file like this:
strPath = "S:\HR\Forms\forms_database.accdb"
I am connecting to it through an WORD adodb.connection
should my database be a different extension ? MDB or something?
I am getting this error when it tries to connect:
unrecognized database format 's:...............accdb'
what's going on here?
here's the entire code:
Sub TransferShipper()
'Transfer new shipping company record to
'Shippers table in Northwind database.
Dim cnn As ADODB.Connection
Dim strConnection As String
Dim strSQL As String
Dim strPath As String
Dim doc As Word.Document
Dim strCompanyName As String
Dim strPhone As String
Dim bytContinue As Byte
Dim lngSuccess As Long
Set doc = ThisDocument
On Error GoTo ErrHandler
strCompanyName = Chr(39) & doc.FormFields("txtCompanyName").Result & Chr(39)
strPhone = Chr(39) & doc.FormFields("txtPhone").Result & Chr(39)
'Confirm new record.
bytContinue = MsgBox("Do you want to insert this record?", vbYesNo, "Add Record")
Debug.Print bytContinue
'Process input values.
If bytContinue = vbYes Then
strSQL = "INSERT INTO vacation " _
& "(title, department) " _
& "VALUES (" _
& strCompanyName & ", " _
& strPhone & ")"
Debug.Print strSQL
'Substitute path and connection string with DSN if available.
strPath = "S:\HR\Forms\forms_database.accdb"
strConnection = "Provider=Microsoft.Jet.OLEDB.4.0;" _
& "Data Source = " & strPath
Debug.Print strConnection
Set cnn = New ADODB.Connection
cnn.Open strConnection
cnn.Execute strSQL, lngSuccess
cnn.Close
MsgBox "You inserted " & lngSuccess & " record", _
vbOKOnly, "Error Added"
doc.FormFields("txtCompanyName").TextInput.Clear
doc.FormFields("txtPhone").TextInput.Clear
End If
Set doc = Nothing
Set cnn = Nothing
Exit Sub
ErrHandler:
MsgBox Err.Number & ": " & Err.Description, _
vbOKOnly, "Error"
On Error GoTo 0
On Error Resume Next
cnn.Close
Set doc = Nothing
Set cnn = Nothing
End Sub
Try ACE OLEDB 12.0 as the db version.
"Provider=Microsoft.ACE.OLEDB.12.0"