I have a problem with the DoCmd.SetOrderBy method applied by my report.
I have a table with the name "Types_Docuements" and columns:
ID
Document_Name
Version
Then I have a Report based on this table.
I want to order the data based on ID or Document_Name.
The report property sheet has this setting:
Record Source - Types_Documents
Filter - empty
Filter on Load - Yes (I tried also no)
Order by - id
Order by on load - yes
Allow Filters - yes
My VBA code is:
Option Compare Database
Private Sub cmd_id_desc_Click()
DoCmd.SetOrderBy ("id DESC")
End Sub
However, I am not able to do that neither in Property Sheet manually nor with VBA. I guess that VBA code works, because after its trigger the property sheets changes. But order of the data is still the same.
Thank you for your advice,
Vaclav
Related
Is there some sort of work-around that could make this possible? Or could anyone offer just some general advice on my situation below? I tried to set the record source through VBA but had no luck.
My situation:
I have a main form with a subform contained within, and I want the subform to be purely for data entry (Data Entry = Yes). Upon clicking a button, the user is sent from the main form to a report (print preview only). I want the source for this report to be the subform the users are entering data into, but I don't have this option from the report's property sheet itself (no forms), and I also was unable to set it through VBA. Here's my code, it's one line so I highly doubt it's the problem.
Private Sub Report_Load()
Reports![P18003 SDR Report].RecordSource = "P18003 SDR Subform"
End Sub
Previously, to work-around this I had a parameter query that waited for the user to enter data into an unbound textbox from the main form, and an after update trigger on that textbox would load any data relevant to that parameter (my employer and I miscommunicated the requirements).
It turns out though that I don't need to load any older data, and I run into problems with my current parameter query in the event that the user does input a parameter which loads old data - that old data is transferred to the report in addition to the new data they've just entered. This is the main problem with the method I am currently using, and it trashes almost all functionality with this form and report. The events that a user would need to enter a parameter which queries older data are few and far between, but it's not a functional product unless I can get the subform to be connected to the report directly. There's likely something obvious I'm missing here (or at least, I hope there is).
Thanks in advance for taking the time to read this and for any help you may offer.
you can either send the recordsource to the report itself in the OpenArgs by the open report event, after the click event in the subform
Private Sub btnSubform_Click()
Dim strSQL as String
strSQL = "SELECT * FROM SubformQuery WHERE ID = " & CurrentSubfromRecordID
Docmd.OpenReport, acViewReport, , , , strSQL
End Sub
and then in the Report.
Private Sub Report_Open(Cancel As Integer)
Me.recordsource = Me.OpenArgs
End Sub
Or you can make a paramter Query and set this Query criteria as record source for the report. So the parameter in the query is pointing to the current selected row in the subform. Like this:
--- At the Criteria in the Query designer:
--- RecordSource for the Report:
Forms![FormMain]![YourSubform]![ID]
Now every time the reports obens he gets the ID from the current selected record of your subform.
I have been using MS Access to aid in generating pdf reports based on a table. I have created a form that contains a text box for entering a client's name (this value is in the main table) and a button that when clicked runs the code:
Private Sub cmdPrintRecord_Click()
Dim strReportName As String
Dim strCriteria As String
strReportName = "Current SP Report"
strCriteria = "[Owner]='" & Me![Owner] & "'"
DoCmd.OpenReport strReportName, acViewPreview, , strCriteria
End Sub
The idea here is to generate an individual PDF report based on the clients name.
The above procedure has been able to do that successfully however, I have encountered that as I run it, the data in my table is affected, specifically the client name field.
For example: I'll run a report for client "Anthony" and it shows 10 products which is correct, but then if I go back and run that same report again it will show 11 products. It is as if the procedure here is altering the data table.
How can I troubleshoot this issue and or are there any alternatives recommended?
Thanks.
Attached is the MS link where I obtained the source code:
https://support.microsoft.com/en-us/kb/209560
If the Control Source of a form control (textbox, combo box) is linked to a table then it will modify that table. In your case, you want to receive user input based on selections from a table and not to modify the table itself. You want to use the "Row Source" property to limit the selection to table items and clear the Control Source. This pulls potential options from the table without changing existing table entries.
Like this:
Notice that the source of options for the combobox is a query that defines what items should appear in the dropdown but no Control Source is specified.
I'm new to VBA and Access, but I do have some understanding.
I can set a field easily by using
[Field1] = Now()
What I want to do is save the name of a field into a string and use that variable to reference the field. This way I can save different field names into the variable and have the code act on which field name happens to be stored.
From what I can find, the proper way to do this is in my situation is:
Private Sub ctlUpdateButton_Click()
Dim varField as String
varField = Dlookup("[Targeted Field]", "[Other Table]")
Cases.Fields(varField) = Now()
End Sub
This code breaks on the reference to Cases.Fields(varField) and reports the error as 'Run-time error '424' Object Required.
The record source for the form is a query based on the Cases table.
I'm not familiar enough with what I'm working with to know if this is a sufficient explanation.
Not sure what you're trying to do with varField = Dlookup("[Targeted Field]", "[Other Table]")
DLookup returns the value of a field in another table
Is there only one row in that table?
If so - then your code will work in theory -
If not, you;ll have to specifiy the criteria to find the correct row
The last issue is that you can't use a table name directly in code (in your case "Cases")
If you want to change the underlying record in your form, you can modify it if the field name is in your query and it hasn't been renamed.
Simply use Me(varField) = Now()
I am completely new to VBA. I have been told to add records to a table by using a form and a Save button and given some very basic instructions. While I have achieved this with inline query, I have been told to follow some strict methods like usage of QueryDef/QueryDefs and .Parameters.
So far I am trying a very basic project, just to grasp the concepts, but I am unable to add any record to an empty table. In case the table is not empty(I manually enter a record), whenever I click the Save button for saving newer records, the number of records added are somehow doubling with each instance. For example, when I Save for the 1st time, 1 record is added, 2nd time 2 records of the same type is added, 3rd time 4 are added and so on.
The table(tbl_test) has 2 fields --> ID(primary key), Source(Long Text) and Reg No (Number).
The query(qry_test) is made with the Append feature and I have been told to add expressions which makes the code like this -
INSERT INTO tbl_test ( Source, [Reg No] )
SELECT [strSource] AS Expr1, [lngRegNo] AS Expr2
FROM tbl_test;
The form has 2 fields for Source(txt_Source) and Reg No(txt_RegNo) which have blank Record Sources (Unbound). The Save button has the following Event Procedure -
Private Sub btn_save_Click()
Dim qdf As QueryDef
Set qdf = CurrentDb.QueryDefs("qry_test")
qdf.Parameters("strSource") = Me.txt_Source
qdf.Parameters("lngRegNo") = Me.txt_RegNo
qdf.Execute
End Sub
I have zero knowledge about VBA and would gladly accept ANY help. It would be great if I get any sort of source code that will explain to all the details about saving records from forms and editing them using these querydef, parameter and recordset stuff.
Welcome to StackOverflow!
If you are using a form to collect data for records that are stored in a table, running a saved append query by QueryDefs to do this is, in my opinion, not the best method.
Whilst an append query does add new records to an existing table, I would tend to use an append query where I've got multiple established records that I want to add to an existing table.
If I'm setting up a data entry form that is designed to collect new data for new records 1-at-a-time, an append query doesn't really suit this purpose.
Instead, there are a number of features built in to the design of MS-Access forms to help collect data and save it to a table. This is because forms are very much intended to be set up so that users can interact with records from a table in a controlled, user-friendly way rather than interact directly with the table object itself.
The first and most important feature of a form in this context is probably the form's record source property. When you create a new form, go in to design view for the form and open the form's property sheet (F4 key). In the "Data" tab of the form's property sheet you'll find the record source property:
The record source essentially connects your form with a set of records, whether those be records in a table object, a query object or an sql query string.
In your case it would be better, in my opinion, to bind your tbl_Test table to your form by referring to it in your form's record source:
It will seem like nothing has happened to your form, but if you now open the "Add Existing Fields" panel (alt + F8), you'll notice that the fields associated with your tbl_Test table are available to you:
Drag them to the detail section of your form...
Then put your form in to Form View:
Essentially what you and your users are seeing is the first blank record in your tbl_Test, but displayed on a form instead.
Entering data in these fields on the form...
...will put that data in to the table we specified in the form's record source...
So hopefully you can see that setting the form's record source property to that of your table, is much cleaner than trying to get an append query to collect data from your form and deliver it your table.
At this point you're probably asking a few questions:
When I have filled in the fields for a record on my form, how do I save that record?
More can be said about this, but for brevity, I'd recommend using a command button for running some vba to save the record; similar to what you've done, but utilising the form's Dirty property instead using an append query:
Here's the click event VBA for my save button example:
Private Sub cmdSave_Click()
If Me.Dirty Then
Me.Dirty = False
End If
End Sub
Me.Dirty is a Boolean (True or False) setting for the form; essentially it is automatically set to True when a user changes something on the form. To save those changes, the Me.Dirty setting will have to be set to False.
Me.Dirty is a bit like the swing gate on a sheep pen. When a shepherd puts a sheep (data) in the pen (form) they will open the gate to the pen. The open gate is like the form's Me.Dirty being set to True. To lock the sheep (data) in, the gate needs to be closed, or in the case of forms, the Me.Dirty property needs to be set to False. The VBA above essentially checks to see if the gate was opened and if it was to close it.
How do I move to a new record in the form once I have saved the current one?
Again, I'd give the user a command button to do this and run some VBA on its click event:
Here's the VBA for moving to a new record:
Private Sub cmdNew_Click()
DoCmd.GoToRecord , , acNewRec
End Sub
Summary
There is a lot more to consider than what I've outlined here, such as:
validating data before it is saved
checking other form events (such as close) to ensure data entry is not lost
navigating to an existing record
But hopefully what I've given you here is at least pointing you in a better direction. Best of luck!
Access is optimized for bound forms. Unbound forms are for special cases only.
Should you prefer unbound forms (could be for many reasons), Access isn't worth the trouble, and you should turn to Visual Studio and WinForms.
In either case, browse for a beginner's tutorial.
If you want to use an unbound for or unbound controls you can create the SQL string in the procedure:
Dim mysql as String
mysql = "INSERT INTO tbl_test ( [source], [reg_No]) VALUES (Me.txt_Source, Me.txt_RegNo)
DoCmd.RunSQL mysql
I have a report (ReportX) that I wish to open from two different forms (FormA and FormB) in my database. I wish to do this because FormA and FormB address different aspects of my data, even if they ultimately get to the same output. ReportX is based on data from QueryX.
The problem I have is that QueryX would ideally filter the data based on the current RecordID in the current form. But I don't know how to accomplish this. I'd like to design QueryX so that the criteria for RecordID is essentially CurrentForm!RecordID, but research suggests that I cannot do this. Must I make separate but otherwise identical queries and reports for each form? Or is there a way to use VBA to define the query criteria when I click on the OpenReportX command button?
I already tried using the WHERE condition in the OpenReport command:
DoCmd.OpenReport "ReportX", acViewPreview, ,"RecordID = " & RecordID
but that did not display the results I wished. I need the report header to display/print for each RecordID and the page count in the page footer to reflect only the current/total pages of the RecordID in question. (In other words, if record 1 is one page, record 2 is two pages and record 3 is three pages, then ReportX, when displaying the first page of record 2, should say "Page 1 of 2" and not "Page 2 of 6.") So being able to display and print a single record properly using record filters would also solve my problem.
Which is the least cumbersome/most possible solution?
You should be able to accomplish this using the WHERE condition argument when you open a report:
DoCmd.OpenReport "rptName", acViewPreview, ,"RecordID = " & Me!RecordID
In the case where a I need more control over a Report's recordsource than what the Where condition argument can do for me, I will set the Reports RecordSource to be blank (after designing the report). Next I write code create the correct SQL statement in the Open Report button's Click event, followed by code to open the report and pass in the SQL as an opening argument for the report.
Private Sub cmdOpenReport_Click()
Dim sSQL as string
sSQL = "SELECT * FROM tblWhatever WHERE RecordID = " & Me!RecordID
DoCmd.OpenReport "rptReportName", acViewPreview, , , ,sSQL
End Sub
Then in the report's Open event I write code to set the recordsource:
Private Sub Report_Open(Cancel As Integer)
If IsNull(Me.OpenArgs) = False Then
Me.RecordSource = Me.OpenArgs
End If
End Sub
If neither of those accomplish what you want then you have an issue of a different sort. It's a little difficult for me to understand why you need All Records to show up in the header but only one record in the detail area. And how you expect to accomplish this. You might be best off trying to write a query first that gives you the exact results that your looking for so you know that it can be done.
As a side note, I actually use very few saved queries in my designs. It's not that there's anything wrong with using them, as the option is there for your convenience. I frequently use raw SQL on both forms and reports and set the RecordSource to the SQL on the Form or Reports Open or Load events.
Yes you can point to form data items in a query, and subsequently use that query in a report. The forms need to be open before the report runs. As far as having a header for each record, that is controlled in the settings of the report and how it displays the data.
In the Field, or Critera you can use the format:
[Forms]![frm_Process_Candidates]![QuestionTemplate]
Where frm_Process_Candidates would be the name assigned to your form, and QuestionTemplate is either the name of a control on your form, or a field from the data source of your form.
If you have a sub-form, there will be another [Form] call in the middle there.
[Forms]![frm_Dropdown_Admin]![frm_Dropdown_Admin_Detail].[Form]![text22]
Access should figure it out from there.