新聞中心
解決Birt等報(bào)表工具制作報(bào)表的幾個(gè)難題
專注于為中小企業(yè)提供成都網(wǎng)站制作、成都網(wǎng)站設(shè)計(jì)、外貿(mào)營銷網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)白堿灘免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了1000+企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
在上一篇《Birt 如何實(shí)現(xiàn)不規(guī)則月份統(tǒng)計(jì)》中,我們講解了如何幫助 Birt 制作這種報(bào)表的詳細(xì)過程,在本文中我們再繼續(xù)討論幾個(gè)類似的制作難題,并把說明集中在如何編寫集算器 SPL 腳本上,不再贅述如何在 Birt 中引入 SPL 的步驟了。
1.??????? 組內(nèi)跨行計(jì)算
組內(nèi)跨行計(jì)算是指在計(jì)算一行中某個(gè)計(jì)算列的值時(shí),需要引用到組內(nèi)其它行的數(shù)據(jù)來進(jìn)行計(jì)算。比如下面這個(gè)例子:
庫表 sample 有三個(gè)字段,其中 id 是分組字段。需要設(shè)計(jì)一張分組表,使用 id 分組,明細(xì)字段是 v1,v2 以及計(jì)算列 crossline, 其中 crossline 的算法是本條記錄 v1、v2 之和加上本組上一條記錄的 v1、v2 之和。示例源數(shù)據(jù)如下:
id | v1 | v2 |
1 | 1 | 2 |
1 | 2 | 3 |
2 | 1 | 1 |
2 | 2 | 2 |
3 | 3 | 3 |
最后要展現(xiàn)的報(bào)表結(jié)果如下圖所示:
編寫集算器 SPL 代碼如下:
A | |
1 | =connect("demo") |
2 | =A1.query("select ? *, 0 as crossline from sample") |
3 | >A2.group(id).run(~.run(v1+v2+v1[-1]+v2[-1]:crossline)) |
4 | >A1.close() |
5 | return ? A2 |
?
A1?? 連接數(shù)據(jù)庫
A2?? 查詢數(shù)據(jù)庫,同時(shí)多產(chǎn)生一列常數(shù)備用。
A3?? 按 id 分組,并在每組數(shù)據(jù)中修改計(jì)算列 crossline,最后合并,其中 v1[-1]、v2[-1] 是集算器特有的定位上一行記錄中字段的寫法。
A4?? 關(guān)閉數(shù)據(jù)庫
A5?? 將 A2 中的計(jì)算結(jié)果數(shù)據(jù)集返回給報(bào)表工具
?
2.??????? 跨庫數(shù)據(jù)源
制作報(bào)表的數(shù)據(jù)往往來自于多種數(shù)據(jù)源,比如不同的物理數(shù)據(jù)庫、文本文件、Excel 文件等,這些數(shù)據(jù)在報(bào)表中往往還需要相互關(guān)聯(lián)進(jìn)行運(yùn)算。
報(bào)表工具本身能實(shí)現(xiàn)從多數(shù)據(jù)源取數(shù),但進(jìn)行關(guān)聯(lián)運(yùn)算會有一定的困難,或者運(yùn)算性能非常差。而由開發(fā)者自己編程去做關(guān)聯(lián)運(yùn)算,工作量一般又會非常大。而集算器 SPL 恰恰能在這一點(diǎn)幫上大忙。
下面這個(gè)例子中,訂單表 orders 和訂單明細(xì)表 orderDetail 數(shù)據(jù)分別來自兩個(gè)不同的數(shù)據(jù)庫,二者之間要做 join 運(yùn)算。兩表數(shù)據(jù)如下:
?
最后想要展現(xiàn)的報(bào)表結(jié)果如下:
?
編寫集算器 SPL 代碼如下:
A | |
1 | =connect("db1") |
2 | =connect("db2") |
3 | =A1.query("select orderID,customer,orderDate ? from orders") |
4 | =A2.query("select orderID,productID,price,mount ? from orderDetail order by orderID") |
5 | >A1.close() |
6 | >A2.close() |
7 | =join@1(A3:orderID,A4:orderID) |
8 | =A7.new(#1.orderID,#1.customer,#1.orderDate,#2.productID,#2.price,#2.mount) |
9 | return A8 |
?
A1?? 連接數(shù)據(jù)庫 1
A2?? 連接數(shù)據(jù)庫 2
A3?? 查詢訂單表數(shù)據(jù)
A4?? 查詢訂單明細(xì)表數(shù)據(jù)
A5A6?? 關(guān)閉數(shù)據(jù)庫連接
A7?? 以 A3 的 orderID 和 A4 的 orderID 為主鍵進(jìn)行 left join,連接后的結(jié)果集有兩個(gè)字段,第一個(gè)字段是 A3 的記錄,第二個(gè)字段是 A4 的記錄。
A8?? 以 A7 中兩個(gè)字段的字段形成新的數(shù)據(jù)集,也就是需要的結(jié)果
A9?? 將 A8 的數(shù)據(jù)集返回給報(bào)表工具
本例只是演示了兩個(gè)數(shù)據(jù)源的 left join,其實(shí) SPL 能做關(guān)系數(shù)據(jù)庫能完成的任何數(shù)據(jù)運(yùn)算,比如各種 join、union、過濾、分組、排序等。
3.??????? 字段拆分成記錄
在本例中,數(shù)據(jù)庫表 data 有兩個(gè)字段,其中 ANOMOALIES 字段是用空格分隔的多個(gè)字符串,我們需要把 ANOMOALIES 按空格拆分為多個(gè)字符串,并用每個(gè)字符串和原 ID 字段形成新的記錄。源數(shù)據(jù)如下:
ID | ANOMALIES |
3903 | B1 D1 CAT1 |
3904 | D7 D2 B1 CAD4 |
最后想要展現(xiàn)的報(bào)表結(jié)果如下:
編寫集算器 SPL 代碼如下:
A | |
1 | =connect("db") |
2 | =A1.query("select ID,ANOMALIES from ? data") |
3 | =A2.conj(ANOMALIES.array("?").new(A2.ID:ID,~:ANOMALIES)) |
4 | >A1.close() |
5 | return A3 |
?
A1?? 連接數(shù)據(jù)庫 1
A2?? 查詢 data 表數(shù)據(jù)
A3?? 將ANOMALIES字段值按空格拆分,并與原ID形成新的記錄
A4?? 關(guān)閉數(shù)據(jù)庫連接
A5?? 將 A3 形成的數(shù)據(jù)集返回給報(bào)表工具
?
4.??????? 主表中動態(tài)插入子表字段
在本例中,數(shù)據(jù)庫表 dColThread 是主表,主鍵是 tID。dColQuestion 是子表,外鍵是 tID,如下:
dColThread
tID | ApplicationName | User | Phone | Decline |
A01 | mfc | Bill | +70000000 | 1 |
A02 | mfc | John | +18761221 | 2 |
A03 | java | Jack | +8014001231 | 6 |
A04 | mfc | Tim | +008613133123 | 4 |
A05 | db | John | +18761221 | 8 |
dColQuestion
qID | tID | status |
1 | A01 | yes |
2 | A01 | no |
3 | A01 | yes |
4 | A02 | yes |
5 | A03 | no |
6 | A04 | no |
7 | A04 | no |
8 | A05 | yes |
報(bào)表需要根據(jù) ApplicationName 查詢主表并以列表的形式展現(xiàn)數(shù)據(jù)??梢钥吹?,在子表中,主表每條記錄對應(yīng)的 status 字段值有多個(gè),但不超過 5 個(gè)。我們需要把子表中的這些記錄橫向排列后插入主表的 Phone、Decline 字段之間,依次命名為 QuestionNo1、QuestionNo2…QuestionNo5。同時(shí),如果某列數(shù)據(jù)都為空,則這一列不顯示。最后的表樣形如下圖:
用集算器準(zhǔn)備數(shù)據(jù),SPL 代碼如下:
A | B | |
1 | =connect("db") | |
2 | =A1. ? query("select * from dColThread t,dColQuestion q where t.tID=q.tID and ? t.ApplicationName=?",arg1) | |
3 | >A1.close() | |
4 | =A2.group(tID) | |
5 | =create(ApplicationName,User,Phone,QuestionNo1,QuestionNo2,QuestionNo3,QuestionNo4,QuestionNo5,Decline) | |
6 | for A4 | =A6.(status)|["","","","",""] |
7 | = A5.record(A6.ApplicationName|A6.User|A6.Phone|B6.to(5)|A6.Decline) | |
8 | return A5 |
?
A1?? 連接數(shù)據(jù)庫
A2?? 執(zhí)行 SQL,取出主子表關(guān)聯(lián)數(shù)據(jù)。arg1 是來自報(bào)表參數(shù)。假如 arg1= "mfc ",則 A1 的計(jì)算結(jié)果如下:
A4?? 按照 tID 分組,每組是一條主表記錄及其對應(yīng)的子表記錄,如下圖:
A5?? 按照報(bào)表中列表的結(jié)構(gòu)新建空二維表。
A6?? 循環(huán) A4 中的組,每次向 A5 插入一條記錄。循環(huán)體中可用 A6 引用循環(huán)變量,用 #A6 來引用循環(huán)計(jì)數(shù)。
B6?? 取當(dāng)前組中 status 的字段值,并補(bǔ)足至少 5 條記錄。
B7?? 向 A5 追加新記錄。循環(huán)結(jié)束后 A5 如下:
A8:返回結(jié)果給報(bào)表。
?
隱藏空列的工作交給 BIRT,設(shè)計(jì) list 表,模板如下:
如果 QuestionNo 列為空則應(yīng)當(dāng)隱藏。動態(tài)隱藏的方法有很多,這里介紹其中一種。對于 QuestionNo5(其他列類似),可以先在 dataSet 的 onFetch 方法中使用如下腳本:
if(reportContext.getGlobalVariable("t5")==null){
??? reportContext.setGlobalVariable("t5",row.QuestionNo5)
}else{
reportContext.setGlobalVariable("t5",reportContext.getGlobalVariable("t5")+row.QuestionNo5)
}
再在 QustionNo5 列的 Visibility 屬性中使用如下表達(dá)式:BirtStr.trim(reportContext.getGlobalVariable("t5"))==""
預(yù)覽后可以看到報(bào)表結(jié)果:
?
5.??????? 小結(jié)
通過以上例子可以看出,報(bào)表制作時(shí)經(jīng)常遇到不好處理的數(shù)據(jù)準(zhǔn)備工作,而在集算器的幫助下都可以得到完美的解決。這是因?yàn)榧闫魈峁┝送陚涞臄?shù)據(jù)源連接功能,能連接市面上常見的各種數(shù)據(jù)源并從中取數(shù)。同時(shí),SPL 還提供了豐富的函數(shù)庫,能在庫外輕松進(jìn)行數(shù)據(jù)的各種關(guān)聯(lián)運(yùn)算。
網(wǎng)頁名稱:解決Birt等報(bào)表工具制作報(bào)表的幾個(gè)難題
轉(zhuǎn)載注明:http://ef60e0e.cn/article/poepjj.html