How to refresh/requery report in access VBA before auto-exporting it on database launch - email

I searched thoroughly and tried many different solutions, but I can't seem to get it to work, even though it shouldn't be that difficult.
I have an access database which automatically sends reports by e-mail, every monday morning, when the database is opened. The problem is I can't get the reports to show the most recent data in the charts. The procedure is as follows (with Report1 as example)
(Users open a .accdr version of the database)
Upon opening this code runs when the head form loads (form_load event):
If Weekday(Now(), 2) = 1 Then
If Forms![Head Form]![Once subform].Form![ID] = 0 Then
DoCmd.OpenQuery "UpdateOnce1", acViewNormal, acEdit
DoCmd.SetWarnings False
DoCmd.OpenReport "Report1", acViewPreview
DoCmd.RunSavedImportExport "Export-Report 1"
Dim strSql
Dim db As Database
Set db = CurrentDb()
Dim Outlook
Dim rng
Dim OutApp As Object
Dim OutMail As Object
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
On Error Resume Next
With OutMail
.To = "number of mail adresses"
.CC = ""
.BCC = ""
.Subject = "Report 1"
.HTMLBody = ""
.Attachments.Add ("T:\.....\Report1.pdf")
.Send
End With
DoCmd.Close acReport, "Report1"
End If
End If
So if it is monday, and the code hasn't run yet, Report 1 is openend, exported to PDF, added as an attachment and then mailed via outlook.
As you can see I currently tried opening the reports before calling the code to mail the pdf, in hopes of refreshing it before it exports. But it doesn't seem to be working unfortunately, because the report doesn't show the most recent data.
Any ideas on how I can refresh/requery the report before it is exported & mailed? Much appreciated.
Tim

One way around it is a make table with the most recent data you want when your criteria is met (monday, not been ran yet) and base the report off that, then once you have exported the report delete the temp table with your data. This also prevents users pissing around with your queries/set up etc.
a bit like
dim ssql as string
sSql = "Select yourFields from yourTable INTO tmpTblRpt"
currentdb.execute(ssql)
'set the rpt to be based off tmptblRpt here
then set warnings off docmd.deleteObject actable, "tmpTblRpt" then warnings back on

Related

Why is Access form giving me the error message "A column number has been specified more than once in the order list"? The related queries open fine

I'm working on an Access database with a SQL Server back end. Some times when I open a particular form, I get an Error 3146 "Column has been specified more than once in the order by list."
There are several possible queries that might feed into this form but I checked and ran them all individually and they run fine, so it's something in the form but I'm not sure. Below is a screen shot of the Data Properties window. My hypothesis is that "Order By" property (which I did not populate manually) is not being cleared out when the form closes, and thus when the form is re-opened, that in effect puts in the same columns twice.
I can temporarily solve the problem by opening up the form and clearing those Filter and Order By fields. That solves it for a while but intermittently it will happen again so there's probably one other thing I'm overlooking. I put in code in the Form close event to set the orderby="" but even that doesn't totally solve it.
Here is the code that opens the form from the main menu (frmProdSched is the form in question)
Private Function OpenProdSched(RunQuery, RunCaption)
DoCmd.OpenForm "frmProdSched", , RunQuery, "", , acNormal
Forms!frmProdSched.Caption = RunCaption
gScheduleRptQry = RunQuery
Me.Refresh
End Function
and then the code that is in the Form_Current event
Private Sub Form_Current()
On Error Resume Next
Dim strForm As String
Dim strForm1 As String
Dim strWhere As String
strForm = "frmSubmittalStatus"
strForm1 = "frmProdSched"
strWhere = "StatusJobno = " & Me.JOBNO & ""
If IsLoaded(strForm) Then
If Forms(strForm).Filter = strWhere Then
Forms(strForm1).SetFocus
Else
DoCmd.Close acForm, strForm
DoCmd.OpenForm FormName:=strForm, WhereCondition:=strWhere
Forms(strForm1).SetFocus
End If
End If
End Sub
I tried adding this code to the Form Close event and it seemed to work most of the time but it still intermittently happens
Private Sub Form_Close()
Me.Filter = ""
Me.OrderBy = ""
End Sub
I'm not sure what to check next. Any ideas?

How to retrieve a count of all records where a Date field is within the next year, and store it in a variable?

