ARTICLES

Home  > Articles  >  Using the Ratio-to-report function - A technique to add sub totals to the result set

Using the Ratio_to_report function - A technique to add sub-totals to the result set
By John Adolph Palinski

In a previous column I discussed using Oracle's analytic function, Ratio_to_report, to compute a ratio for each value in a sub-set of records.  When using this function you will receive a result set similar to the one shown below.  The Ratio_to_report function is used to compute an employee salary ratio.  The ratio is each employee's share of the total department's salary. 

SQL> select deptno department, ename name,
  2         sal salary,
  3         ratio_to_report(sal)
  4         over (partition by deptno) ratio
  5  from emp;

DEPARTMENT     NAME           SALARY      RATIO
-----------------     -----------      -----------     -------------
        10                   CLARK                 2450                    .28
        10                   KING                    5000      .571428571
        10                   MILLER                1300      .148571429
        20                   SMITH                    800      .073563218
        20                   ADAMS                1100      .101149425
        20                   FORD                    3000      .275862069
        20                   SCOTT                  3000      .275862069
        20                   JONES                   2975      .273563218
        30                   ALLEN                  1600      .170212766
        30                   BLAKE                  2850      .303191489
        30                   MARTIN                1250     .13297872
        30                   JAMES                     950     .10106383
        30                   TURNER                1500     .159574468
        30                   WARD                    1250     .132978723

14 rows selected.

SQL>

It is not readily evident that the ratio is based upon each individual department's total salaries.  You can only determine that the ratio is based upon the department by looking at the ratios.  View the first three ratios for Department 10: .28, .57, and .14.  The sum of these ratios is 99 indicating that the ratio is based upon the total department salaries. 

A second problem with the result set is that the viewer cannot determine the magnitude of the ratio.value.  For example, the first row has a ratio of 28%.  Rows six and seven have ratios of 27%.  Does this indicate that the employee salaries for the three rows is somewhat equal.  No it does not.  Reviewing the rows you can see that there is a $550 difference between row one and the other three rows.  This can be a little misleading if the reader is not careful.

The result set would be more readable if a break with the total department salary can be added between each department's records.  This break is really a sub-total displaying the ratio calculation denominator, the total department salaries.  Most report writing tools can add this sub-total.  It can also be done using the Select statement that creates the result set.  Add a unioned Select statement to the original Select statement.  The second statement is used to compute the total department salaries.  This was done in the following result set.  Notice how much more readable this result set is.  

SQL> select department, name,
  2         salary, ratio
  3  from
  4  (select deptno department, ename name,
  5         sal salary, ratio_to_report(sal)
  6         over (partition by deptno) ratio,
  7         to_char(deptno) sort_column
  8  from emp
  9  union
 10  select null, 'Total Department '||deptno||' Salaries', sum(sal),
 11         null, to_char(deptno)||'a'
 12  from emp
 13  group by deptno)
 14  order by sort_column;

DEPARTMENT   NAME                                         SALARY    RATIO
-----------------   ----------------------------------  ----------   ------------
        10                 CLARK                                              2450                .28
        10                 KING                                                 5000   .571428571
        10                 MILLER                                             1300   .148571429
                             Total Department 10 Salaries               8750
        20                 ADAMS                                             1100   .101149425
        20                 FORD                                                 3000   .275862069
        20                 JONES                                                2975   .273563218
        20                 SCOTT                                               3000   .275862069
        20                 SMITH                                                  800   .073563218
                             Total Department 20 Salaries              10875
        30                 ALLEN                                                1600   .170212766
        30                 BLAKE                                                2850   .303191489
        30                 JAMES                                                  950    .10106383
        30                 MARTIN                                             1250   .132978723
        30                 TURNER                                             1500   .159574468
        30                 WARD                                                 1250   .132978723
                             Total Department 30 Salaries                9400

17 rows selected.

SQL>

The difficult part in creating the above result set was to get the sub-totals to sort in the proper location.  Without special techniques the sub-total rows would not have appeared at the end of the department's records.  They would have been sorted according to the department's name values and been interspersed within the department's records.  For example, the last row with the Name value "Total Department 30 Salaries" would have appeared between the MARTIN and TURNER records.   

Proper sorting was caused by two techniques.  The creation of an artificial sort value and an in-line view.  The artificial sort order is the Sort_column expression.  In the first Select statement this value consists of the Deptno value.  In the second Select statement this value consists of the Deptno value and the letter 'a', causing this value to be sorted after the normal Deptno values.  It is necessary have the Sort_column but it is not desireable to see the Sort_column values.  This was achieved by wrapping the two unioned Select statements in an In-line view.  An In-line view is a Select statement that resides in the From clause.  It in essence creates a virtual result set when it is executed.  The In-line allows me to sort the records based upon the Sort_column, but not display the column in the result set. 

Adding the sub-total will enhance your use of the Ratio_to_report function.

John Adolph Palinski is a former adjunct faculty member at the University of Nebraska at Omaha and Iowa Western Community College.  He is the author of the "Oracle Database Construction Kit", Que, 1997, the "Oracle SQL and PL/SQL Handbook: A Guide for Data Administrators, Developers, and Business Analysts", Addison Wesley Longman, 2002, and "Oracle 9i Developer: Developing Web Applications With Forms Builder", Course Technology, 2003.  He has also written numerous articles for periodicals such as Oracle Internals and Oracle Professional.  He provides Oracle training.   He may be contacted at www.oracle-trainer.com.