集算報表繼承了潤乾報表的宏機制來處理動态報表,對于簡單的動态報表使用宏實作非常友善。對于一些複雜的動态報表,集算報表還提供了腳本資料集來處理動态報表,适合宏無法實作的場景,而潤乾報表中要實作複雜動态報表時則需要編寫自定義資料集來完成。下面通過幾個例子來詳細比較一下集算報表和潤乾報表在處理動态報表時的相同與不同點。
相同點
集算報表和潤乾報表都提供了宏,使用方式幾乎完全一緻,且都包含普通宏和動态宏。
普通宏常用于靜态内容替換,如在員工表中同時隻希望檢視薪金或獎金,開發兩張報表顯然是繁冗的,使用普通宏在一張報表來完成很簡單,如下報表:

預覽報表輸入參數和宏:
當參數arg1值為BONUS,宏macro值為BONUS時,可得到如下報表結果:
當參數arg1值為SALARY,宏macro值為SALARY時,可得到如下報表結果:
相對普通宏隻能替換靜态内容,動态宏則可以編寫動态表達式,完成動态内容的替換,進而完成動态報表制作。比如這樣的動态報表,針對指定表根據使用者選擇的字段和條件進行查詢,報表中顯示選擇的字段及其資料。由于字段和條件都是動态的,是以需要先在報表中将SQL拼好再交由資料庫進行查詢,這時就需要在動态宏中進行拼接。如下報表:
其中報表參數和宏設定為:
輸入cols值:訂單ID,客戶ID,訂購日期,發貨日期,到貨日期,運貨費
輸入where值:where 貨主地區='華北' and 貨主城市 in ('北京','天津','張家口','秦皇島')
其值為:"select"+cols+" from 訂單"+where,宏類型為動态宏。
設定資料集SQL為:${sql},預覽報表可以得到如下動态報表結果:
以上為使用宏(普通宏和動态宏)開發相對簡單(隻靜态内容或通過簡單的表達式完成)的動态報表,而對于複雜的動态報表,往往需要經過複雜計算才能完成,而這類複雜情況使用宏往往很難甚至無法完成,這時集算報表和潤乾報表處理的方式則有很大不同。
不同點
集算報表提供了腳本資料集的方式可以完成上述提到的複雜動态報表的開發,由于腳本内置且文法簡單,很容易處理這類報表。而潤乾報表隻能通過自定義資料源在JAVA中完成,使用的簡易性則略遜一籌。下面還是通過例子來看一下。
由使用者針對特定表指定選擇列和條件,如使用者在訂單表中選擇列時,訂單ID、雇員ID和訂購日期是必選列,即使使用者沒有選擇,在查詢後仍然顯示。這就需要在拼接SQL的時候事先判斷必選列是否在使用者的選出列中,如果不在,則在後面添加,同時要保證使用者選出列的次序。
通過宏實作的難點在于,由于需要判斷每個必選列是否在使用者選擇字段的清單中,如果沒有則附加,有多少個必選列就要比較幾次,在必選列較多的時候非常複雜。
下面是集算報表通過腳本資料集的實作(報表參數與表達式與上例一緻):
上述腳本在A2中将所選字段集合與必選字段集合做并集即獲得了所有查詢字段,拼接SQL進行查詢後為報表傳回結果集,過程很簡單。
而潤乾報表在這種情況一般要采用自定義資料集了,下面是潤乾報表通過自定義資料集的實作(主要代碼):
<span style="font-size:14px;">public class QueryData implements IDataSetFactory {
public DataSet createDataSet(Context ctx, DataSetConfig dsc, boolean isinput) {
Map map = ctx.getParamMap(false); // 獲得目前報表的所有參數對照表
String cols = "";
String where = "";
if (map != null) {
Iterator it = map.entrySet().iterator();
cols = map.get("cols").toString(); // 擷取參數值
where = map.get("where").toString(); // 擷取參數值
}
DataSet ds1 = new DataSet("ds1");
Connection con = null;
try {
con = ctx.getConnectionFactory("demo").getConnection(); Statement stmt = con.createStatement();
String sql = "select " + cols + " from 訂單 " + where;
ResultSet rs = stmt.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
int colCount = rsmd.getColumnCount();
//設定列名
for (int i = 1; i <= colCount; i++) {
ds1.addCol(rsmd.getColumnName(i));
}
//設定資料集資料
if (rs != null) {
while (rs.next()) {
Row rr = ds1.addRow();
for (int i = 1; i <= colCount; i++) {
rr.setData(i, rs.getObject(i));
}
}
}
rs.close();
stmt.close();
con.close();
} catch (Exception ex) {
ex.printStackTrace();
}
return ds1;
}
}
</span>
上述自定義資料集首先擷取了報表參數和目前資料源連接配接,其次根據參數拼接出要執行SQL,而後根據獲得的ResultSet為資料集分别設定列名和資料,最後傳回建立的資料集。在使用時,将編譯後的class(QueryData.class)放到應用的classpath中方才完成。
通過以上實作過程可以看到,對于複雜的動态報表(如上例),使用腳本資料集實作更為簡單,除了其擁有簡潔的文法,腳本資料集内置在報表中無需其他程式檔案附加,則更為便捷。