Search code examples
jasper-reports

Is it possible to make a custom sorting (not ascending or descending) with help of engine?


I have a data to be sorted, but it should be a custom sorting defined by mine rules.

For example I need to print values in this order:

B 
C
A
D

It is not an ascending or descending sorting.

Is it possible to do this?


Solution

  • First of all, it is possible to make sorting via JasperReports engine (without help of query language, for example SQL).

    This can be done with help of sortField attribute of main dataset or subDataset.

    The sample of report without sorting

    The jrxml for report without sorting:

    <?xml version="1.0" encoding="UTF-8"?>
    <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="Non sorted data" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20">
        <property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
        <subDataset name="ds">
            <field name="value" class="java.lang.String">
                <fieldDescription><![CDATA[_THIS]]></fieldDescription>
            </field>
        </subDataset>
        <summary>
            <band height="15">
                <componentElement>
                    <reportElement x="0" y="0" width="311" height="15"/>
                    <jr:list xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" printOrder="Vertical">
                        <datasetRun subDataset="ds">
                            <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource(Arrays.asList("def", "jkl", "abc", "ghi"))]]></dataSourceExpression>
                        </datasetRun>
                        <jr:listContents height="15" width="311">
                            <textField>
                                <reportElement x="0" y="0" width="311" height="15"/>
                                <textFieldExpression><![CDATA[$F{value}]]></textFieldExpression>
                            </textField>
                        </jr:listContents>
                    </jr:list>
                </componentElement>
            </band>
        </summary>
    </jasperReport>
    

    The result in Jaspersoft Studio (JSS) will be:

    Non sorted data

    After adding sorting with help of sortField the template will be:

    <?xml version="1.0" encoding="UTF-8"?>
    <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="Sorted data" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20">
        <property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
        <subDataset name="ds">
            <field name="value" class="java.lang.String">
                <fieldDescription><![CDATA[_THIS]]></fieldDescription>
            </field>
            <sortField name="value"/>
        </subDataset>
        <summary>
            <band height="15">
                <componentElement>
                    <reportElement x="0" y="0" width="311" height="15"/>
                    <jr:list xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" printOrder="Vertical">
                        <datasetRun subDataset="ds">
                            <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource(Arrays.asList("def", "jkl", "abc", "ghi"))]]></dataSourceExpression>
                        </datasetRun>
                        <jr:listContents height="15" width="311">
                            <textField>
                                <reportElement x="0" y="0" width="311" height="15"/>
                                <textFieldExpression><![CDATA[$F{value}]]></textFieldExpression>
                            </textField>
                        </jr:listContents>
                    </jr:list>
                </componentElement>
            </band>
        </summary>
    </jasperReport>
    

    and the result in JSS:

    The sorted data

    The custom sorting can be implemented in several ways

    1. Using sortField attribute

    The sortField attribute may deal not only with fields, but also with variables. If it possible, we can move the sorting logic here (to variable).

    The simple example:

    <?xml version="1.0" encoding="UTF-8"?>
    <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="Data with custom sorting" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20">
        <property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
        <subDataset name="ds">
            <field name="value" class="java.lang.String">
                <fieldDescription><![CDATA[_THIS]]></fieldDescription>
            </field>
            <sortField name="valueForSorting" type="Variable"/>
            <variable name="valueForSorting" class="java.lang.Integer">
                <variableExpression><![CDATA["a".equalsIgnoreCase($F{value}) ? 3 :  "b".equalsIgnoreCase($F{value}) ? 1 : "c".equalsIgnoreCase($F{value}) ? 2 : "d".equalsIgnoreCase($F{value}) ? 4 : 0]]></variableExpression>
            </variable>
        </subDataset>
        <summary>
            <band height="15">
                <componentElement>
                    <reportElement x="0" y="0" width="311" height="15"/>
                    <jr:list xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" printOrder="Vertical">
                        <datasetRun subDataset="ds">
                            <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource(Arrays.asList("d", "c", "b", "a"))]]></dataSourceExpression>
                        </datasetRun>
                        <jr:listContents height="15" width="311">
                            <textField>
                                <reportElement x="0" y="0" width="311" height="15"/>
                                <textFieldExpression><![CDATA[$F{value}]]></textFieldExpression>
                            </textField>
                        </jr:listContents>
                    </jr:list>
                </componentElement>
            </band>
        </summary>
    </jasperReport>
    

    The result in JSS will be:

    The custom sorted data

    2. Using query tricks

    In some cases using CASE operator can help us to sort data like we want.

    For example:

    SELECT value,
      CASE
        WHEN value = 'a' THEN 3
        WHEN value = 'b' THEN 1
        WHEN value = 'c' THEN 2
        WHEN value = 'd' THEN 4
        ELSE 0
        END AS valueForSorting
    FROM someTable
    

    3. Custom datasources

    The using custom datasource is another way to sort data. We can sort data in Java code and then pass datasource to the report.

    4. Using crosstab

    The crosstab component is using mechanism of sorting data - we can set the custom behaviour for sorting.