Recently we resolved an issue with Crystal Report, related with heterogeneous data source computation. Due to its complexity, the computation cannot be done with the current functionality of Crystal Report. Thus esProc is used for cross database computation.
Project background: The customer has recently rolled out their KPI system, which required some modification on their original salary calculation algorithm. In the past the salary list is mainly calculated from the basic salary of the employees, which is stored in the MSSQL database used by their Accounting System. The new salary list consists of two parts, basic salary and performance-based salary. The performance-based salary is calculated according to the performance score for each employee, which are stored in the Oracle database used by KPI system. Obviously, the new salary list has to be generated with cross database computation on two heterogeneous databases.
The actual algorithm for calculating performance-based salary is quite complicated. Firstly, the algorithm for each position is different. Some are based on the level of the basic salary, while others are not. Some positions are purely based on performance, while others need to consider the performance and how many years the employee has worked for the company. Moreover, there are also positions that have performance score but no performance-based salary. Secondly, even for those positions based on the level of the basic salary, the algorithm might differ, as the salary level is different for each position. Within each level, the algorithm might also be different. Finally, the salary for all employees needs to be combined into one report.
For better understanding, we simplified the algorithm significantly, and ignored the tax implication. We limited the positions to 2: “normal” and “sales”. Position “normal” has performance score but no performance-based salary. The pre-tax salary equals basic salary. For position “sales”, the pre-tax salary is the sum of basic salary and performance-based salary. Among which, the performance-based salary is calculated in this way:
For employees with basic salary below 2000: performance-based salary=basic salary*(performance sore /100)
For employees with basic salary between 2000 and 4000: performance-based salary=basic salary*(performance sore*0.9 /100)
For employees with basic salary above 4000: performance-based salary=basic salary*(performance sore*0.8 /100)
Thus we could see that to generate a complete salary list, we need to separate the employees in employee table in MSSQL into several groups (2 groups after the simplification). For each group we need to calculate the pre-tax salary, and then combine them into one list. For two different positions, the calculation is different. For employees with position as “sales”, the “performance” table in Oracle database needs to be associated, with pre-tax salary being calculated according to respective level. For employees with position “normal”, no such association is needed.
The difficulty in this report lies in: 1) table employee and performance belongs to two heterogeneous databases, which requires cross database computation. 2) the algorithm is too complicated, as simply associate the two tables cannot do the job.
The ideal solution for cross database computation is to do this through reporting tool. If the reporting tool can process two heterogeneous data sources in one report, cross database computation can then be done on the “report level”. However Crystal Report handles heterogeneous data sources in a very complicated way, and it is done with a high implement cost. Plus, reporting tool can only work with simple inner and outer join, not the kind of complicated computation, such as what-if judgments in a loop, and multiple result sets aggregation.
Since reporting tool cannot solve such issues, we can only turn to other way. Loading the data to a separate database with ETL is not a good choice, because the development for ETL is costly, and data synchronization, as well as real time updates need to be considered. With user-defined data source the problem can be simplified significantly. Well, esProc can be a very good self-defined data source for reporting tool.
See the codes below:
These codes are easy to understand.
A1A2: retrieving data from ORACLE and MSSQL databases. A3: adding an empty column to table “employee”, to store the future pre-tax salary.
A4A10: extract data for all employees with positions of “sales” and “normal”. For future aggregation purpose, business name is more convenient. Thus we name these two sets as sales and normal respectively. Of course, we did not define extra variable for temporary computation result like A3, which, instead, is called in A4 by the name of the cell. The same is for A1, which is called A5.
A5-C9: calculating the pre-tax salary for sales. Here A5 is an association, which is done between the basic salary for sales and their respective performance-based salary. A6 to C9 is a loop, used to calculating the pre-tax salary for each row of sales, based on the actual salary level for the employee. Three things need to be noted here: 1) the loop is indicated with indentation, with B7-C9 as the body of the loop. 2) The variable of the loop is in cell A6, after the “for” operator. In the loopA6 can be used to refer to current record. 3) The way that A6.empID.score is used how an object is referred to. This refers to the score field of the records associated with empID field of current record A6 (eg., record in performance), which is the performance score of the current employee.
A11: replace the preTax value in normal with baseSalary.
A12: combine the computation result sets for different positions. Of course, in reality the positions are not limited to two in algorithm. The algorithm for computing pre-tax salary of each position is also more complicated than the above example.
A13: Select some fields from A12 for output.
A14: output A13 by JDBC, so that JAVA code or reporting tools can call it directly through JDBC URL. We can see that this is also a way to unify heterogeneous data sources. However, the data source association in Crystal Report is too simple to handle such process-based cross database computation.