Как показать колонку в Crosstab, даже если данные отсутствуют
У кого-нибудь есть подсказки, если я хочу создать столбцы кросс-таблицы из массива, а затем вставить информацию о коррекции в кросс-таблицу?
Например, у меня есть таблица, как показано ниже в моей БД:
клиент ---- активность_дата ---- активность |
customer1 ---- 01-01-2016 ---- A |
customer1 ---- 01-03-2016 ---- B |
customer2 ---- 01-01-2016 ---- A |
Когда пользователи запрашивают отчет с 16 января по 16 марта, отчет должен отображаться, как показано ниже:
клиент ---- 01-2016 ---- 02-2016 ---- 03-2016 |
customer1 ---- Количество действий: 1 ---- Количество действий: 0 ---- Количество действий: 1
customer2 ---- Счетчик активности: 1 ---- Счетчик активности: 0 ---- Счетчик активности: 0
Итого ---- Сумма активности: 2 ---- Сумма активности: 0 ---- Счет активности: 1
В настоящее время проблема заключается в том, что, поскольку в феврале 2016 года нет данных, в отчете отсутствует столбец 02-2016.
Есть ли способ (например, скриптлет) создать массив в виде столбца, а затем сообщить JasperReport о правильных данных вставки, когда activity_date == column_date?
Я использую Jaspersoft Studio.
1 ответ
Чтобы показывать даты без дат (без действий в вашем случае), вы должны передать данные из источника данных. JasperReports ничего не знает ни о каких диапазонах дат или о чем-то еще. Это просто требует данных.
Проблемы
- Первая проблема состоит в том, чтобы получить данные в диапазоне дат, даже если данные отсутствуют
- И второй - избегать показа в кросс - таблице "нулевых" данных
Решение
В случае использования БД вы можете использовать внешнее соединение и некоторый генератор дат для отображения данных.
Мы должны решить эту задачу:
Получение списка всех дат (дней) за определенный период времени. Для разных RDBMS синтаксис будет разным.
Для PostgreSQL вы можете найти решение в разделе Получение списка дат в диапазоне PostgreSQL.
Для MySQL - MySQL, как заполнить пропущенные даты в диапазоне и создать дни из диапазона дат. Для SQL Server - SQL Server: Как выбрать все дни в диапазоне дат, даже если в течение нескольких дней не существует данных.Используя левое или правое внешнее соединение.
Сортировка данных по дате и данным, которые вы хотите
В случае использования источников данных JavaBean вы должны сделать то же самое - добавить нужные вам даты (без данных) и отсортировать данные. Мы можем пропустить реализацию сортировки данных и попросить механизм JasperReports сделать это за нас.
Кросс-таблица имеет одну "особенность" - мы не можем скрыть строку с условием. Даже если мы установим все свойства для сокрытия всех текстовых полей - пустая строка будет нарисована. Если мы попытаемся использовать фильтр на Crosstab, наши дополнительные строки исчезнут. Я думаю, что хорошей идеей (в этой жалкой ситуации) является специальное имя для такой строки (мы также можем заменить 0 на что-то лучше). В моем примере это будет "Не установлено".
Пример
Я использовал PostgreSQL в этом примере.
Шаблон отчета
<?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="crss_dates_group" pageWidth="842" pageHeight="595" orientation="Landscape" whenNoDataType="AllSectionsNoDetail" columnWidth="802" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" isIgnorePagination="true" uuid="6886d70f-dbf3-4dfa-bbee-d5bc70b1c45d">
<style name="Crosstab Data Text" hAlign="Center"/>
<subDataset name="dsDates" uuid="9b8d3c04-25f5-40f0-b116-a77f8d2f7445">
<queryString language="SQL">
<![CDATA[SELECT activityName, to_char(generate_series, 'YYYY-MM-DD') AS activityDate
FROM myTable RIGHT OUTER JOIN (SELECT (generate_series('2010-07-18', '2010-07-29', '1 day'::interval))::date) fake
ON to_char(activityDateFromMyTable, 'YYYY-MM-DD')=to_char(generate_series, 'YYYY-MM-DD') ORDER BY 2, 1]]>
</queryString>
<field name="activityName" class="java.lang.String"/>
<field name="activityDate" class="java.lang.String"/>
<group name="activityDateGroup">
<groupExpression><![CDATA[$F{activityDate}]]></groupExpression>
</group>
</subDataset>
<title>
<band height="79" splitType="Stretch">
<crosstab>
<reportElement x="0" y="0" width="802" height="79" uuid="d39eef3f-aada-406f-99ee-1d2ce2bde5c8"/>
<crosstabDataset>
<dataset>
<datasetRun subDataset="dsDates" uuid="619c0498-512a-4f23-9f1e-6a5d7cfa986d">
<connectionExpression><![CDATA[$P{REPORT_CONNECTION}]]></connectionExpression>
</datasetRun>
</dataset>
</crosstabDataset>
<rowGroup name="activityName" width="95" totalPosition="End">
<bucket class="java.lang.String">
<bucketExpression><![CDATA[$F{activityName}]]></bucketExpression>
</bucket>
<crosstabRowHeader>
<cellContents backcolor="#F0F8FF" mode="Opaque">
<box>
<pen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/>
</box>
<textField>
<reportElement style="Crosstab Data Text" x="0" y="0" width="95" height="25" uuid="c25490b6-a836-41fb-a36c-a7ebb211bf03"/>
<textFieldExpression><![CDATA[$V{activityName} == null ? "Not set" : $V{activityName}]]></textFieldExpression>
</textField>
</cellContents>
</crosstabRowHeader>
<crosstabTotalRowHeader>
<cellContents backcolor="#BFE1FF" mode="Opaque">
<box>
<pen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/>
</box>
<staticText>
<reportElement x="0" y="0" width="95" height="25" uuid="12efa463-c4a3-4120-b0e2-0664856cc616"/>
<textElement textAlignment="Center" verticalAlignment="Middle"/>
<text><![CDATA[Total by Date]]></text>
</staticText>
</cellContents>
</crosstabTotalRowHeader>
</rowGroup>
<columnGroup name="activityDate" height="30" totalPosition="End">
<bucket class="java.lang.String">
<bucketExpression><![CDATA[$F{activityDate}]]></bucketExpression>
</bucket>
<crosstabColumnHeader>
<cellContents backcolor="#F0F8FF" mode="Opaque">
<box>
<pen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/>
</box>
<textField>
<reportElement style="Crosstab Data Text" x="0" y="0" width="61" height="30" uuid="5b931464-5a7a-4e57-a51a-3d687c0a4130"/>
<textFieldExpression><![CDATA[$V{activityDate}]]></textFieldExpression>
</textField>
</cellContents>
</crosstabColumnHeader>
<crosstabTotalColumnHeader>
<cellContents backcolor="#BFE1FF" mode="Opaque">
<box>
<pen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/>
</box>
<staticText>
<reportElement x="0" y="0" width="50" height="30" uuid="227c77a6-b1c1-485f-95cf-95b43bc95920"/>
<textElement textAlignment="Center" verticalAlignment="Middle"/>
<text><![CDATA[Total by Activity]]></text>
</staticText>
</cellContents>
</crosstabTotalColumnHeader>
</columnGroup>
<measure name="activityNameMeasure" class="java.lang.Integer" calculation="Count">
<measureExpression><![CDATA[$F{activityName}]]></measureExpression>
</measure>
<crosstabCell width="61" height="25">
<cellContents>
<box>
<pen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/>
</box>
<textField>
<reportElement style="Crosstab Data Text" x="0" y="0" width="61" height="25" uuid="b8a8aacb-58d1-447a-9628-7f045b039f9f"/>
<textFieldExpression><![CDATA[$V{activityNameMeasure}]]></textFieldExpression>
</textField>
</cellContents>
</crosstabCell>
<crosstabCell width="61" height="25" rowTotalGroup="activityName">
<cellContents backcolor="#BFE1FF" mode="Opaque">
<box>
<pen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/>
</box>
<textField>
<reportElement style="Crosstab Data Text" x="0" y="0" width="61" height="25" uuid="02e88c9a-e9cc-4674-9301-21676d3f33bc"/>
<textFieldExpression><![CDATA[$V{activityNameMeasure}]]></textFieldExpression>
</textField>
</cellContents>
</crosstabCell>
<crosstabCell width="50" columnTotalGroup="activityDate">
<cellContents backcolor="#BFE1FF" mode="Opaque">
<box>
<pen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/>
</box>
<textField>
<reportElement style="Crosstab Data Text" x="0" y="0" width="50" height="25" uuid="d39d1353-61a6-4041-96d6-2065bae0041b"/>
<textFieldExpression><![CDATA[$V{activityNameMeasure}]]></textFieldExpression>
</textField>
</cellContents>
</crosstabCell>
<crosstabCell rowTotalGroup="activityName" columnTotalGroup="activityDate">
<cellContents backcolor="#BFE1FF" mode="Opaque">
<box>
<pen lineWidth="0.5" lineStyle="Solid" lineColor="#000000"/>
</box>
<textField>
<reportElement style="Crosstab Data Text" x="0" y="0" width="50" height="25" uuid="09aa0d57-5cfa-4e78-af85-0e718c0fee44"/>
<textFieldExpression><![CDATA[$V{activityNameMeasure}]]></textFieldExpression>
</textField>
</cellContents>
</crosstabCell>
</crosstab>
</band>
</title>
</jasperReport>
Результат в iReport
Заметки:
Я пытался скрыть пустую строку (с нулевым значением) с помощью свойств "Удалить строку с пустым", "Пустое при нулевом", "Распечатать при выражении" без какого-либо успеха. Копание в исходниках мне тоже не помогает.
Вы можете найти больше информации о подобных попытках скрыть пустые записи в кросс-таблице здесь:
- Скрыть группы строк NULL JasperReports
- Скрыть строку в кросс-таблице
- как скрыть строку в кросс-таблице, когда нет данных
- Кросс-таблица: Подавить пустую колонку, сохранить ряд подробностей
Возможно, пришло время проголосовать за эту "новую старую" функцию (скрытие пустой строки) в сообществе Jaspersoft/Tibco:)