Search code examples
postgresqlaggregate-functionspostgresql-9.5

Percentile calculation with a window function


I know you can get the average, total, min, and max over a subset of the data using a window function. But is it possible to get, say, the median, or the 25th percentile instead of the average with the window function?

Put another way, how do I rewrite this to get the id and the 25th or 50th percentile sales numbers within each district rather than the average?

SELECT id, avg(sales)
    OVER (PARTITION BY district) AS district_average
FROM t

Solution

  • You can write this as an aggregation function using percentile_cont() or percentile_disc():

    select district, percentile_cont(0.25) within group (order by sales)
    from t
    group by district;
    

    Unfortunately, Postgres doesn't currently support these as a window functions:

    select id, percentile_cont(0.25) within group (order by sales) over (partition by district) 
    from t;
    

    So, you can use a join:

    select t.*, p_25, p_75
    from t join
         (select district,
                 percentile_cont(0.25) within group (order by sales) as p_25,
                 percentile_cont(0.75) within group (order by sales) as p_75
          from t
          group by district
         ) td
         on t.district = td.district