Crosstab i Dataset użytkownika w Jasper Reports

23 sierpnia 2009 | 1 komentarze

Natrafiłem na banalny z pozoru problem w iReport: jak w prosty sposób poza głównym zapytaniem odczytać coś z DB i wyświetlić w raporcie, np. w sekcji nagłówka? Założenie: id rekordu jest stałe albo przekazywane jako parametr zewnętrzny.

Najłatwiej byłoby oczywiście dodać podzapytanie w głównym query, ale komplikowanie mocno rozbudowanego sql'a to zły pomysł - wydajnościowo i (nie)higienicznie. Raport podrzędny też odpada - armata na komara. Pozostaje użycie dedykowanego Dataset przez wstawienie tabelki krzyżowej.

Crosstabs to niewdzięczne struktury. Moj iReport (3.5.3) kompletnie sobie z nimi nie radzi - próby wstawienia tabeli krzyżowej z palety kończą się szybkim pożegnaniem z GUI NetBeans bez zapisania zmian i komunikatu o błędzie. Pozostaje edycja źródeł raportu w XML'u, ale po kolei.

Poniżej załączam przepis na wstawienie do dowolnej sekcji raportu pola odczytanego dedykowanym zapytaniem sql. Ważne jest takie zgrupowanie kolumn i wierszy w Crosstab, żeby została widoczna tylko jedna komórka sekcji Detail, bez nagłówków i sum. Oczywiście podany kod trzeba dopasowac do swoich potrzeb (zapytanie, wielkość elementów, itd).

Krok 1. Do raportu dodać nowy Dataset - "Add Dataset" z menu kontekstowego po kliknięciu na nazwę raportu. Dodać parametr. Typ parametru musi być zgodny z id rekordu i parametrem zewnętrznym raportu.


Krok 2. Wpisać sparametryzowane zapytanie do Dataset.


Krok 3. Wstawić Crosstab do raportu, np. do sekcji nagłówka (z palety). Jeśli iReport nie chce współpracować - przejść do następnego punktu (wkleić XML).


Krok 4. Wyciąć nagłówki i stopki kolumn i wierszy tabeli. W edytorze tabeli powinna zostać widoczna tylko jedna komórka sekcji Detail typu String (w sekcji Measures pole ma Value Expression=$F{number}). Jako bucket expression (wyrażenie grupujące) w Row Groups i Column Groups wpisać stały tekst, np. "a".


Jeśli przy edycji tabeli iReport odmawia współpracy, wkleić gotowy szablon kodu do żródła XML raportu.

<crosstab isRepeatColumnHeaders="false" isRepeatRowHeaders="false" columnBreakOffset="0">
    <reportElement x="60" y="14" width="200" height="14"/>
    <crosstabParameter name="orderId" class="java.lang.Long"/>
    <rowGroup name="row" width="0">
        <bucket>
            <bucketExpression class="java.lang.String"><![CDATA["a"]]></bucketExpression>
        </bucket>
        <crosstabRowHeader>
            <cellContents/>
        </crosstabRowHeader>
        <crosstabTotalRowHeader>
            <cellContents/>
        </crosstabTotalRowHeader>
    </rowGroup>
    <columnGroup name="col" height="0">
        <bucket>
            <bucketExpression class="java.lang.String"><![CDATA["a"]]></bucketExpression>
        </bucket>
        <crosstabColumnHeader>
            <cellContents/>
        </crosstabColumnHeader>
        <crosstabTotalColumnHeader>
            <cellContents/>
        </crosstabTotalColumnHeader>
    </columnGroup>
    <measure name="orderNumber" class="java.lang.Object">
        <measureExpression><![CDATA[$F{number}]]></measureExpression>
    </measure>
    <crosstabCell width="237" height="25">
        <cellContents>
            <textField>
                <reportElement style="Crosstab Data Text" x="0" y="0" width="237" height="14"/>
                <textElement textAlignment="Left">
                    <font isBold="true"/>
                </textElement>
                <textFieldExpression class="java.lang.String"><![CDATA[""+$V{orderNumber}]]></textFieldExpression>
            </textField>
        </cellContents>
    </crosstabCell>
</crosstab>

Krok 5. Przypisać nazwę Dataset do tabeli. Zrobić mapowanie wartości parametru raportu na Dataset.


Krok 6. Jeśli nie istnieje, wstawić pole tekstowe do sekcji Detail tabeli i przypisać zmienną typu String (Text Field Expression=$V{orderNumber}).



I to byłoby na tyle. Wszelkie uwagi są mile widziane. :)

1 komentarze:

delete Anonimowy 5 stycznia 2010 14:26

dokładnie tego szukałem:)