Access report not updating after query change - sql

I have a form, below, that allows the user to filter the database multiple ways. When they push the filter button on the form a report populates based on the filter query. The issue is if I filter the database again, even with .requery in the report code, the report doesn't update to the new Query results. I know if I manually close out of the report it works, however when I code it to DoCmd.Close it doesn't actually close the report. If I show it in
acViewPreview it updates each time I use the refilter button on the form but then I cant use buttons on the report. I am trying to make it like a kiosk so I don't want the nav tabs to show.
Filter form
Report
Form Code:
Private Sub btnFilter_Click()
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim SQL2 As String
Dim ToDate As Date
Dim FromDate As Date
SQL2 = ""
Set db = CurrentDb()
Set qdf = db.QueryDefs("Filter")
If cmbFilter.Value = "Vended Date" Then
ToDate = Format(DTPickerTo.Value, "YYYY-MM-DD")
FromDate = Format(DTPickerFrom.Value, "YYYY-MM-DD")
SQL2 = "SELECT CribMaster_Quality.Line,CribMaster_Quality.[Vended Date],CribMaster_Quality.PartNumber,CribMaster_Quality.Group,CribMaster_Quality.ItemNumber,CribMaster_Quality.Amount,CribMaster_Quality.Description,CribMaster_Quality.Cost,CribMaster_Quality.[Extended Cost],CribMaster_Quality.User " & _
" FROM CribMaster_Quality" & _
" WHERE CribMaster_Quality.[Vended Date]" & _
" BETWEEN #" & FromDate & "# AND #" & ToDate & "#" & _
" ORDER BY CribMaster_Quality.[Vended Date] DESC;"
ElseIf ckbDateConst = True Then
ToDate = Format(DTPickerTo.Value, "YYYY-MM-DD")
FromDate = Format(DTPickerFrom.Value, "YYYY-MM-DD")
SQL2 = "SELECT CribMaster_Quality.Line,CribMaster_Quality.[Vended Date],CribMaster_Quality.PartNumber,CribMaster_Quality.Group,CribMaster_Quality.ItemNumber,CribMaster_Quality.Amount,CribMaster_Quality.Description,CribMaster_Quality.Cost,CribMaster_Quality.[Extended Cost],CribMaster_Quality.User " & _
" FROM CribMaster_Quality" & _
" WHERE CribMaster_Quality." & Me!cmbFilter.Value & " = '" & Me!cmbFilterBy.Value & "' And CribMaster_Quality.[Vended Date] " & _
" BETWEEN #" & FromDate & "# AND #" & ToDate & "#" & _
" ORDER BY " & Me.cmbFilter.Value & " DESC;"
Else
SQL2 = "SELECT CribMaster_Quality.Line,CribMaster_Quality.[Vended Date],CribMaster_Quality.PartNumber,CribMaster_Quality.Group,CribMaster_Quality.ItemNumber,CribMaster_Quality.Amount,CribMaster_Quality.Description,CribMaster_Quality.Cost,CribMaster_Quality.[Extended Cost],CribMaster_Quality.User " & _
" FROM CribMaster_Quality" & _
" WHERE CribMaster_Quality." & Me!cmbFilter.Value & " = '" & Me!cmbFilterBy.Value & "'" & _
" ORDER BY " & Me.cmbFilter.Value & " DESC;"
End If
qdf.SQL = SQL2
Set db = Nothing
Set qdf = Nothing
DoCmd.OpenReport "CribMasterReport", acViewReport
End Sub
Report Code:
Private Sub btnReFilter_Click()
DoCmd.Close , acSaveNo
DoCmd.OpenForm "Filter Database Form"
End Sub
Private Sub Report_Load()
Me.Requery
With VendedDatetxt
.Requery
End With
With ItemNumbertxt
.Requery
End With
With Linetxt
.Requery
End With
With PartNumbertxt
.Requery
End With
With Usertxt
.Requery
End With
With Amounttxt
.Requery
End With
With Costtxt
.Requery
End With
With ExtendedCosttxt
.Requery
End With
End Sub

