簡化報表資料來源的複雜集合運算,簡化報表運算
報表資料來源計算中經常會使用到集合運算,SQL對集合運算的支援使得大部分簡單的集合運算都能輕鬆完成。但是,當集合運算比較複雜,需要使用預存程序完成時,由於預存程序對集合運算的支援不夠,也無法使用中間結果導致這類運算實現起來非常困難。
像http://bbs.csdn.net/topics/390902711中提到的問題,就是一個比較典型的複雜集合運算問題,這類計算往往都是為前台報表格服務的,使用SQL和預存程序都很難完成。而一般的報表工具由於不具備強計算能力,對於這類計算更加無法完成。
使用潤乾集算報表來做則比較簡單,這裡以上述連結中的實際業務為例,給出集算報表的實現方案。
報表背景
來源資料如下:
現需要在報表中統計不同id下不同時間段內不重複的天數,如:
這個報表的痛點在於用SQL或預存程序寫起來很困難,而一般報表工具則不具備資料來源計算能力,根本無法實現。
集算報表本身內建了適合結構化計算的指令碼,可以方便地寫出資料準備的計算(相當於一種更使用更簡單的自訂資料集)。
編寫集算指令碼
首先使用集算指令碼編輯器,建立集算指令碼,設定指令碼參數,如ID範圍。
編寫指令碼完成資料計算,為報表輸出計算後結果集:
A1:串連資料來源;
A2:根據id起止範圍,執行sql取數;
A3:根據日期範圍欄位,增加起始日期和終止日期欄位;需要說明的是,類似的字串拆分工作也可以用SQL完成,但SQL的串拆分功能不是很方便,所以這裡也給出集算指令碼的實現方式,使用者使用時可以選擇;
A4:先按id分組,將每個id下所有日期段內日期合并(重複的只顯示一個),然後計數,得到不重複天數;其原理是將這些時間段轉換成日期的集合(period函數),再將這些集合求並集(union),這時就會將重複的去除,最後只要數集合的成員個數即可(len)。
如果不重複天數是指只計算出現過一次的日期,即重疊的日期都不計數,那麼通過集算指令碼也很容易實現,通過下面的代碼即可完成:
A3.group(id;~.conj(periods(起始日期,終止日期,1)).group().count(~.len()==1):不重複天數)
其原理是按照日期分組後,統計每個分組子整合員數為1的子集數量,也就是只出現過一次的日期。
A5:為報表返回結果集
編輯報表範本
使用集算報表編輯器,編輯報表範本,用於資料展現。首先建立參數,並設定預設值。
建立報表並設定集算器資料集,調用上述編輯好的指令檔。
其中,dfx檔案路徑既可以是絕對路徑,也可以是相對路徑,相對路徑是相對選項中配置的dfx主目錄的;參數b_id和e_id為報表範本參數,begin和end為指令碼參數,事實上二者可以同名。
編輯報表運算式,直接使用集算指令碼返回的結果集,完成報表製作 。
報表展現結果如下:
可以看到,使用集算器指令碼可以快速完為報表準備資料。而且外置的集算指令碼具有可視化的編輯調試環境,編輯好的指令碼還可以複用(被其他報表或程式調用)。不過,如果指令碼已經調試好,而且不需要複用的時候,要維護兩個檔案(集算指令碼和報表範本)的一致性會比較麻煩,這時候直接使用集算報表的指令碼資料集就比較簡單了。
在指令碼資料集中可以分步編寫指令碼完成計算任務,文法與集算器一致,還可以直接使用報表定義好的資料來源和參數。本例使用指令碼資料集可以這樣完成:
1. 在資料集設定視窗中點擊“增加”按鈕,彈出資料集類型對話方塊,選擇“指令碼資料集”;
2. 在彈出的指令碼資料集編輯視窗中編寫指令碼;
這裡可以看到,在指令碼資料集中直接使用了報表中定義好參數b_id和e_id,比起單獨的集算指令碼更加簡單、直接。
3.報表範本和運算式與使用集算器資料集方式一致,不再贅述。