This is the kind of thing I feel I should already know, but don't...
In MS Access, if a query consists of n calculated fields (say calc_1, calc_2, .... calc_n) but I only want to use a subset of them in a particular form or report - say calc_x, calc_y and calc_z - would Access calculate all n calculations when running SELECT calc_x, calc_y, calc_z FROM myquery and then return the ones I want, or would it be smart enough to only calculate calc_x, calc_y and calc_z?
In my case I'm using Access 2003 but presumably the answer is the same for all versions.
Access is smart and don't calculate not-visible fields.
Tried with Access 2003
Like #David, I did not believe #Andreas's answer at first. So I tested it myself as follows. I created the following function:
Function Watch(Val, Optional CalledFrom As String = "")
Debug.Print Val, CalledFrom
Watch = Val
End Function
Then I created a table named "Dummy" with a single field named "ID". I created a form and used the following as the form's RecordSource:
SELECT Watch([ID],"ShowInForm") AS ShowInForm,
Watch([ID],"HideFromForm") AS HideFromForm
FROM Dummy;
I added a single textbox control with a ControlSource of ShowInForm.
I then opened the form and got this in the immediate window:
1 ShowInForm
1 ShowInForm
1 ShowInForm
I then went back to the RecordSource and previewed it in Datasheet view and got this:
1 ShowInForm
1 HideFromForm
I'm not sure why the "ShowInForm" expression is evaluated three times in the form, but it seems pretty clear that the unused field, "HideFromForm", does not get evaluated.
To address #HansUp's comment, I went back and saved a query named "Qry":
SELECT Watch([ID],"ShowInForm") AS ShowInForm,
Watch([ID],"HideFromForm") AS HideFromForm
FROM Dummy;
Then changed the form RecordSource to:
Select ShowInForm FROM Qry
This produced the same result as before when I opened the form (ie, 3 lines of 1 ShowInForm). Interestingly, when I opened the RecordSource in datasheet view I got this:
1 ShowInForm
1 ShowInForm
In other words, it evaluated the ShowInForm field twice. Presumably, once in "Qry" and again in the RecordSource query.
The end result is still a confirmation of #Andreas's answer.
If you include the calculated fields in the SELECT clause of your report or form's recordsource, it will calculate them for each row AS IT IS RETRIEVED.
If you leave them out of the SELECT and include the calculations only in the ControlSource properties of controls on your report/form, then what you say is true.
Also, if you do any sorting/grouping on the calculations or put criteria on them, all rows will be calculated.
Thus, in this recordsource:
SELECT Field1/Field2 As Ratio1, Field3/Field4 As Ratio2, FIeld1, Field2, Field3, Field4
FROM MyTable;
...for each row that is retrieved, both calculations will be executed regardless of whether or not the result is used in the form or report.
If you want to delay calculations to the last possible moment, do NOT include them in the SQL recordsource, but just use them as the ControlSources of the controls that are displaying the calculations. However, this has the downside that you'll see the calculations painting onscreen in many cases.
EDIT:
It seems this may not be correct, but I feel there's something going on here that is not completely explained by #mwolfe02's answer. I'll just leave this here for further discussion.
I put calculations like this on the server side.. computed columns are awesome.
I think that Access finally got this feature in 2007, I don't know how people ever survived without it.
Related
As the subject expresses, I'm trying to sum the values of a string field where spaces may exist. It must be done this way, unfortunately.
The database is very old. The original developer chose to make all fields Text fields; to get over the null value problems, a function was written in VB6 to replace any null value with a space. This cannot be changed.
Fast forward to now, I'm trying to create a report that sums the length field without changing spaces to nulls first, and it should be done entirely through the control source property of the report.
I've added some of what I've tried below, but every time the report is run, I receive:
Data Type Mismatch
...and I'm not sure how to get around it.
Ideally, I'd like to keep the users out of the database completely, and just add a combo box that lists the reports created in the database so they can be opened by name without having to run any additional update queries first.
=Sum(IIf([MY_LEN]<>" ",DCount("[MY_LEN]","MY_TABLE"),0))
=Sum(Nz(Iif(Trim([MY_LEN])='',Null,[MY_LEN]),0))
=DSum("[MY_LEN]","[MY_TABLE]","[MY_LEN]<>' '")
=Sum(Iif(Val([MY_LEN])>0,[MY_LEN],0))
=(SELECT Sum([MY_LEN]) AS MyLen FROM MY_TABLE WHERE (((MY_TABLE.[MY_LEN])<>' ')))
Is this possible?
Can't compare anything to Null. Can't say If x = Null Then because Null is undefined. So you can't test if undefined = undefined. Use If IsNull(x) Then in VBA and Is Null in query criteria. Don't really need IIf() for Sum() aggregate, other aggregates such as Count or Avg would.
To handle possible space, empty string, or Null for a text field holding numeric data.
=Sum(Val([MY_LEN] & ""))
I have been researching on MS-Access topics around DLookup, but not being lucky on the resolution of my problem.
I have a query that solely returns one value, which is a lumpsum of credits. So I used the clause "AS TOT_CREDIT" on the query to give the unique column a name.
On access report, I learned that you can't directly set the value of a textbox from a query, but also learned the magic is to set the textbox controlsource property to dlookup, like this: dlookup([TOT_CREDIT]; [QUERY THAT CONTAINS TOT_CREDIT]). When I pull the report from access, the textbox still displays the infamous "#Name?", instead of the query value.
Is anything missing here? What else can I do in order to have the textbox display the query result?
Must use quotation marks:
DLookup("[TOT_CREDIT]"; "[QUERY THAT CONTAINS TOT_CREDIT]").
I am attempting to maintain and fix a horribly out-of-date CRM designed by an ex-employee ~4-5 years ago in Access 2007. I have brought it into Access 2013 and fixed a ton of stuff up, but I am still running into many problems.
I spent a good 4 hours today attempting to figure out why certain values didn't line up. These values were being pulled from a SELECT statement on a Combo Box over a stored Query which simply returns a table with a few extra rows. Great.
However this value (a number) doesn't appear to correlate with what we expect. I enter in one value, save the ticket, and a completely different value gets stored into the table. Opening up the ticket, I see the value that I expect. Digging deeper, I found the following difference:
Set value_1 = Me.RegistrationID // What's being stored in the table
Set value_2 = Me.RegistrationID.Column(0) // What we expect
Surprise surprise! This is a Combo Box and some value is being stored in the table. The Control Source is "RegistrationID" and the Row Source is the query in question.
However I do not know what it is! This specific value correlating to the Combo Box appears to pull the correct data when we later open the tickets. However I have a strong feeling that this could be why many tickets from before one of the rows was deleted all appear to have invalid RegistrationID's.
How badly can this break?
How easily can we correct tens of thousands of tickets?
How can I fix this to store the correct value?
This is what I expect is happening.
Your combo box row source is based on a Select query which returns and displays multiple rows. For example:
Select RegistrationID, CustomerID, CustomerName From MyTable;
The Control Source for the combo box is bound to RegistrationID which is part of the Forms Record Source.
The issue is the bound column. If we set the bound column in our example to 1, then we get the behavior your are describing with:
Set value_1 = Me.RegistrationID - Set's value to CustomerID (may appear correct)
Set value_2 = Me.RegistrationID.Column(0) - position 0 from our query (RegistrationID)
Further building on our query example, you can say:
Me.TextBox1 = Me.RegistrationID.Column(0) - RegistrationID
Me.TextBox2 = Me.RegistrationID.Column(1) - CustomerID
Me.TextBox3 = Me.RegistrationID.Column(2) - CustomerName
The RegistrationID is what normally should be stored in the table.
As long as your form shows any values that directly relate to this RegistrationID you're fine.
I would start by checking to see under the format setting to see if column widths are set properly and I would also check under the data section to see if the bound column is correct. I might also throw in an after update macro/vba sub routine that saves the record. Hope this helps.
I am trying to filter a query using a temporary variable that is inside an IN() condition. The temporary variable contains a list of text values. I am using the macro-builder tool in Access 2010.
Assume I have a query qryMain that produces:
Field1 Field2
1 A
4 B
2 C
3 D
without a WHERE clause. Using the clause
WHERE [tblMain].[Field2] IN([TempVars]![tmpField2])
to filter the query, the desired results are
Field1 Field2
1 A
4 B
when tmpField2 is set to "A,B". I set tmpField2 using an on-click event in form frmMain using SetTempVar and Requery the subform/subreport object sfrmMain that is based on qryMain. This is done via the MS macro-builder, not VBA.
Unfortunately, requerying sfrmMain produces an empty table rather than the expected results. Note that if I set tmpField2 to "A", then the requery macro works as expected.
I have tried multiple variations of initializing tmpField2, based on Access's double quote requirements, but still no success. My question is similar to this as-yet unanswered question, but my question involves passing the temp variable inside an IN() statement within the WHERE clause, without using VBA.
The problem is not actually due to TempVars. If your value list came from a form's text box instead of TempVars, the result would be the same.
For what you're attempting to do, IN () requires a hard-coded list of values:
SELECT m.Field1, m.Field2
FROM tblMain AS m
WHERE m.Field2 IN ('A','B');
But, instead of a hard-coded list of values, you want to supply the list dynamically when the query is run:
WHERE m.Field2 IN (something_dynamic);
Unfortunately, Access will not cooperate. Whatever you supply for something_dynamic, Access will interpret it to be only one value ... not a list of values. And it doesn't matter what method you use to supply something_dynamic ... a TempVar, a text box, a formal query parameter, a custom VBA function which returns a string containing a list of values ... that list will be evaluated as only a single value.
If you were willing to use VBA, you could write the query at runtime to include a hard-coded value list before executing it. Since you want to avoid VBA, you can try something like this ...
WHERE InStr(1, [TempVars]![tmpField2], "'" & m.Field2 & "'") > 0
Note that approach requires quoting text values within tmpField2: 'A','B'
Also beware that approach could be painfully slow with a large table. Access would need to evaluate that InStr expression for every row in the table.
I am attempting to have a single List Box pull up two possible values based on whether or not a Check Box is filled. The Row Source I have for the List Box is:
IIf([Forms]![frmPDPRate]![chkTrue], [qryPDPRate]![Initial], [qryPDPRate]![Renewal])
The specifics are that I'm trying to pull a rate, either Initial or Renewal, based on if [chkTrue] is true or false.
Another note: The query that the list box should be pulling from has been paired down to one row based on cascading combo boxes. So there is only one possible choice per column in the query.
EDIT:
I think I'm going about this all wrong but I don't know how to get it to do what I want at this point.
Yawar, nothing is happening when I run the form but that makes sense as I can't force the rowsource to choose between two possibilities.
I think you need the following code in VBA:
Private Sub chkTrue_AfterUpdate()
If chkTrue =TRUE then
listbox.RowSource = "SELECT Initial FROM qryPDRRate"
Else
listbox.RowSource = "SELECT Renewal FROM qryPDRRate"
End If
End Sub
I was able to use the Query Builder in the RowSource Property using an IIf statement. The RowSource Data Looks as such.
SELECT IIf([Forms]![frmPDPRate]![chkTrue],[qryPDPRate]![Initial],[qryPDPRate]![Renewal]) AS Rate FROM qryPDPRate;