Evaluation Time Defaults
Chapter 1 discussed the Two-Pass Report Processing model. Knowing how this model works is especially important when writing formulas. The type of formula determines when it is processed. Where you place a formula on a report and the functionality within that formula also affects when the formula is evaluated and whether it returns the expected value or not. A formula can be placed on any section of your report, but you should plan this in advance so that you can guarantee the proper results. To determine where to place a formula, you need to know the rules that Crystal Reports uses to evaluate functions. The following list shows the rules that are applied.
- A formula that only references variables (it doesn’t use database fields or group/summary fields) is evaluated before any records are read. It is only evaluated one time and its value is saved for the duration of the report.
- Formulas using database fields are evaluated while records are being read. It is re-evaluated every time a new record is read from the data source.
- Formulas using group fields, summary fields, or page related fields (e.g. the page number) are evaluated after the records are read and while the report is being printed.
- When there are multiple formulas within a section, you can’t determine which formula will be called first. This is because formulas within the same section are not evaluated in any particular order. The exception to this rule is in the next bullet point.
- Crystal Reports does evaluate formulas based upon the order that they were added to the section. As you add formulas to the section, Crystal Reports adds each formula to an ‘internal list’ and processes each formula based upon its order in the list. The problem with putting this into practical use is that you have no way of knowing which formula was added first. Unless you have a photographic memory of when you added every formula to every section, it’s impossible to use this rule on a regular basis. If you only have two formulas in a section then you could use this rule, but anything more than that and you start leaving a lot to chance.
There are times when the default rules listed above will not give you the results you desire. For example, there may be a situation where you have four formulas in the same section and two formulas rely upon one other to be called first. According to the default rules listed above, you know that there it is difficult to determine which one will be called first. You need some way to force one formula to be called before the other. Fortunately, Crystal Reports lets you override the default rules to fit your particular situation. There are four keywords that let you set when a formula will be evaluated: BeforePrintingRecords, WhileReadingRecords, WhilePrintingRecords, and EvaluateAfter. The keyword is added to the beginning of a formula to force it to be evaluated at a time that is different than its default behavior. These keywords are listed in Table 7-5.
Table 7-5. Evaluation Time Keywords
Evaluation Time | Description |
---|---|
BeforeReadingRecords | Evaluate the formula before any database records are read. |
WhileReadingRecords | Evaluate the formula while reading the database records. |
WhilePrintingRecords | Evaluate the formula while printing the database records. |
EvaluateAfter(formula) | Evaluate after another function has been evaluated. |
If a formula isn’t returning the expected results and you debugged the logic enough to feel confident about it, there is a good chance it’s because of when the formula is being evaluated. If you are trying to debug a formula, then you have to take many things into consideration: does the formula only use variables; should the formula be put in a different section; is the formula being evaluated while reading records or while printing records; does the report use a grouping section that may be effecting the order of evaluation? This is a lot to think about.
You can cut down on the amount of time spent debugging formulas if you start out by following some general guidelines. The remainder of this section gives guidelines and examples to consider when writing your formulas. If you’re having problems getting a formula to work, then you should come back to this section as a refresher and see if any of these guidelines would help you.
Place formulas that reset variables to their default value in the Report Header, Page Header or Group Header section. This insures that they are called before the formulas in the detail section are evaluated. For example, if you have a variable that prints the row number on a page and you want the first row on each page to be 1, then reset the variable in the Page Header. If a variable sums data within a single group, reset the variable in the Group Header section so that it gets reset with each new group printed.
Be careful when using formulas that only have variables in them without any database fields. They only get calculated one time prior to reading the records. If the formula is cumulative in nature, you need to force the evaluation time to be WhileReadingRecords. If the report uses groups, then you should use the WhilePrintingRecords keyword.
The keyword BeforeReadingRecords can’t be used with formulas that have database fields or grouping/summary fields in them.
When you place multiple formulas within the same section, you can’t assume the order that they are executed in. If you need one formula to be evaluated before another formula (its result is used in other formulas) then put the EvaluateAfter keyword in the dependent formula. The following example shows how this is used. This formula relies upon the formula ParseName to take the {Customer.Name} field and parse the first name and last name out of it. The values are put into the global variables FirstName and LastName. This example formula returns the LastName variable so that it can be displayed on the report. The @ParseName formula isn’t shown here.
Summary calculations are performed while printing records. They can only do calculations on formulas that were evaluated beforehand (i.e. while reading records). Thus, a formula that uses WhilePrintingRecords can’t have summary functions performed on it.
Of course, these guidelines won’t be able to prevent every problem from happening, but they are here to help give you a start in the right direction.