Issue 1: Requerying the Report
When a report is opened using standard techniques, such as clicking on a report in the Navigation pane or when opening a report using DoCmd.OpenReport, Access creates a default instance of the Report that is accessible via the Application.Reports collection. Before the report is first opened or if the default report instance is completely closed (i.e. removed from memory), the Application.Reports collection will not contain an instance of the report. Before accessing the default instance, ensure that the report is already open.
Like other MS Office object-model collections, Application.Reports does not have a "Contains" method or other direct way to test whether a report is already open, only by looping through numeric indexes and testing each report object. Although it seems sloppy to me, the easiest method is to use error handling to try getting the report directly, then catching the error if it's not found:
On Error Resume Next
Set frm = Application.Reports("CribMasterReport")
If err.Number <> 0 Then
'Default instance not open
End If
CAUTION: Do not refer to the report using the class name like an object, as in Report_CribMasterReport.Requery. If you do that, VBA will automatically create a new, hidden instance of the report, but it is NOT the same default instance as described above and this new instance will not be accessible via the Application.Reports collection. Likewise, using the properties and calling methods on such an object will be largely ineffective. (It is possible to create and use such independent instances, but that is an advance technique riddled with its own pitfalls and challenges.)
As the question describes, which is also confirmed by other online sources, the Report.Requery is not effective in refreshing the report after the underlying query or data have changed. However, resetting the Report.RecordSource forces a full refresh of the report when in normal Report View.
Issue 2: Report not closing
The DoCmd.Close command was missing a comma. It should be DoCmd.Close , , acSaveNo. Even better is to always use explicit names for optional parameters. Typing an extra parameter is definitely worth the saved frustration and time with typos in an ambiguous list of commas:
DoCmd.Close Save:=acSaveNo
Issue 3: Unnecessary calls
It is completely unnecessary to call Requery on the report and every single control in the Report_Load event. I get that you were trying to debug the situation, but this behavior should happen automatically. Also, the Form_Load event occurs only once when the form is first loaded, so that code would not be called again unless the report is completely closed and reopened.
Finally some alternative code
Private Sub btnFilter_Click()
'... Include previous code to reset report query
'* Call DoCmd.OpenReport every time to
'* 1) Ensure default report is open
'* 2) Automatically activate the report (even if it was already open)
DoCmd.OpenReport "CribMasterReport", acViewReport
On Error Resume Next
Dim frm As Report_CribMasterReport
Set frm = Application.Reports("CribMasterReport")
If Err.Number = 0 Then
'* Force the Report object to re-run query and recreate report
frm.RecordSource = frm.RecordSource
End If
End Sub
It is no longer be necessary to completely close the report.
Private Sub btnReFilter_Click()
''DoCmd.Close Save:=acSaveNo
DoCmd.OpenForm "Filter Database Form"
End Sub
Private Sub Report_Load()
'* Eliminated unnecessary Requery calls
End Sub

Related

MSAccess Form Search-Button conflicts with Edit-Button