I am fairly new to MS Access, but have a decent understanding of databases, with some knowledge of SQL.
I am creating a database in Access. On a main form that users will see first, I need to display a count of all records from my Case table, which have a StatuteOfLimitation date that is within the next year.
My goal was to create a label describing the information, with a button below it. The button will open a report of all of the records (this part is working fine), and I wanted the caption for the button to display the total count of how many records meet the criteria.
The only way I can think to do it, is to retrieve the count and store it into a variable. From there, I should be able to set the caption to the variable value.
I have seen a few methods of retrieving a count and storing it in a variable, but all that I found only stored a count of EVERY record, without filtering for the date range.
This was the best that I could think of, but it is not working:
Private Sub Form_Load()
Dim oneYearFromToday As TempVars
SET TempVars!oneYearFromToday = (SELECT COUNT(StatuteOfLimitation) FROM Case
WHERE StatuteOfLimitation <= DateAdd("yyyy", 1, Date());
End Sub
DCount() provides a simple approach for "How to retrieve a count of all records where a Date field is within the next year"
Dim lngCount As Long
lngCount = DCount("*", "Case", "[StatuteOfLimitation] <= DateAdd('yyyy', 1, Date())")
Then you can use that count in your command button's Caption property. Say the button is named cmdOpenReport ...
Me!cmdOpenReport.Caption = "Report " & lngCount & " cases"
If you want the count in a TempVar instead of a regular Long variable, declare it As TempVar (just one) instead of As TempVars (a collection). And when you assign the value to it, don't use Set.
Dim oneYearFromToday As TempVar
TempVars!oneYearFromToday = DCount("*", "Case", "[StatuteOfLimitation] <= DateAdd('yyyy', 1, Date())")
I probably wouldn't use a tempvar to store your variable. you can try something like below using the DAO.
Private sub Form_Load()
dim rst as dao.recordset
dim strSQL as string
'Creates query string
strsql = "SELECT Count(StatueOfLimitation) as RecordCount " & _
"FROM Case " & _
"WHERE (((StatueOfLimitation) <= DateAdd('yyyy',1,date())));"
'Opens the query string into a recordset
set rst = currentdb.openrecordset(strsql)
'Change Labelnamehere isnto the name of the label control on your form
'Change what ever saying you want here to something you want the label to display
me.labelnamehere.caption = "What ever saying you want here " & rst![RecordCount] 'Don't need a variable storage is you can use the result here
rst.close 'closes recordset
set rst = nothing 'Clears memory
EndCode: 'Ensures clean up is successful
If not rst is nothing then
rst.close
set rst = nothing
end if
end sub
If this doesn't work for you, please let me know and I'll do some more digging.
I'm not able to comment on HansUp's answer, but to change a label caption in VBA you need to open the form in Design view. It's not something I typically do, my personal preference is to use an unbound text box with labels that don't change, but I have done it in one database to update the time/date and user for the last email sent.
The code would look like this:
DoCmd.OpenForm "yourformname", acDesign, , , , acHidden
Forms![yourformname]![yourlabelname].Caption = "There are " & TempVars!onYearFromToday & " cases to view."
DoCmd.Close acForm, "yourformname", acSaveYes
DoCmd.OpenForm "yourformname", acNormal
It's a bad idea to use a button for info display. That's not the purpose of a button.
Use a textbox and set its ControlSource:
=DCount("*","[Case]","[StatuteOfLimitation]<=DateAdd("yyyy",1,Date()))
It will fill by itself, and the button is free to open the report at any time.

Create Access reports from Form and save as PDF

Im currently using an Access database to create alot of reports - the report is made using a Query as a source, in the Query i use a Form as criteria so that the open page in the Form is the data used in the report.
Then I save the report as a PDF and click in the form to run the next set of data.
That is very time consuming when i have over 500 reports to make. So is there a way to make a function, a VBA or macro to run through all pages in the form and save each report as a PDF?
My form is named NorwF, the query is NorwQ and the report is NorwRap
I hope that makes sense and that there is a faster way to make this projekt run smoothly.
If you place a button on the form, this code behind should work:
Dim rst As DAO.Recordset
Dim strReport As String
Dim strReportFile As String
strReport = "NorwRap"
'Set rst = Me.RecordsetClone
Set rst = CurrentDB.OpenRecordSet("NorwQ") 'use the query
Do While rst.EOF = False
strReportFile = rst!ID & ".pdf" ' give report name based on field name
DoCmd.OpenReport strReport,acViewPreview , , "id = " & rst!ID
DoCmd.OutputTo acOutputReport, strReport, acFormatPDF, strOutFile
DoCmd.Close acReport, strReport
rst.MoveNext
Loop

How to schedule auto-exporting MS Access query to Excel and email it?

I know Access can setup an Outlook Task to auto-export query to Excel, but it requires the Outlook to be always open on the user's computer.
Is there an easy way to setup a schedule that can automatically export a query to Excel and this schedule will then auto-email the exported Excel file to an email address every Monday at 5AM for example?
If this can only be done in VBA, any reference I may start with?
Thanks.
I do not think you can do this with Access. You can use a tool like these:
http://www.r-tag.com
http://www.hybing.com/Report-Genie.html
They are able to get data from a database, export it to excel and email it. Report genie is cheap although it is pretty old software and I don't know if it has any support. I don't think there is a way to schedule tasks too. R-Tag has paid and free version. Both versions will allow you to schedule a task to export data from any database to excel and email the file. There are some restrictions for the free version.
I don't know how to schedule it, but this may give you a good start:
If Weekday(Now(), 2) = 1 Then
If Forms![Head Form]![Once subform].Form![ID] = 0 Then
DoCmd.OpenQuery "UpdateOnce1", acViewNormal, acEdit
DoCmd.SetWarnings False
DoCmd.OpenReport "Report1", acViewPreview
DoCmd.RunSavedImportExport "Export-Report 1"
Dim strSql
Dim db As Database
Set db = CurrentDb()
Dim Outlook
Dim rng
Dim OutApp As Object
Dim OutMail As Object
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
On Error Resume Next
With OutMail
.To = "number of mail adresses"
.CC = ""
.BCC = ""
.Subject = "Report 1"
.HTMLBody = ""
.Attachments.Add ("T:\.....\Report1.pdf")
.Send
End With
DoCmd.Close acReport, "Report1"
End If
End If
So if it is monday, and the code hasn't run yet (it checks if the ID equals 0), Report 1 is openend, exported to PDF, added as an attachment and then mailed via outlook.

When viewing a report inside an application, the parameter prompt redisplays when moving to the next page

I'm pretty much a novice with crystal reports. We have another team making our reports, and I'm integrating it with the application. The problem is with paging and user defined parameters. Essentially, the document.table. setdatasource points at our query result set (set in code). The report, upon opening, will then prompt the user for the parameter, which will further reduce the displayed result to the user as the prompt parameter is part of the record selection formula.
AND
{#Age} >= 20 and
{#Age} < 30 and
{Report;1.Sector} = {?NewSector})
This will return a table of more than one page in length. However, requesting the next page will result in the user being prompted for the Sector again, and once provided, will take the user back to page 1 of the results again.
If I take out the reference to the parameter, then obviously the paging works fine.
Is there away to just take the parameter once from the user, and then reuse this value in the subsequent paging requests?
Appreciate your help...
Stupid me. I had the report refreshing every postback.
EDit
A bit more elaboration:
I have the report being created in a RefreshReports procedure, which sets up the report as follows:
Dim objConnectionInfo As CrystalDecisions.Shared.ConnectionInfo
Dim crConnectionInfo As CrystalDecisions.Shared.ConnectionInfo
Dim myconnection As New SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings(ApplicationConstants.MyDB).ConnectionString)
Dim myConnBuilder As New SqlConnectionStringBuilder(myconnection.ConnectionString)
'// Log on credentials from web.config
objConnectionInfo = New CrystalDecisions.Shared.ConnectionInfo
objConnectionInfo.IntegratedSecurity = False
objConnectionInfo.ServerName = myconnection.DataSource
objConnectionInfo.UserID = myConnBuilder.UserID
objConnectionInfo.Password = myConnBuilder.Password
crConnectionInfo = objConnectionInfo
'// Get the report details needed
rep = Request.QueryString("Report")
crDoc.Load(Server.MapPath(rep))
crDoc.SetDatabaseLogon(myConnBuilder.UserID, myConnBuilder.Password)
Dim crDatabase As CrystalDecisions.CrystalReports.Engine.Database
Dim crTables As CrystalDecisions.CrystalReports.Engine.Tables
Dim aTable As CrystalDecisions.CrystalReports.Engine.Table
crDatabase = crDoc.Database
crTables = crDatabase.Tables
There is then a series of else ifs like the following:
ElseIf rep = "ExampleRep.rpt" Then
For Each aTable In crTables
If aTable.Name = "GetSectorRep;1" Then
Dim NewSector As String = ""
NewSector = Session("NewSector").ToString()
aTable.SetDataSource(DAL.GetSectorRepTable(NewSector))
End If
Next
In my Page_Init I grab the query strings I need and call RefreshReports. The problem I was having was that I was also requesting RefreshReports in a If Postback on page_load, which meant that every time the report posted back (eg. new page) it was requesting the parameter again, as the report was being created afresh.
So, silly me - quite an obvious mistake in the end!