天天看點

一個crystal report水晶報表無法實作的多資料源計算

項目背景:使用者新上線了績效考核系統,原本的工資算法需要相的調整。以前的工資表主要由員工的基本工資計算得到,基本工資存儲在财務管理軟體的MSSQL資料庫中。新的工資表由基本工資+績效工資組成。績效工資由績效分數計算得出,而績效分數存儲在績效考核系統的Oracle資料庫中。顯然,新的工資表需要兩個資料庫的跨庫計算才能得到。

具體的績效工資算法比較複雜。首先,不同的崗位算法不同。有些崗位是根據基本工資的區間來計算的,而有些崗位不需要按區間來計算。有些崗位隻是單純的用績效來計算,而有些崗位要考慮績效和工齡雙重因素。還有些崗位有績效得分但沒有績效工資。其次,同樣是按基本工資區間來計算績效的崗位,不同的崗位其區間劃分方法、每個區間内的具體算法也有不同。最後,所有的員工工資要合并為一張報表。

為了便于了解,這裡将算法大幅簡化,并去掉交稅的影響,崗位也簡化為2個:normal和sales。Normal有績效得分但沒有績效工資,其稅前工資=基本工資。sales的稅前工資=基本工資+績效工資。其中績效工資是這樣算的:

基本工資在2000以下的:基本工資*(績效得分/100)

基本工資在2000至4000的:基本工資*((績效得分*0.9)/100)

基本工資在4000以上的基本工資*((績效得分*0.8)/100)

可以看到,要計算完整的工資表,需要将MSSQL的employee表按照崗位分成多份(簡化後是2份),每份資料單獨計算出稅前工資,最後再将不同崗位的稅前工資合并起來。兩種崗位的算法不同,崗位是sales的需要關聯Oracle中的performance表,其稅前工資需要按不同的區間分别計算。而崗位是normal不需要做這種關聯計算。

這張報表的難點在于:一、employee和performance分屬不同的資料庫,需要跨庫計算。二、算法較複雜,僅将兩張表簡單地關聯起來是無法實作目标的。

跨庫計算最理想的解決方案是依靠報表工具。如果報表工具能在一張報表中處理兩種資料源就可以實作“報表層跨庫”。但Crystal report處理多資料源的辦法很複雜,實作成本不低。而且報表工具也隻能提供簡單的内外關聯,難以處理這種循環中判斷以及多結果集合并的複雜算法。

報表工具無法解決這種問題,隻能從報表之外尋求解法。事先ETL到一個庫裡顯然不是個好辦法,一方面ETL開發成本太高,另一方面還有資料同步和實時性的麻煩。

最後用集算器解決了這個問題,具體代碼如下:

一個crystal report水晶報表無法實作的多資料源計算

代碼的意思也很好了解:

A1A2:分别從ORACLE和MSSQL取資料。A3:為employee加一個空列preTax,用來存儲将來的稅前工資。

A4A10:從employee分别取出崗位是sales和normal的資料。由于後期要合并,用業務名引用比較友善,是以這兩部分資料分别定義為sales和normal。當然,A3這種臨時的計算結果并沒有額外定義變量,而是直接在A4中按格名來引用A3。類似的還有A5中引用A1。

A5-C9:計算sales的稅前工資。其中A5是關聯計算,将sales的基本工資和績效分數關聯了起來。A6到C9是個循環,将sales逐條循環判斷,按不同區間不同算法來計算稅前工資。這裡需要注意三點。一是循環體是用縮進來表示的,B7-C9都是循環體。二是循環變量就是for所在的單元格,即A6。循環體中可以用A6來表示目前記錄。三是A6.empID.score的用法,這是對象的引用方式。這表示目前記錄A6的empID字段所關聯的記錄(即performance中的記錄)的score字段,即目前員工的績效分數。

A11:直接将normal的preTax指派為baseSalary。

A12:将不同崗位的計算結果合并起來。當然,實際的算法中遠不止兩種崗位,每種崗位的稅前工資算法也比示例中複雜。

A13:從A12中挑選一些需要輸出的字段。

 A14:以JDBC的形式輸出A13,以便JAVA代碼或報表工具通過JDBCURL直接調用。可以看到,這實際上這也是一種将多資料源合并為單資料源的方法,隻是Crystal的資料源關聯過于簡單,無法實作這種過程性的跨庫計算罷了。

可以看到,水晶報表中的這個跨庫的問題被輕松解決了。另外水晶報表會把集算器當作MSSQL或Oracle這樣的資料庫來調用,配合起來也很容易。

繼續閱讀