I'm new to this forum and quite new to Access. I have the following problem. I've created an Form/Subform to edit the Data of a Query. Two Controls seem to be in conflict in my code.
"Search_Order" is an unbound text field. If text is entered and enter is pressed the corresponding fields of a query are shown. The code looks like the following:
Set rs_Search = Me.RecordsetClone
rs_Search.FindFirst "[OrderNumber]=""" & Search_Order & """"
If rs_Search.NoMatch Then
MsgBox "Sorry, no such record '" & Search_Order & "' was found.", _
vbOKOnly + vbInformation
Else
Me.Recordset.Bookmark = rs_Search.Bookmark
End If
rs_Search.Close
Search_Order = Null
Set rs_Search = Nothing
End Sub
The second command "ButtonSetOrderDetails10" should create a RecordsetClone of the Subform "sfrmChangeOrderDetails" and change the Value of the Field "OrderStatus" to the Vlaue of "10".
It has this code:
Private Sub ButtonSetOrderDetails10_Click()
Dim rs_Status_Change As DAO.Recordset
Set rs_Status_Change = Me.sfrmChangeOrderDetails.Form.RecordsetClone
With rs_Status_Change
Do While Not .EOF
.Edit
.Fields("OrderStatus") = 10
.Update
.MoveNext
Loop
End With
rs_Status_Change.Close
Set rs_Status_Change = Nothing
End Sub
I've looked both codes here up and modified them to the needs of my database. Both codes work fine so far, but unfortunately only once.
My problem is that as soon as I hit the Button "ButtonSetOrderDetails10" I can't do the same trick with a different order. I can search for the other order, it is displayed but the Button "ButtonSetOrderDetails10" does not work anymore. If I close the Form and reopen it, it works again.
It would be great if someone can give me a hint what I'm doing wrong here.
Best regards, Ferdi
I am surprised even works one time. With DAO recordset need to read dataset into memory before it will be able see records for edit otherwise just sees EOF and the loop doesn't run. Try:
rs_Status_Change.MoveLast
rs_Status_Change.MoveFirst
With rs_Status_Change
Don't even need to declare/set/close a recordset object.
Private Sub Search_Order_AfterUpdate()
With Me.RecordsetClone
.FindFirst "[OrderNumber]='" & Me.Search_Order & "'"
If .NoMatch Then
MsgBox "Sorry, no such record '" & Me.Search_Order & "' was found.", _
vbOKOnly + vbInformation
Else
Me.Bookmark = .Bookmark
End If
End With
Me.Search_Order = Null
End Sub
Private Sub ButtonSetOrderDetails10_Click()
With Me.sfrmChangeOrderDetails.Form.RecordsetClone
.MoveLast
.MoveFirst
Do While Not .EOF
.Edit
.Fields("OrderStatus") = 10
.Update
.MoveNext
Loop
End With
End Sub
Could really simplify code by running an UPDATE action SQL.
Private Sub ButtonSetOrderDetails10_Click()
CurrentDb.Execute "UPDATE ChangeOrderDetails SET OrderStatus=10 WHERE OrderNumber='" & Me.OrderNumber & "'"
End Sub

INSERT INTO - errors, but allows input into table

For reasons I cannot see I get the following error message:
Compile error: Method or data member not found
when I use the following:
Private Sub cmd_Add_Click()
Dim strSQL As String
strSQL = " INSERT INTO BERTHAGE " _
& "(BOAT, LOCATION, BERTH_WEEK, BERTH_YEAR, BERTHED) VALUES " _
& Me.Add_Boat & "','" _
& Me.LOCATION & "','" _
& Me.txt_week & "','" _
& Me.txt_year & "','" _
& Me.In_Port & "');"
cmd_Clear_Click
End Sub
Once I click OK and use the refresh button the entry is put into the database, but each time I do an entry I have to go to the same process.
I would like to figure out what method or data is missing?
I should add that there is an outnumber primary key field on this table (Berth_ID), and each time I use the cmd_Add button a new ID number is created for the new record. This includes creating a new ID number for the new record that triggers the error.
Here is all the VBA associated with this form
Private Sub Form_Load()
DoCmd.RunCommand acCmdRecordsGoToLast
End Sub
Private Sub LOCATION_Change()
Me.txt_Cur_Flo = Me.LOCATION.Column(1)
Me.txt_Cur_Doc = Me.LOCATION.Column(2)
Me.txt_Cur_Ori = Me.LOCATION.Column(3)
End Sub
Private Sub cmd_Add_Click()
Dim strSQL As String
strSQL = " INSERT INTO BERTHAGE " _
& "(BOAT, LOCATION, BERTH_WEEK, BERTH_YEAR, BERTHED) VALUES " _
& Me.Add_Boat & "','" _
& Me.LOCATION & "','" _
& Me.txt_week & "','" _
& Me.txt_year & "','" _
& Me.In_Port & "');"
cmd_Clear_Click
End Sub
Private Sub cmd_Clear_Click()
Me.Add_Boat = ""
Me.LOCATION = ""
Me.txt_Cur_Flo = ""
Me.txt_Cur_Doc = ""
Me.txt_Cur_Ori = ""
Me.Add_Boat.SetFocus
End Sub
Private Sub cmd_Close_Click()
DoCmd.Close
End Sub
Consider the best practice of parameterization and not string concatenation of SQL mixed with VBA variables. Due to missing quotes, the compiler attempts to reference a column name and not its literal value. Instead, consider parameterization with defined types which is supported with Access SQL using QueryDefs. Notice below, SQL and VBA are complete separate.
SQL (save as stored query)
PARAMETERS prmBoat TEXT, prmLoc INT, prmBerthed INT;
INSERT INTO BERTHAGE (BOAT, LOCATION, BERTHED)
VALUES(prmBoat, prmLoc, prmBerthed)
VBA
Dim db As Database
Dim qdef As QueryDef
Dim strSQL As String
Set db = CurrentDb
Set qdef = db.QueryDefs("mySavedParamQuery")
' BIND PARAM VALUES
qdef!prmBoat = Me.Add_Boat
qdef!prmLoc = Me.LOCATION
qdef!prmBerthed = Me.In_Port
' EXECUTE ACTION QUERY
qdef.Execute
Set qdef = Nothing
Set db = Nothing
Even better, save your query with form controls intact and simply call OpenQuery:
SQL (save as stored query)
INSERT INTO BERTHAGE(BOAT, LOCATION, BERTHED)
VALUES(Forms!myForm!Add_Boat, Forms!myForm!LOCATION, Forms!myForm!In_Port)
VBA
Private Sub cmd_Add_Click()
Dim strSQL As String
DoCmd.SetWarnings False ' TURN OFF APPEND PROMPTS
DoCmd.OpenQuery "mySavedActionQuery"
DoCmd.SetWarnings True ' RESET WARNINGS
Call cmd_Clear_Click
End Sub
Missing opening parenthesis after VALUES. Also missing apostrophe in front of Me.Add_Boat. These special characters must always be in pairs, an even number by counting.
If Berth_Week and Berth_Year are number fields (and should be), don't use apostrophe delimiters.
If In_Port is a Yes/No field, don't use apostrophe delimiters.
The issue appears to be that I was doubling up the inputs into the 'week' and 'year' field. this was happening (I believe) because those text box fields were already accessing the week and year information directly from the default value on the BERTHAGE table. Essentially I went through each input and would run it individually waiting for the error to occur. Once it occurred I took it out of the INSERT INFO statement. With the removal of week and year, everything is working. That was a painful exercise, and still not complete, but I am back to a function form/DB so I'll take the small victories when they occur.
Private Sub cmd_Add_Click()
Dim strSQL As String
CurrentDb.Execute " INSERT INTO BERTHAGE " & "(BOAT, LOCATION, BERTHED) VALUES ('" & Me.Add_Boat & "'," _
& Me.New_Loc & "," _
& Me.In_Port & ");"
cmd_Clear_Click
DoCmd.Requery
End Sub`

OpenRecordset not returning usable recordset / .edit not working?

Working on a database on Access, trying to run a query to find a record with the latest date and a 'where' condition.
Error returned is "Run Timer Error '3027' Cannot update. Database or object is read-only"
Following conditions:
Button is clicked on a form that contains a text field for 'fCheckInFor'.
Database 'ToolTests' fields
"CheckOut" is dates in format of "3/15/2019 5:35:31 PM"
"CheckIn" is dates in format of "3/15/2019 5:35:31 PM"
"CheckInFor" is a text field
"ToolNumber" is a text field
Public CheckInTool as String
Private Sub CheckIn_Click()
CheckInTool = "000"
If Me.fCheckInFor = "" Then
MsgBox "Enter Returning User."
Else
Dim dbsUE As DAO.Database
Dim rstUE As DAO.Recordset
Set dbsUE = CurrentDb
Set rstUE = dbsUE.OpenRecordset("SELECT Max([CheckOut]) FROM [ToolTests] WHERE [ToolNumber]= '" & CheckInTool & "'")
With rstUE
.Edit 'error occurs here
!CheckIn = Now()
!CheckInFor = Me.fCheckInFor
.Update
End With
MsgBox "Checked In"
DoCmd.Close acForm, "CheckIn"
End If
End Sub
So the error throws at the .Edit line, I'm unsure where to go from here. would also be fine with tossing the whole thing and going at it from a different direction.
If I get you right, you want to update a record that has a specific ToolNumber. So, if you want to use a subquery, you will either need to use that criterion in both the main query and the subquery, or link the subquery with the main query using that field:
Set rstUE = dbsUE.OpenRecordset( _ &
"SELECT CheckIn, CheckinFor FROM ToolTests WHERE" & _
" CheckOut IN (SELECT Max(CheckOut) FROM ToolTests AS tmp WHERE ToolNumber = ToolTests.ToolNumber)" & _
" And ToolNumber = '" & CheckInTool & "'")
Alternatively, you could simply sort the records in the correct order and update the first one:
Set rstUE = dbsUE.OpenRecordset( _ &
"SELECT CheckIn, CheckinFor FROM ToolTests WHERE" & _
" ToolNumber = '" & CheckInTool & "'" & _
" ORDER BY CheckOut DESC")

MS Access save record as PDF using ID

My organization uses a MS Access database to store incident reports. I have a report called "Case Details" and I want to have the option to save the report that's currently open as a PDF. I've got it working for the most part, the only issue is that when saving the PDF, it's saving all of the records, not just the record that was being viewed.
How do I fix it so that it only saves the record being viewed, using the record's ID?
Here's the code for the save button.
Private Sub Command1626_Click()
DoCmd.OutputTo acOutputReport, "Case Details", acFormatPDF, "G:\Police\Restricted\Saved Reports\ " & Me.txtPDFRef & ".pdf", True
End Sub
The "txtPDFRef" box on the report contains the following code, which is used to name the report. (Case Number - Officer - Date Saved)
="CR" & Format(Date(),"yy") & "-000" & [ID] & " - " & [ReportingOfficer] & " - " & Format(Date(),"yyyymmdd")
It seems the only way is to filter the report to the record to be printed.
So it's essential to determine the ID of the record to be printed.
It's not clear for me, if your button is located on the report itself or maybe on a form.
Button on the report itself
I tried to get it running when the button is on the report itself.
To determine the current ID it seems to be necessary that the calling button is located in the detail section of the report.
Then you can filter the report, export it to pdf and restore the maybe before applied filter.
The only backdraw is, that I found no way to view the last viewed record in the report after the code executed.
Instead you are on the first record.
This would be the code for the button:
Dim currentFilter As String
currentFilter = Me.Filter
Dim currentFilterOn As Boolean
currentFilterOn = Me.FilterOn
'If field type of ID is a number use this:
Me.Filter = "[ID] = " & Me.ID
'If field type of ID is a string use this:
'Me.Filter = "[ID] = '" & Me.ID & "'"
Me.FilterOn = True
DoCmd.OutputTo acOutputReport, Me.Name, acFormatPDF, "G:\Police\Restricted\Saved Reports\ " & Me.txtPDFRef & ".pdf", True
Me.Filter = currentFilter
Me.FilterOn = currentFilterOn
Button on a form
If the button is for example on a form and you just want to print the regarding report, then you could use this code in this button:
Const REPORT_NAME As String = "Case Details"
Dim condition As String
'If field type of ID is a number use this:
condition = "[ID] = " & Me.ID
'If field type of ID is a string use this:
'condition = "[ID] = '" Me.ID & "'"
DoCmd.OpenReport REPORT_NAME, acViewPreview, , condition, acHidden
'You would have to provide txtPDFRef in another way, because the report isn't open yet.
DoCmd.OutputTo acOutputReport, REPORT_NAME, acFormatPDF, "G:\Police\Restricted\Saved Reports\ " & Me.txtPDFRef & ".pdf", True
DoCmd.Close acReport, REPORT_NAME
It closes the report after saving to pdf. Be aware that you maybe have to provide txtPDFRef in a different way. But maybe it exists on the form too with the same name, that would make it run immediately.
Simplest solutions:
Option 1
Open the report in preview with a filter, then use outputTo without the ObjectName argument.
docmd.openReport "Case Details",,"id = " & id
docmd.outputTo objectType:=acOutputReport, outputFormat:=acFormatPDF, outputFile:= somefileName
docmd.close acOutputReport, "Case Details"
Option 2 (even simpler)
In design view, change the reports'filter property to refer to a control in the calling form.
Something like id = forms!someForm.idControl

Dynamic report in MS access will not update with source query

So I have a database of mechanical components. I have a search form in the database that allows the user to apply filters to a query (through the use of 5 text/combo boxes and an "apply filters" button). This query will contain the components that made it past the filter, and some details about those components. Also on the search form, I have a sub-report that is bound to the query.
My plan is to have the user filter though the data using the controls on the form. As the user filters out components, the report should update to display what components pass the new query. They would then select the component they are interested in by clicking on a record in the report, and that component ID would be passed into VBA to do more stuff.
My problem is that the report bound to the query will not update as the query does. I have tried using DoCmd.Requery and Me.Form.Refresh on the button click event, but haven't gotten anywhere. It only works if I close the form, then re-open it.
How do I get my bound report to change dynamically as the user modifies the SQL of its source query?
Here's my click event code:
Private Sub cmdApplyFilters_Click()
Call updateSearchFilters
Me.Requery
Me.Form.Refresh
End Sub
Here's my sub to update the query:
Public Sub updateSearchFilters()
Dim strSQL As String
Dim searchQryDef As DAO.QueryDef
strSQL = searchSQLstrBuilder(Forms("frmSearch").tboCompID, Forms("frmSearch").tboDesc, Forms("frmSearch").cboType, Forms("frmSearch").cboVendor, Forms("frmSearch").tboVendPN)
Set searchQryDef = CurrentDb.QueryDefs("qrySearchRes")
searchQryDef.SQL = strSQL
End Sub
Here's my SQL string builder:
Public Function searchSQLstrBuilder(tboCompID As TextBox, tboDesc As TextBox, cboType As ComboBox, cboVend As ComboBox, tboVPN As TextBox) As String
searchSQLstrBuilder = "SELECT tblDocs.compID, tblComponents.Desc, tblComponents.type, tblComponents.vend, tblComponents.vendorPN "
searchSQLstrBuilder = searchSQLstrBuilder & "FROM tblComponents INNER JOIN tblDocs ON tblComponents.numComp = tblDocs.numComp "
Dim strCompID, strDesc, strType, strVend, strVPN As String
strCompID = tboCompID.Value
strDesc = tboDesc.Value
strType = cboType.Value
strVend = cboVend.Value
If IsNull(tboVPN.Value) Then
strVPN = ""
searchSQLstrBuilder = searchSQLstrBuilder & "WHERE (((tblDocs.compID) Like '*" & strCompID & "*') AND ((tblComponents.Desc) Like '*" & strDesc & "*') AND ((tblComponents.type) Like '*" & strType & "*') AND ((tblComponents.vend) Like '*" & strVend & "*') AND ([vendorPN] Is Null Or (tblComponents.vendorPN) Like '*" & strVPN & "*'));"
Else
strVPN = tboVPN.Value
searchSQLstrBuilder = searchSQLstrBuilder & "WHERE (((tblDocs.compID) Like '*" & strCompID & "*') AND ((tblComponents.Desc) Like '*" & strDesc & "*') AND ((tblComponents.type) Like '*" & strType & "*') AND ((tblComponents.vend) Like '*" & strVend & "*') AND ((tblComponents.vendorPN) Like '*" & strVPN & "*'));"
End If
End Function
Thanks in advance! Let me know if there's more information I can provide.
I don't fully understand this problem, because you can't have a button on a report. They're not interactive. So, I'm assuming you have a button on a form which opens a report.
What you might try is updating the RecordSource of the report. After the updateSearchFilters code runs, at the very end of that function, add:
Reports!rptMyReport.RecordSource = "Select * from qrySearchRes"
Alternatively, you could have a SQL string as a RecordSource and pass variables in using OpenArgs:
Dim strMyValue As String
strMyValue = "This Is A TEST!"
DoCmd.OpenReport "rptMyReport", acViewPreview, , , acWindowNormal, strMyValue
and then in the report you would add this on Form_Load:
Dim strMyValue As String
strMyValue = Me.OpenArgs
Then you can use strMyValue as a parameter in your RecordSource.
It is also possible to pass multiple values via OpenArgs, but it's a little more tricky. You can use a pipe delimiter ("|") to separate your values, but when you open it you'll have to parse out the values on the other side using some VBA.
It's kind of unusual to have a subreport on a form...
After running updateSearchFilters, you need to explicitly Requery the subreport.
Me!subReport.Report.Requery
subReport is the name of the subreport control on the form.