I am not able to encode any entries to the Sub-form data grid on the Main form when I inserted the following SQL field. If I remove this column, the system allows me to the new data record creation. Can anyone look into this issue please!
Advance Payment Balance:
(SELECT SUM(NZ(T1.AdvancePayment,0)-
NZ(([GrossInv-WorksCertified-61110]*
[SubCon-BasicInfo].[Advance-409130-%]/100),0))
FROM [InvoiceMaster] AS T1
WHERE T1.[SubConName]=[InvoiceMaster].[SubconName]
AND T1.[ID]<=[InvoiceMaster].[ID])
Using calculations in a query make the underlying recordset not updateable.
See this question for an excellent list why queries (and forms based on them) sometimes are not updateable.
The proper way to include calculations on a datasheet form is to open it in design view, add a new text box control to them, and set the controls control source equal to an = equal sign followed by your calculation.
You also will need to rewrite the subquery to a domain aggregate or use a combo box to use a query.
Rewrite example:
DSUM("NZ(InvoiceMaster.AdvancePayment,0)- NZ(([GrossInv-WorksCertified-61110]*[SubCon-BasicInfo].[Advance-409130-%]/100),0)", "InvoiceMaster", "[SubConName] = """ & [InvoiceMaster].[SubconName] & """ AND ID = " & [InvoiceMaster].[ID])
Related
NOTE
I significantly edited my original post to include more relevant information and removed insignificant information. Some of the comments are based on the information removed, but the integrity of the original question is still intact and the comments are still relevant and useful.
In my database I have a table tblStandards that has a list of compound names with their associated fields.
I created a form to generate a subform which only populates compound names and their data when you select a solution mixture (I called these "handles"). I am using this subform as a means of generating a "Location Finder" of all the respective compounds associated with that solution mixture "handle". The issue is some compounds are used in multiple different mixtures, thus having multiple "handles". I have included a cascading combo box as recommended by #June7, but I am running into an issue with the last combo box filter.
I don’t want to have a separate field attached to my tblStandards with the combo box display value ("handle") just to filter my table (which is what I have done in the past). Using combo box display value field in my table works but it is limited and I wish to make it more modular. I have a second table tblComboBox which has three fields; [Compound Name], [Standard_InternalStd], and [Cal_QC_Handle].
I have the cascading combo box working, except for last filter. I think I found a round-about way to filter based on my tables. I am using an After_Update event with the FilterOn function to filter a TempSubform which is filtering the tblComboBox based on matching the [Cal_QC_Handle] to the cboxSecondChoice, then using TempSubform![Compound Names] field as a second FilterOn function for my MainSubform.
My code is working, but the second FilterOn is only using the first Compound Name from my TempSubform to filter MainSubform. I want to filter based on all the rows in my Tempsubform.[Compound Name]. I think my issue is in my " & Me.Temsubform![Compound Name] &" block of code.
Private Sub cboxSecondChoice_AfterUpdate()
Dim Filter_Tempsubform As String
Filter_Tempsubform = "[Cal_QC_Handle] ='" & Me.cboxSecondChoice & "'"
Forms![Standards_Form]![TempSubform].Form.FilterOn = False
Forms![Standards_Form]![TempSubform].Form.Filter = Filter_Tempsubform
Forms![Standards_Form]![TempSubform].Form.FilterOn = True
Dim Filter_MainSubform As String
Filter_MainSubform = "[Compound Name] = '" & Me.TempSubform![Compound Name] & "'"
Forms![Standards_Form]![MainSubform].Form.FilterOn = False
Forms![Standards_Form]![MainSubform].Form.Filter = Filter_MainSubform
Forms![Standards_Form]![MainSubform].Form.FilterOn = True
End Sub
The issue is the filter is only using one Compound Name (the first on the list) to filter. I need the filter to use all the Compound Names from the newly filtered TempSubform. Apologies if this is a very convoluted approach. Every example that I have seen so far always has the combo box value embedded in the table that they are filtering, which is something I wish to avoid.
UPDATE
I have abandoned my 1st attempt (the double FilterOn function with a temporary Subform) and I have a working form! I had to modify my tblStandards to include a new field which contained values from my final combobox selection (which I wanted to circumvent initially due to my perceived limitations of this design). The new Form-Handle field on my table is a string with multiple single "handles" which I use if the final combobox selection (only a single "handle" can be selected) is in the subform using the wildcard "Like *". Each one of these "handles" corresponds to a solution mixture which is a specific list of compounds.
This solution allows me to have a single compound used to make multiple different solutions, and if you select any of these solutions to make from the dropdown combo box the compound will be returned. I think this is the simplest solution to my issue and I might have just been too stubborn looking for a over-complicated solution.
I modified code from Allen Browne's ms-Access "Filter a Form on a Field in a Subform"
Relationships (All)
Form with cascading comboboxes and filter button
Working code
As #June7 said, cascading ComboBoxes (or ListBoxes) are the standard UI design for multistage filtering of data tables. If I have the available form real estate, I prefer cascading ListBoxes over ComboBoxes, because of the visual cues they provide. For example, look at how Digi-Key does it. Problems with cascading ComboBoxes have been questioned to death here. Boxes which filter data, list or combo, are usually unbound, and should not be simultaneously used to update data. Their sole purpose is to display item choices, select an item, and pass it's value to the next filter.
I'm linking below to a few tutorials, which require little to no VBA code. The 3rd tutorial filters "plants and animals, categorized by their taxonomic rank", which is a similar case to filtering chemical compounds. The 4th is one of my previous answers to a similar question.
Microsoft Access: How to Create Cascading Combo Boxes
Access 2016 - How to Make a City/State Selector (Cascading Combo
Boxes)
Creating Cascading Combo Boxes and List Boxes on Microsoft Access
Forms
Creating Cascading Comboxes in VBA code using RowSource
I am having to redevelop an MS Access 2003/2010 ADP project, that uses SQL Server views as the RecordSource for all its forms, into an MS Access 2016 ACCDB.
I have tried using pass through queries to get the data and this works fine for readonly columns, however when I want to change the value in one of the bound columns, it says that the RecordSet is not updateable, which is what you might expect if using a view.
But I have now read that if you define the view with SCHEMABINDING like this:
ALTER VIEW [dbo].[vwQuote_MinibusesDetails]
WITH SCHEMABINDING
AS
SELECT ...
and add a UNIQUE CLUSTERED INDEX like this:
CREATE UNIQUE CLUSTERED INDEX CIX_vwQuote_MinibusesDetails
ON vwQuote_MinibusesDetails (txtQuoteNo, txtVersion, txtVehicleNo);
and then add the view to your project as a DSN-less TableDef like this
stConnect = "ODBC;Driver=SQL Server;Server=" & SERVER_NAME & ";Database=" & APP_DATABASE & ";Trusted_Connection=Yes"
Set td = CurrentDb.CreateTableDef(stLocalTableName, dbAttachSavePWD, stRemoteTableName, stConnect)
CurrentDb.TableDefs.Append td
it becomes editable as if it were a table.
However, when I open the TableDef in Access it shows all the rows and columns as if it were editable, but if I try to edit a column, it says that there is a Write Conflict with another user's changes, when I am 100% sure that there isn't because I am the only person using it.
Any ideas? (I am using Access 2010 at the moment)
But why do all that truckloads of work? There is zero reason to do all that extra work.
Simply bind and set the forms data source to a view. It is assumed that you will simply link all of the existing views on the client side. Access will thus see all the views as simply tables, and views (as opposed to Pass through queries) are read/write.
So, there is no need to:
Have ANY connection strings in your code. If you ARE using connection strings in code, then you approach is all wrong. Just link to the views, and set the forms data source as that view.
At this point, the forms can edit data.
As for a pass-through quires to drive combo boxes? Do NOT do this. While a PT query is likely the fastest way to pull data, the access client cannot filter PT queries. So you ONLY EVER want to use a PT query for cases in which the client side does NOT have to filter the results. If you bind a combo box to a PT query, then Access needs and wants to ONLY pull the one value from that table for display. And since the access client can’t filter a PT query, then it will scan the WHOLE data source for that combo box to get the one value that is currently displayed. If you use a linked table (or even a view) to that source that drives the combo box, then the access client can filter that dataset to the ONE row. So, do NOT use a PT query for ANY case in which client side filtering is required. A linked view (or linked table) is fine in these cases.
So, just bind the forms directly to the linked table, or the linked view.
If the table has 1 million rows of data, and you say do this:
Docmd.OpenForm "frmInvoice",,,"InvoiceNum = 1234"
Access will open the form to the ONE row of data, and ONLY pull one row down the network pipe. This is despite that the form in question is bound to a table of 1 million rows. The form will load instant, and you not had to write any sql, any connection stuff, and not really do anything different then how you developed typical access applications.
Bound forms are how and why Access saves huge development dollars. If you jump to .net, then you have all kinds of tools and wizards that can help you around this issue. So in .net, you could adopt the dataset designer, or use the newer entity framework.
In Access, we don’t have this huge tool box of data designers and tools, so if you attempt to hand code, and code up the data sources for a form, then you get the worst possible outcome (you write truckloads of code, and don’t have all those cool tools for un-bound forms).
Simply link your forms to linked tables (or views) and you now have a working data bound form without any code. If you need to load the form, then use the 20+ year standard approach of the “where” clause of the open form command to open the form to the one record. The access client will ONLY pull what you put in the “where” clause.
So, to wire up a form for editing of data, ZERO code is required. The only developer efforts will then to ensure that the form does not pull un-necessary data to the client.
tldr: Can not update records from query because of aggregate functions. What workarounds do you suggest?
I have a table containing decision criteria to which a user can assign a relative weight. I calculate the absolute weight in an SQL query using an aggregate function (as described here Divide the value of each row by the SUM of this column).
qryDecisionCriteria
name relative_weight absolute_weight (calculated)
price 2 50 %
quality 1 25 %
experience 1 25 %
I would like to present the query result in a form, where the user can update the relative weights, and then sees the absolute_weights.
However, the query results are not updatable, because the query involves an aggregate function.
What alternative methods or workarounds could I use, so that a user can edit relative_weights and view absolute_weights as a kind of visual feedback?
I read about temporary tables here http://www.fmsinc.com/MicrosoftAccess/query/non-updateable/index.html but I'm not sure, how to implement this.
Maybe I could also create an additional "edit form" based on a simple query, that is automatically invoked when the user selects a record in qryDecisionCriteria data?
Or maybe just display data from two queries (one updatable, one with the calculated field) next to each other in the form?
Which options would you recommend and why?
Make the Record Source for the form the updatable base query. In the text box which shows the calculated absolute weight set the control source to
=DSum("relative_weight","<base table name>")/Forms!<Form Name>!relative_weight
You'll need to be sure that you do two things with this
When you drag fields onto a form in Access it makes the name of the control the same as the control source column. this is really annoying and can cause a lot of headaches. Rename your control to something like txtColumnName. That way Forms!<Form Name>!relative_weight is guaranteed to reference the field and not the textbox.
in the AfterChange event for the relative_weight textbox you should add an event handler in which the following code is run
txtabsolute_weight.Requery
This will make sure the formula is recalculated whenever someone changes a weight. Otherwise they need to hit F5.
So I have a form that I want the user to use to update multiple tables with. I do not want the form to be bound to the tables, as I would rather do this with VBA (I think, I don't know).
So here is a little table example
UserTable
UserID
First
Middle
Last
Division
Title
EquipTable
EquipID
AssignedLaptop
Model
Barcode
SoftTable
SoftID
SoftwareName
License#
Custom (running sum to calculate how many licenses are left....another question)
ExchangeTable
UserID
SoftID
EquipID
So that is how I set the tables up. All these text/cmb boxes exist on one table, and I would like to be able to save this data from this one form to all relative tables with a button click.
So can anyone help me with the following:
If I have this unbound form populate after a Create New button click, how then can I tell hidden text boxes (that ideally are to contain the " "ID numbers), to populate new ID numbers (auto-numbers), for each of the tables, in them, so that I can assign an UPDATE SQL statement to a SAVE button click, in the VB to save the data?
Could I set it up so that I just the "exchange table" (no idea why i named it that) populates the ID numbers for the other tables, instead of visa versa?
Am I going about this the wrong way
EDIT:
I was just trying to give you an example to see if what I was trying to do is possible with multiple tables (ultimately multiple Keys) on one form, and if so how does it differ from doing it with one form/table: I use the unbound approach alot because of the forms I have to build, and the need to constantly pas parameters from one form to the next in the VBA. I think it is faster to code it myself? So for this concept I always have a hidden text box on the form that usually has the IDnumber of the relative table. So to click save would just require a simple SQL = * WHERE Tbl_ID = frmID kinda idea.
All I was wondering were these questions?
When you run an INSERT, does the ID number need to be present in the STATEMENT or will access just assign the next relative one for you when you execute?
If not
Considering the method above, how can i determine this number (ID I need to use) myself, with code?
Another question? How do you defeat the mouse wheel scroll through records function on a bound form?
I see what you are saying, wording was strange on this but I do see where you are goign with this.
This is what you have:
You have an unbound form that is not linked to any table
This unbound form that is in no way linked to any table will be designed by you by adding some text boxes and also combo boxes and buttons
Within these textboxes you have some textboxes that are going to store the ID (The key value) of the row. So that when you do a save the ID number is set back to the text box
Once the ID number is set to this hidden field you can then issue updates to all tables that need this ID number
Does that sound right? If so it is very simple. All you have to do is once you click the "Create Button" perform the insert, something to this effect:
' Command to Insert Records.
Dim cmdInsert As New OleDbCommand()
cmdInsert.CommandText = "INSERT INTO AutoIncrementTest (Description) VALUES (?)"
cmdInsert.Connection = cnJetDB
cmdInsert.Parameters.Add(New OleDbParameter("Description", OleDbType.VarChar, 40, "Description"))
oleDa.InsertCommand = cmdInsert
Then you issue another command to grab the IDENTITY back, namely your ID:
' Create another command to get IDENTITY value.
cmdGetIdentity = New OleDbCommand()
cmdGetIdentity.CommandText = "SELECT ##IDENTITY"
cmdGetIdentity.Connection = cnJetDB
You can always get an identity with SELECT ##IDENTITY
So in your code behind you set the textbox to the value of SELECT ##IDENTITY.
I haven't done access in over 5 years but I remember doing something like this. Once you have this identity you place it in your hidden text box. This will help you perform your UPDATES that use this identity.
Here is a good place to start: http://support.microsoft.com/kb/815629
Here is another great article that may help you: http://support.microsoft.com/kb/815629
I have come across the problem of generating complex access reports (by complex I mean with data processing, variable number of fields, among others).
Let me explain in deeper detail some of the things I need to implement:
Some fields should not show according to some values in a query
If a certain record does not exist, a nice colored (very noticeable) message should appear instead of the values that would be there (Suppose, for example, that a record with 03/04/2009 in the date field exists, a record with 03/06/2009 in the date field also exists but no record with 03/05/2009 exists. Before showing the data related to the last record, I should print something like "Didn't show up on 03/05/2009")
A bar chart that takes as data not the values in the records, but instead something else that is calculated over a set of records (like an average of all grades for a certain date). The number of series in this chart also varies according to values in the records, this chart would not be in the detail section, but instead in the page heading or some kind of group heading.
It should also be mentioned that the query is a TRANSFORM query (more precisely, an INNER JOIN of many TRANSFORM queries), and thus the number of columns returned by the query varies. While in the past I've been unable to bind this query as the recordsource for the report, somehow Access stopped complaining for now (can someone please clarify this? Is this normal, should I not worry about it and use it as a recordsource or should I avoid it?)
There are two options to achieve what I want (that I can see for now):
Create a report with no record source and lots of unbound fields, and through several events (Report_Open, Section_Format, etc.) and with the help of DAO, manually set the values of these fields. Changing the Data Series of the chart is also possible through VBA.
Set the record source to the query, and create some crazy and confusing VBA code to deal with the data and implement everything I need.
It seems to me that option 2 is going to be a huge headache and waste of time, and I recognize option 1 is pretty much like writing to an Excel file (since all the data is obtained with DAO), which would be much easier since I have much more control over almost everything there (but for many other reasons, we want everything in an access report)
While I'm biased and intend to go with option 1, I have found several problems with this option, for example:
I can't find a way to create new pages in the report with VBA, and thus I'm limited only to the first page.
Lack of some kind of free, online, decent and complete documentation on VBA and Access Reports
Also, if option 2 is more viable, I'm certainly willing to go with it, but I would also need some advice, and perhaps some tips to solving the problems I mentioned in this question.
So, the questions are:
Where can I find some decent and complete documentation on Access Reports and VBA?
How can I create pages in an access report, and choose which page I want to write to?
With the problem I have in my hands, will I reach any bottlenecks I should know about? Should I already be thinking of alternatives to Access Reports (writing to a spreadsheet, for example?)
Sounds like you want to dynamically create the report and avoid all the dummy text boxes.
In regard to:
I can't find a way to create new pages
in the report with VBA, and thus I'm
limited only to the first page.
Your solution #1 seems to assume an unbound report.
I think what I'd do is have the form the crosstab as the rowsource, so you'd have records to generate the pages, and then define your report's controls with no ControlSource (except for the controls that are bound to fields that are always present in the CrossTab). Then you could assign the ControlSources at runtime based on the particular columns. Here's the SQL for a crosstab grabbed from an app I'm working on now:
TRANSFORM First(impNoMatch.PersonID) AS FirstOfPersonID
SELECT impNoMatch.LastName, impNoMatch.FirstBame
FROM impNoMatch
GROUP BY impNoMatch.LastName, impNoMatch.FirstName
PIVOT impNoMatch.Status;
Now, you know that the fields in the SELECT clause will always be present, so if you opened a recordset on the SQL string you are using and count the number of fields in the recordset's Fields collection (you can't use the report's Recordset unless it's an ADO recordset, i.e., not bound to the Recordsource):
Dim strSQL As String
Dim rsFields As DAO.Recordset
Dim lngFieldCount As Long
strSQL = Me.Recordsource
Set rsFields = CurrentDB.OpenRecordset(strSQL)
lngFieldCount = rsFields.Fields.Count
From that, since you know the number of fields in the SELECT statement (i.e., the row headings), you can calculate the number of dynamic controls you want to assign, and you can use this recordset's fields collection to assign the ControlSources and unhide the controls.
You'd start out with all your controls that will display the dynamic fields set so their Visible property is FALSE. You'd also use a naming convention for those controls. In the code below, I've used txtNN, where NN is the numeric index in the Fields collection formatted as 2 digits. Here's the code (which adds lines to what's listed above, and is run in the OnOpen event):
Dim strSQL As String
Dim rsFields As DAO.Recordset
Dim lngFieldCount As Long
Dim l As Long
Dim strControlName As String
strSQL = Me.RecordSource
Set rsFields = CurrentDb.OpenRecordset(strSQL)
lngFieldCount = rsFields.Fields.Count
For l = 2 To lngFieldCount - 1
strControlName = "txt" & Format(l, "00")
Me(strControlName).ControlSource = rsFields.Fields(l).Name
Me(strControlName).Visible = True
Next l
rsFields.Close
Set rsFields = Nothing
Now, if you want to get fancy, you can reformat the controls, changing widths and horizontal/vertical position. If you do that, you have to do it in a different event, and it's a bit tricky to choose that. The only good place to put it is in a report group's header's OnFormat event. If you don't have any grouping, you can add one that doesn't do anything. In the case of my crosstab, a two-level sort on Lastname and Firstname and a header on the Firstname group with nothing in it is a good place to use the OnFormat event to change the appearance/layout of the controls on your report.
As to your question about how to learn how to do this, I recommend picking up an intermediate/advance Access programming book. The Access Developers Handbook is the gold standard on this, and includes tons of examples of programmatic control of reports.