I'm new to VBA and am writing a macro that downloads data from Access based on a month-end date entered by the user.
Currently, I am having issues getting information to download from Access.
To be more specific: when I run the macro and enter in the month-end date, no data is downloaded but I also receive no error messages.
I have been trying different code iterations to try to get it to work. Before I was getting various error messages; now I get no error messages but no data downloads.
I was reading online that I need to use a function to get my variable from the input box (box) to work in the Access query. I am wondering if it has to do with how I have my function set up. Or is there an issue with my Access query.
Sub Expense_Download()
'
' Expense_Download Macro
'
Dim cnn As ADODB.Connection, rs As ADODB.Recordset, sQRY As String, strFilePath As String, box As Variant, myvar As Variant
strFilePath = "C:\Users\NVanWyk\Documents\Fidato\Lunch And Learn\Lunch and Learn Access DB\Nate's Expenses DB.accdb" 'Replace the ‘DatabaseFolder’ and ‘myDB.accdb’ with your DB path and DB name
Set cnn = New ADODB.Connection
Set rs = New ADODB.Recordset
box = InputBox("What month do you want expense data for? Please use the MM/DD/YYYY format.", "Expense Month?")
If Not IsDate(box) Then MsgBox "Value entered is not a valid date, please try again.", , "Input Value is Not Correct"
End
myvar = box
cnn.Open "provider = microsoft.ace.oledb.12.0;" & _
"Data Source=" & strFilePath & ";"
'have to indent the data source or the code does not run
sQRY = "SELECT * FROM Expenses Where Expenses.Expense_Month=myvar()" 'Replace ‘tblData’ with your Access DB Table name or Query name from which you want to download the data"
rs.CursorLocation = adUseClient
rs.Open myvar(), sQRY, cnn, adOpenStatic, adLockReadOnly
Application.ScreenUpdating = False
Sheet1.Range("A2").CopyFromRecordset rs
'sheet 1 for whatever reason still pastes to the "expense" sheet
rs.Close
Set rs = Nothing
cnn.Close
Set cnn = Nothing
Exit Sub
End Sub
First of all, the line that contains the word 'End' only, will stop execution.
If you want to stop execution in case of wrong user input, do this:
If Not IsDate(box) Then
MsgBox "Value entered is not a valid date, please try again.", , "Input Value is Not Correct"
End 'or Exit Sub
End If
You store the user's month input in myvar variable but then you don't actually put into the select query.
Instead of this:
sQRY = "SELECT * FROM Expenses Where Expenses.Expense_Month=myvar()"
Try this:
sQRY = "SELECT * FROM Expenses Where Expenses.Expense_Month= " & myvar
However, the value you are expecting in InputBox is not obvious. I'm assuming that it's a number between 1 and 12 and Expense_Month field is a number too in your database.
In case it contains the year too in YYYY-MM format and is a varchar, you will need to change your code like this:
sQRY = "SELECT * FROM Expenses Where Expenses.Expense_Month= '" & myvar & "'"
Either of the above is true, IsDate is not the right function to check whether the input is correct. For example if the user types 20 into the box, it will return True as it is a date but January 20 of 1900.
Also, remove the first parameter myvar() from this line.
rs.Open myvar(), sQRY, cnn, adOpenStatic, adLockReadOnly
rs.Open sQRY, cnn, adOpenStatic, adLockReadOnly
Based on your additional input I recommend using YYYY-MM-DD as user input. So your query would be defined as:
sQRY = "SELECT * FROM Expenses Where Expenses.Expense_Month= '" & myvar & "'"
To test your query, open Locals windows in VB editor, see what the value of sQRY is once execution reaches this point and run that in Access's SQL editor to see if it is going to work.
Thanks for the help everyone!
I made the edits above and did some other research and was able to get the code to work. I think the snag was because I was using a date (MM/DD/YYYY) as the variable, I needed to add the # signs in the query so that Access recognized the variable as a date.
Sub Expense_Download()
'
' Expense_Download Macro
'
Dim cnn As ADODB.Connection, rs As ADODB.Recordset, sQRY As String, strFilePath As String, box As Variant, myvar As Variant
strFilePath = "C:\Users\NVanWyk\Documents\Fidato\Lunch And Learn\Lunch and Learn Access DB\Nate's Expenses DB.accdb" 'Replace the ‘DatabaseFolder’ and ‘myDB.accdb’ with your DB path and DB name
Set cnn = New ADODB.Connection
Set rs = New ADODB.Recordset
box = InputBox("What month do you want expense data for? Please use the MM/DD/YYYY format.", "Expense Month?")
If Not IsDate(box) Then
MsgBox "Value entered is not a valid date, please try again.", , "Input Value is Not Correct"
End
End If
myvar = box
cnn.Open "provider = microsoft.ace.oledb.12.0;" & _
"Data Source=" & strFilePath & ";"
'have to indent the data source or the code does not run
sQRY = "SELECT * FROM Expenses Where Expenses.Expense_Month= #" & myvar & "#" 'Replace ‘tblData’ with your Access DB Table name or Query name from which you want to download the data"
' access query
' # before and after the "myvar" variable are necessary for access to recognize the variable as a date and to run the query successfully.
rs.CursorLocation = adUseClient
rs.Open sQRY, cnn, adOpenStatic, adLockReadOnly
Application.ScreenUpdating = False
Sheet1.Range("A2").CopyFromRecordset rs
'sheet 1 for whatever reason still pastes to the "expense" sheet
rs.Close
Set rs = Nothing
cnn.Close
Set cnn = Nothing
Exit Sub
End Sub
Related
I have a userform in Excel I intend to use as a search form and has a listbox to display the result.
The form will search for an Account number from a table in my Access database.
Aside from a Search field (TextBox), it has a search button (CommandButton) and a Listbox.
My goals:
Connect to my Access database from Excel
Validate the search field.
If the field is empty, display message to enter an account number.
If the entry is not among those found in the table, return a message that the Account Number does not exist.
If account number in the table, display the results in the Listbox.
I am trying to create an Excel Worksheet to place the results of my query.
AcctNo is one of the headers from my MemberAccts Table in Access.
acctNoField is the name of the search field in my search form.
The error is
"No value given for one or more parameters".
When debugging, rst.Open qry, cnn, adOpenKeyset, adLockOptimistic is highlighted.
Which parameter am I am?
Private Sub acctSearchBtn_Click()
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("AcctInfo")
sh.Cells.ClearContents
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim qry As String,
Dim AcctNo As String
If Me.acctNoField.Value = "" Then
MsgBox "Please enter an Account Number", vbCritical
Exit Sub
ElseIf Me.acctNoField.Value <> qry Then
cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=E:\MasterDb.accdb"
qry = "SELECT * FROM MembrAccts WHERE Me.acctNoField.Value= '" & AcctNo & "'"
rst.Open qry, cnn, adOpenKeyset, adLockOptimistic
MsgBox "The Account Number does not exists", vbCritical
Exit Sub
Else
MsgBox "Place Retrieve_account function here", vbCritical
End If
rst.Close
cnn.Close
End Sub
You have Me.acctNoField.Value and AcctNo in each other's position in the qry code. Don't need to declare AcctNo variable. Comparing acctNoField.Value to qry variable makes no sense. Missing a test for empty recordset.
Consider:
If Me.acctNoField.Value = "" Then
MsgBox "Please enter an Account Number", vbCritical
Else
cnn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=E:\MasterDb.accdb"
qry = "SELECT * FROM MembrAccts WHERE AcctNo = '" & Me.acctNoField.Value & "'"
rst.Open qry, cnn, adOpenKeyset, adLockOptimistic
If rst.EOF And rst.BOF Then
MsgBox "The Account Number does not exist", vbCritical
Else
'code here to read data from recordset, perhaps use CopyFromRecordset
sh.Range("A1").CopyFromRecordset rst
End If
rst.Close
cnn.Close
End If
I have created a userform that insert data into an Access table. while inserting data, I want to make sure that the ID inserted must exist in the Access table. I have used the DCOUNT function to do this but this is rendering a 'Type Mismatch' error. I have tried every solution found on the internet but nothing is working here. Please help!
I have modified the DCOUNT expression to put the form variable name into '', [], creating an external variable that refers to the DCOUNT function but nothing is working
Set conn = createobject("ADODB.connection")
set rs = createobject("ADODB.recordset")
strconn = "Provider=Microsoft.ACE.OLEDB.12.0;" & "Data source = C:\MyPathMyDB.accdb"
qry = "select * from employee"
with rs
.adnew
if isnumeric(ManagerID) = false then
msgbox "Invalid Manager ID"
exit sub
elseif application.worksheetfunction.dcount("Employee_ID","Employee","activ='Yes' and Employee_ID='" & [EmployeeForm.ManagerID] & "'") = 0 then
msgbox "Manager does not exist"
exit sub
else
. fields("Manager_ID").value = ManagerID
end if
end with
I expect the function to determine if the Employeeform.ManagerID exist in Employee_ID. If yes, then proceed, else display error message
Since you check for the ManagerID to be numeric, I guess its value isn't text, and active is probably a boolean, and as you can access ManagerID on its own, use it as is, and the criteria could read:
"activ=True and Employee_ID=" & ManagerID & ""
Dcount (the one you're trying to use) is an Access function: the Excel one is for querying a worksheet range. you will need to query your access database to see if there's a record:
For example:
sql = "select * from employee where activ='Yes' and Employee_ID='" & _
[EmployeeForm.ManagerID] & "'"
rs.open sql, conn
If not rs.eof then
'got a match: add the new record and update to database
else
msgbox "Manager not found!"
end if
Just to give you background of my work, i have to fetch data from MS Sql on daily basis and for that every time have to go to other server to run the query. Once the query is executed, have to paste into my common drive, which takes a lot time. ~55 mins to paste 5,00,000 row & 30 fields to common or to move file. In total 2 hours for execution & movement from one location to other.
To reduce this i would need your help to use the SQL queries through excel with the below things:
If possible,
Point1: Query will be stored in the text file in the common location
Point2: Query Parameter to be populate to get
Or
Point2:Range to be defined for parameter
If not possible above,
Query will be pasted into the code and parameter to be populated based on the above mentioned suggestion.
Connection type is windows authentication, it will work based on logged in users windows name.
This code will allow you to provide variables that you use within your SQL statement and put those into cells on a spreadsheet (In this case Cred2) and return the results on a separate sheet (Sheet2).
The first portion of the code establishes a connection with the SQL server.
The column Headers will be started in Row 2 and then the data will begin populating starting on row 3. I have used this to pull well over 100,000 records at a time and this works very quickly.
Private Sub CommandButton1_Click()
Dim cn As Object
Dim rs As Object
Dim strCon As String
Dim strSQL As String
strCon = "DRIVER=SQL Server;SERVER=ServerName;DATABASE=DBName;Trusted_Connection=True"
Set cn = CreateObject("ADODB.Connection")
cn.Open strCon
' if not a trusted connection you could replace top line of strCon with
strCon = "DRIVER=SQL Server; Server=myServerAddress;Database=myDataBase;User Id=myUsername; Password=myPassword"
' set up where you are getting your variables to include in the SQL statement
stat = Sheets("Cred2").Range("c7").Value
barg = Sheets("Cred2").Range("c10").Value
worksite = Sheets("Cred2").Range("c11").Value
' Construct SQL statement
strSQL = "select * " _
& " FROM tableName A , table2 B " _
& "WHERE A.[field1] = B.[field1] " _
& " and field1 like '" & stat & "'" _
& "and field2 like '" & barg & "'" _
& "and field3 like '" & worksite & "'" _
& " order by Field? "
' Build Record Set
Set rs = CreateObject("ADODB.RECORDSET")
rs.ActiveConnection = cn
rs.Open strSQL
' Display Data
For intColIndex = 0 To rs.Fields.Count - 1
Sheet2.Range("A2").Offset(0, intColIndex).Value = rs.Fields(intColIndex).name
Next
Sheet2.Range("A3").CopyFromRecordset rs
' Close Database
rs.Close
cn.Close
Set cn = Nothing
end sub
I am having trouble getting data from an Access Database. I found this code online, and it seems to work (to an extent), but for some reason it will only pull the column headers, and none of the data from the query. I am not too familiar with Access, that is why I pulled one from offline.
Someone had a similar post a while back, where the code they used was the same, and our queries were exactly the same, but we had different issues.
Importing Data From Access Using Excel VBA
Would anyone happen to know why the data won't pull?
Sub getDataFromAccess()
Dim DBFullName As String
Dim Connect As String, Source As String
Dim Connection As ADODB.Connection
Dim Recordset As ADODB.Recordset
Dim Col As Integer
Dim startdt As String
Dim stopdt As String
Dim refresh
refresh = MsgBox("Start New Query?", vbYesNo)
If refresh = vbYes Then
Sheet1.Cells.Clear
startdt = Application.InputBox("Please Input Start Date for Query (MM/DD/YYYY): ", "Start Date")
stopdt = Application.InputBox("Please Input Stop Date for Query (MM/DD/YYYY): ", "Stop Date")
DBFullName = "X:\MyDocuments\CMS\CMS Database.mdb"
' Open the connection
Set Connection = New ADODB.Connection
Connect = "Provider=Microsoft.ACE.OLEDB.12.0;"
Connect = Connect & "Data Source=" & DBFullName & ";"
Connection.Open ConnectionString:=Connect
Set Recordset = New ADODB.Recordset
With Recordset
Source = "SELECT * FROM Tracking WHERE [Date_Logged] BETWEEN " & startdt & " AND " & stopdt & " ORDER BY [Date_Logged]"
.Open Source:=Source, ActiveConnection:=Connection
For Col = 0 To Recordset.Fields.Count - 1
Range(“A1”).Offset(0, Col).Value = Recordset.Fields(Col).Name
Next
Range(“A1”).Offset(1, 0).CopyFromRecordset Recordset
End With
ActiveSheet.Columns.AutoFit
Set Recordset = Nothing
Connection.Close
Set Connection = Nothing
End Sub
An easy way to get data in Excel, especially from Access, is to use the menu "Data > Access". This creates a connection to a table, that you can freely edit.
At the very least, that is a convenient way to limit your investigations to:
the query you typed (the connection string will always be OK, so if you're getting no values, it comes from the query)
or the VBA itself (if the table is returning values but not the corresponding VBA Sub, then you know it comes from the VBA itself, not the SQL).
I'm skipping the creation of connection becuse it's really straightforward; it's better to focus on what you can do once the table has been created.
Edit the connection
When you select the table and go to menu "Data > Properties", then in the window you click on the top right button "Connection properties", you get to the definition of the connection, i.e. some properties in the first tab and the actual definition in the second tab.
If you move the .mdb file, you'll have to change the connection string accordingly. There should be no other events forcing you to alter it.
If you want to type an actual complex query, you'll need to:
Change the command type from "Table" to "SQL"
Type the query in the bottom edit box.
Note if you want to define dynamic parameters in the WHERE clause, you can put question marks (?) instead of hardcoded values. Question marks can be linked to either constants (with a prompt to change their values) or cell.
Use in VBA
Once you checked with the connection that everything works, you have 2 solutions to put that in VBA.
Either use exactly the code you have above; in that case, you can make things easy by simply copying the connection string and the query.
Alternatively and this is what I would recommend, the table we have built previously can be updated very easily in VBA.
Use this piece of code:
WorksheetWithTable.ListObjects(1).QueryTable.Refresh
You really don't need more than this 1 line of code to do the refresh.
If you set your query to automatically refresh when a cell's value is being modified, then you do not even need it at all.
Note #1: Instead of an index in .ListObjects(1), you can use the table name.
Node #2: Refresh has an optional parameters to drive if the query is to be refresh in the background. True means the VBA code will not wait for the execution to end before moving to the next instruction. False, obviously, is the opposite.
The posted code is missing End If line. Perhaps this is just a posting typo because code should not compile and run.
The query SQL needs # delimiters for the date parameters:
Source = "SELECT * FROM Tracking WHERE [Date_Logged] BETWEEN #" & startdt & "# AND #" & stopdt & "# ORDER BY [Date_Logged]"
Text field would need apostrophe delimiters. Number field does not need delimiters.
I solved the answer to my own question after hours, i found a different set of code that worked fine. Thank you all for your help!
Sub getdatamdb()
Dim cn As Object, rs As Object
Dim intColIndex As Integer
Dim DBFullName As String
Dim TargetRange As Range
10 DBFullName = "X:\MyDocuments\CMS\CMS Database.mdb"
20 On Error GoTo Whoa
30 Application.ScreenUpdating = False
40 Set TargetRange = Sheets("Sheet1").Range("A1")
50 Set cn = CreateObject("ADODB.Connection")
60 cn.Open "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & DBFullName & ";"
70 Set rs = CreateObject("ADODB.Recordset")
80 rs.Open "SELECT * FROM Tracking WHERE [Date_Logged] BETWEEN #" & startdt & "# AND #" & stopdt & "# ORDER BY [Date_Logged]", cn, , , adCmdText
' Write the field names
90 For intColIndex = 0 To rs.Fields.Count - 1
100 TargetRange.Offset(1, intColIndex).Value = rs.Fields(intColIndex).Name
110 Next
' Write recordset
120 TargetRange.Offset(1, 0).CopyFromRecordset rs
LetsContinue:
130 Application.ScreenUpdating = True
140 On Error Resume Next
150 rs.Close
160 Set rs = Nothing
170 cn.Close
180 Set cn = Nothing
190 On Error GoTo 0
200 Exit Sub
Whoa:
210 MsgBox "Error Description :" & Err.Description & vbCrLf & _
"Error at line :" & Erl & vbCrLf & _
"Error Number :" & Err.Number
220 Resume LetsContinue
End If
End Sub
I'm trying to pull data from an Excel sheet using an ADO query. However, date values are being returned the way they're formatted on the worksheet, rather than the actual date value. For example, the value 8/12/1929 is formatted as 8/12/29, so the query is returning the string "8/12/29". This makes it hard to determine what the correct date is based on the recordset data alone, as the year could also be 2029 in this case.
Here's the code for the ADO query:
Function WorksheetRecordset(workbookPath As String, sheetName As String) As ADODB.Recordset
Dim objconnection As New ADODB.Connection
Dim objrecordset As New ADODB.Recordset
'On Error GoTo errHandler
Const adOpenStatic = 3
Const adLockOptimistic = 3
Const adCmdText = &H1
objconnection.CommandTimeout = 99999999
objconnection.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & workbookPath & ";" & _
"Extended Properties=""Excel 12.0 Xml;HDR=YES;IMEX=1"";"
objrecordset.Open "Select * FROM [" & sheetName & "$]", _
objconnection, adOpenStatic, adLockOptimistic, adCmdText
If objrecordset.EOF Then
Set WorksheetRecordset = Nothing
Exit Function
End If
Set WorksheetRecordset = objrecordset
On Error GoTo 0
Exit Function
errHandler:
Set WorksheetRecordset = Nothing
On Error GoTo 0
End Function
I'm fetching the value by using, e.g.
Sub getValue(rs as ADODB.Recordset)
Debug.Print rs.Fields(0).Value
End Sub
Part of the problem might be that the date values don't start until after several rows of text, so maybe when ADO detects the field type as text it only fetches the visible formatted value. Is there a way to retrieve the actual date value?
EDIT: Just realized that this is similar to this SO question that I previously asked: ADO is truncating Excel data. But I didn't get a satisfactory answer from that one, so I'll ask this one anyways.
Since you have 58 fields I think that the best thing is to build a string running the following code on the workbook that contains the data:
Dim rng as Range
Dim val as Variant, txt as String
Set rng = Worksheets("sheetName").Range("A3:BF3")
For Each val In rng.Value
txt = txt & "[" & val & "], "
Next val
Debug.Print txt
Then you copy the text from the Immediate window and paste in your code, like this:
Dim strFields as String, strSQL as String
strFields = 'Paste the text here
'Note the FROM clause modification
strSQL = "SELECT CDATE([myDate]), " & strFields & " FROM [" & sheetName & "$A3:BF]"
'...
objrecordset.Open strSQL, _
objconnection, adOpenStatic, adLockOptimistic, adCmdText
Note that the FROM clause has the form [sheet$A3:BF]. This specify the third row as the first row that contains data. More details in this question or in this link