Customizing the Report Execution |
To bring up this dialog, click the Advanced button in Step 2 of the Quick Report or Label Wizards or Step 3 of the Cross-Tabulation or Chart Wizards. Some of the steps in this wizard have a text box where you can enter the desired code, a Test Syntax button you can click to test whether the code is correct, and an Expression button that displays the Expression Builder to help enter field names or other expressions. In addition, you can right-click the text box and choose Zoom from the shortcut menu to display a larger editing window with complete syntax coloring and IntelliSense on Stonefield Query commands and functions.
Note that the first two steps are the only ones available unless you are defined as an "advanced" user in the Maintain Users and Groups dialog. Also, the second step is only available if the report includes fields from more than one table.
Step 1 allows you to specify some advanced settings for this report. The options available in this step are:
The DISTINCT clause in a SQL statement tells the database to only find records that have distinct values, so adding that clause to the SQL statement means that Sam's Grocery will only show up once. The Add DISTINCT to SQL statement option allows you to control whether the DISTINCT clause is used or not. No means don't add a DISTINCT clause to the SQL statement for this report and Yes means do add it. When filtering on a table not included in the fields list means only add the DISTINCT clause if you filter on a field from a table that isn't involved in the report.
You might think that When filtering on a table not included in the fields list should always be used. However, there may be times when this isn't the correct behavior. For example, if you want to show fields from the Orders table (Order Date, Product Name, and Quantity Ordered) but filter on Company Name is "Sam's Grocery," Stonefield Query eliminates what it thinks are duplicate records, such as two orders for the same product and same quantity on the same day. Clearly, this isn't right—you'd end up with some missing data. In that case, set this option to No.
Step 2 allows you to change the relationship between tables. This step is only available if the report includes fields from more than one table. Select a table from the list and then select how it's related to the first table. Note that the first table used in the report isn't listed, because the relationships start with the second table. For example, if the first field in the report is from Order Details, that table isn't included in the list.
The sample image shows an example of how the selected relationship will work. The sample is based on one table having records A, B, C and the other table having records A, C, and D. This means there's a match for records A and C but none for B or D.
The types of relationships you can specify are (in these relationships, Table2 refers to the selected table and Table1 refers to the first table in the report):
Use Step 3 to customize the SQL statement for the report. This step shows the SQL statement Stonefield Query sends to the database engine. You can add additional fields to the SQL statement (although they won't appear in the report unless you add them yourself in the Advanced Report Designer because they aren't automatically added to the report layout), add a subquery, or add WHERE or HAVING clauses (note that Stonefield Query automatically adds the filter specified for the report to the SQL statement). Although you can also edit the relationships between tables in this step, it's better to use Step 2 to do so. Don't remove any fields or change field names or you will get an error message when Stonefield Query tries to output the fields it expects to find in the data set to the report layout.
As mentioned, Stonefield Query automatically adds the filter specified for the report to the SQL statement. It does this by finding the WHERE clause in the statement and ANDing the filter condition with the existing conditions. If there is no WHERE clause, one is added. While this works for many types of SQL statements, complex statements with subqueries may cause a problem. For example, consider this SQL statement:
select SomeField, (select SomeOtherField from SomeOtherTable where SomeCondition) as SomeOtherField from SomeTable
Although the main SQL statement doesn't have a WHERE clause, the subquery does. This can confuse Stonefield Query and as a result, it may add the filter for the report to the WHERE clause of the subquery, which is incorrect. To precisely specify where the filter should be added, use a text merge expression (one surrounded with "{" and "}") with "UserFilter" as a placeholder for the filter condition. For example:
select SomeField,
(select SomeOtherField from SomeOtherTable where SomeCondition) as SomeOtherField
from SomeTable {'where ' + UserFilter}In addition to allowing you to specify where the filter condition is added, it gives you flexibility in how it's added. For example, consider this SQL statement:
select SomeField,
(select SomeOtherField from SomeOtherTable
where SomeOtherTable.SomeField = A.SomeField) as SomeOtherField
from SomeTable AIn this case, SomeTable is aliased as A. The problem is that when Stonefield Query adds the filter with a condition involving a field from SomeTable, it doesn't know the table needs to be aliased, resulting in:
select SomeField,
(select SomeOtherField from SomeOtherTable
where SomeOtherTable.SomeField = A.SomeField) as SomeOtherField
from SomeTable A where SomeTable.SomeField = SomeValueThis fails because the filter condition should be A.SomeField = SomeValue. In this case, use a text merge expression that converts any instance of the table name to the aliased name:
select SomeField,
(select SomeOtherField from SomeOtherTable
where SomeOtherTable.SomeField = A.SomeField) as SomeOtherField
from SomeTable A
{iif(empty(UserFilter), '', 'where ' +
strtran(UserFilter, 'SomeTable', 'A', -1, -1, 1))}The test for EMPTY(UserFilter) is there so no WHERE clause is added if there is no filter (for example, if all of the conditions are ask-at-runtime but the user turned on the Ignore this condition option for all of them in the ask-at-runtime dialog). The STRTRAN() function changes the specified expression (in this case, UserFilter, which contains the filter) so that "SomeTable" is converted to "A" (the two "-1" parameters indicate that all instances should be changed and the final "1" parameter means case-insensitive, so "SOMETABLE" and "sometable" are also converted).
If you want to reset the SQL statement back to its default after you've changed it, click the Reset button.
Any code you enter in the Specify OnSelect Code step is executed when the report is selected in the Reports Explorer. An example is setting the default output of a report to a certain file. Say you want a particular report sent to an Excel file called SALES.XLS by default. The following code accomplishes that:
loReport.SetOutputToFile('SALES.XLS')The variable loReport contains a reference to the selected report object so your code can access properties and methods of this object as necessary. See the Report Objects topic for details on this object.
If you want code executed after a report has been run, such as to notify another application or to log the report run to a file, enter the desired code in the Specify AfterRun Code step. Here's an example that adds a new entry to the end of a text file, indicating when a report was run and who ran it.
lcText = 'Report ' + loReport.cReportName + ; ' was run on ' + ttoc(datetime()) + ' by ' + loReport.cUserName + ; chr(13) + chr(10) strtofile(lcText, 'C:\REPORTLOG.TXT', .T.)
Here's an example that changes the delimiter for CSV files from a comma to a pipe character (|) and recreates the output file:
loReport.oOutput.cDelimiter = '|' loReport.oOutput.CreateFile()
In the Specify BeforeData Code step, you can enter code you want executed before data is retrieved from the database engine. You can use this code to pre-create some data or open a different set of tables as necessary.
Sometimes, a report needs a result set that's more complex than the one created by the SQL statement generated by Stonefield Query. For example, perhaps the report needs certain sums or averages calculated. Use the Specify AfterData Code step of the Customize Report Wizard to specify code you want executed after the data has been retrieved from the database engine but before it's output to the report layout.
A variable called ResultSet contains the name of the result set retrieved for the report. You can use this to further manipulate the result set. For example, suppose you have a summary report showing customer name from the Customers table (which is grouped) and Total Sale Amount from the Orders table (which is summed). Because it's a summary report, it just shows the total sales for each customer. However, you only want those customers whose total sales are more than $10,000. The problem is that you can't filter on Total Sale Amount is greater than $10,000 because that only finds records where each individual sale is more than $10,000, not the total of all sales for a customer. The following code prompts the user for the value they want to filter on, then pulls from the original result set only those customers with a total more than that value:
lnValue = GetValueForField('Orders.Total', 'greater than')
if not isnull(lnValue)
select * from (ResultSet) where Total >= lnValue into cursor NewResults
endifThe parentheses around ResultSet are required since the name of the result set is stored in the variable called ResultSet.
Note that the result set you create must have the exact same field names the original result set had (it can contain more fields if desired) because that's the structure the rest of the reporting process expects to work with.