Oracle PERCENT_RANK Function

Express each row's position as a fraction from 0 to 1 within its group, and compare relative standing across groups of any size.

A rank of 3 means little without knowing how many rows there are. PERCENT_RANK expresses a row's rank as a fraction of its group, from 0 for the first row to 1 for the last, so positions can be compared across groups of different sizes: where does this salary stand within its department?

Code for This Guide

The main examples are in the examples/analytic-functions folder of the Oracle Database 26ai code repository on GitHub, each with its output. They use NIMBUS, the sample schema of a fictional airline, which you can install with the scripts in the setup/nimbus folder.

They come from Oracle Database 26ai SQL and PL/SQL Book.

Syntax

percent_rank() over ([partition by expr [, ...]] order by expr [, ...])

PERCENT_RANK = (RANK - 1) / (number of rows in the partition - 1). The first row is always 0 and the last 1; a partition of one row gives 0.

Relative Position of Salaries

This query shows PERCENT_RANK and CUME_DIST for the salaries of one department.

Example:

select last_name, salary,
       round(percent_rank() over (order by salary), 3) as percent_rank,
       round(cume_dist()    over (order by salary), 3) as cume_dist
from   employees
where  department_id = 40
order  by salary;

Output:

LAST_NAME       SALARY    PERCENT_RANK    CUME_DIST
____________ _________ _______________ ____________
Tanaka            7600               0          0.1
Gupta             7800           0.111          0.2
Hussain           8000           0.222          0.3
Johnson           8200           0.333          0.4
Martínez         13000           0.444          0.5
Patel            13800           0.556          0.6
Khan             14200           0.667          0.7
Thompson         14500           0.778          0.8
Kapoor           21000           0.889          0.9
Evans            34000               1            1

10 rows selected.

With ten employees, each step is 1/9: 0, 0.111, 0.222, up to 1. CUME_DIST, in the last column, starts at 0.1 instead, because it counts the current row too.

Within Each Group

Example:

-- where each employee stands within their own department
select department_id, last_name, salary,
       round(percent_rank() over (partition by department_id order by salary), 2) as pct_rank
from   employees
where  department_id in (50, 60)
order  by department_id, salary;

Output:

   DEPARTMENT_ID LAST_NAME       SALARY    PCT_RANK
________________ ____________ _________ ___________
              50 Schmidt           8300           0
              50 Williams          8800        0.33
              50 Reddy            15500        0.67
              50 Mehta            33000           1
              60 Mensah            7400           0
              60 Costa            11200         0.5
              60 Okafor           29000           1

7 rows selected.

The department of four goes 0, 0.33, 0.67, 1; the department of three 0, 0.5, 1. Each top earner is at 1 regardless of department size.

Things to Know

  • Tied rows share a PERCENT_RANK, as they share a RANK.
  • PERCENT_RANK(value) WITHIN GROUP (ORDER BY ...) is the aggregate form, for where a hypothetical value would fall.
  • Multiply by 100 for a percentile-style number.

Related Guides

Conclusion

PERCENT_RANK returns a row's rank as a fraction from 0 to 1 within its partition, (rank - 1) / (rows - 1). Use it to compare relative positions across groups of different sizes.

Vinish Kapoor
Vinish Kapoor

An Oracle ACE, author of four books on Oracle APEX, SQL and PL/SQL, and Oracle Forms, and a software developer building Oracle database applications since 2001.

guest

0 Comments
Oldest
Newest Most Voted