Creating subreports

In the simplest case, the subreport capability of JasperReports allows you to print associated data for each line item in a report—from the same table, from another table in the same database, or from another data source altogether. More complex cases are beyond the scope of this topic, and you should refer to JasperReports documentation for such information.

In complex cases you will probably need a report handler to provide data for the subreport; see Creating an EGL report handler. In some simple cases, you can add a subreport in two simple steps:
  1. Add subreport code to the design file for the main report.
  2. Create one or more design files for the subreport(s).
Here is an elementary example of how you might do this. Given a report that prints all the customers from the table CUSTOMER, you can add a subreport that shows all invoices for each customer, drawn from the table ORDERS.
  1. This is a section of code from the main report design file. This code was originally written to print one line for each customer in the table CUSTOMER. Add the code shown in bold in the following example:
    	<queryString><![CDATA[SELECT * FROM ADMINISTRATOR.CUSTOMER]]></queryString>
    	<field name="CUST_NO" class="java.lang.Integer">
    	</field>
    	<field name="CUST_NAME" class="java.lang.String">
    	</field>
    	<detail>
    		<band height="100">
    			<subreport>
    				<reportElement positionType="Float" mode="Opaque" x="0" y="31" width="709" height="12" isRemoveLineWhenBlank="true"/>
    				<subreportParameter name="CURRENT_CUST">
    					<subreportParameterExpression><![CDATA[$F{CUST_NO}]]></subreportParameterExpression>
    				</subreportParameter>
    				<connectionExpression>
    					<![CDATA[$P{REPORT_CONNECTION}]]>
    				</connectionExpression>
    				<subreportExpression class="java.lang.String"><![CDATA[new String("C:\\workspace\\report_project\\bin\\report_package\\my_subreport.jasper")]]></subreportExpression>
    			</subreport>
    			<textField>
    				<reportElement positionType="Float" x="57" y="11" width="304" height="20"/>
    				<textElement/>
    				<textFieldExpression class="java.lang.String"><![CDATA[$F{CUST_NO} + " " +  $F{CUST_NAME}]]></textFieldExpression>
    			</textField>
    		</band>
    	</detail>
    The <subreport> tag gives JasperReports the information it needs to run the subreport:
    • positioning information (the same parameter you will find in the main report)
    • parameters you wish to pass to the subreport—in this case, the number of the current customer, which you will need in the SQL SELECT statement in the subreport
    • connection information, because the report driver for this report specifies a data source of DataSource.databaseConnection
    • the location of a compiled report design file for the subreport—in this case, my_subreport.jasper
  2. The subreport design file is not different in kind than any other .jasper design file. Include the following crucial code in that file:
    <parameter name="CURRENT_CUST" class="java.lang.Integer"/>
    	<queryString><![CDATA[SELECT * FROM ADMINISTRATOR.ORDERS WHERE CUST_NO = $P{CURRENT_CUST}]]></queryString>
    	<field name="CUST_NO" class="java.lang.Integer">
    	</field>
    	<field name="INVOICE_NO" class="java.lang.Integer">
    	</field>
    	<field name="ORDER_TOTAL" class="java.lang.Float">
    	</field>
    	<detail>
    		<band height="100">
    			<textField>
    				<reportElement positionType="Float" x="50" y="10" width="300" height="20"/>
    				<textElement/>
    				<textFieldExpression class="java.lang.String"><![CDATA["Invoice # " + $F{INVOICE_NO} + " total: " +  $F{ORDER_TOTAL}]]></textFieldExpression>
    			</textField>
    		</band>
    	</detail>
    Even though you passed the parameter CURRENT_CUST to the subreport, you must tell the report what type the parameter is, using the class= attribute of the <parameter> tag. Next comes the query string (JasperReports is very particular about the order of the tags within the file). Here you reference the value of CURRENT_CUST as $P{CURRENT_CUST}. The field names refer to column names in the ORDERS table, which you can then reference inside the <textFieldExpression> tag.

These are the only changes you need to make to add a subreport; you do not need to change any code in the EGL report driver program. If you wish to include other sources of data or complex calculations, however, you will need to create a report handler (see Creating an EGL report handler).

You can create nested subreports. For example, you might call up line items for each invoice from a third table. This would involve adding the information within a <subreport> tag to the subreport file my_subreport.jasper, and creating a separate design file for the nested subreport (you might call it my_invoice_subreport.jasper). There is no limit to the depth to which you can nest subreports.

Related Tasks
Creating an EGL report handler
Creating the report design file

Related Reference
EGL report handler

Feedback
(C) Copyright IBM Corporation 2000, 2005. All Rights Reserved.