0

I have tables like the following:

recorddate score 
2021-05-01   0
2021-05-01   1 
2021-05-01   2
2021-05-02   3
2021-05-02   4
2021-05-03   5
2021-05-07   6

And want to get the 60th percentile for score per week. I tried:

select distinct 
       recorddate
     , PERCENTILE_disc(0.60) WITHIN GROUP (ORDER BY score)
                             OVER (PARTITION BY recorddate) AS top60
from tbl;

It returned something like this:

recorddate top60
2021-05-01  1
2021-05-02  4
2021-05-03  5
2021-05-07  6

But my desired result is like weekly aggregation (7 days). For example for the week ending on 2021-05-07:

recorddate                    top60
2021-05-01 ~ 2021-05-07        2

Is there a solution for this?

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
Heisenberg
  • 4,787
  • 9
  • 47
  • 76

1 Answers1

2

I think you want this:

SELECT date_trunc('week', recorddate) AS week
     , percentile_disc(0.60) WITHIN GROUP(ORDER BY score) AS top60
FROM   tbl
GROUP  BY 1;

That's the discrete value at the 60th percentile for each week (where actual data exists) - where 60 % of the rows in the same group (in the week) are the same or smaller. To be precise, in the words of the manual:

the first value within the ordered set of aggregated argument values whose position in the ordering equals or exceeds the specified fraction.

Adding your format on top of it:

SELECT to_char(week_start, 'YYYY-MM-DD" ~ "')
    || to_char(week_start + interval '6 days', 'YYYY-MM-DD') AS week
     , top60
FROM  (
   SELECT date_trunc('week', recorddate) AS week_start
        , percentile_disc(0.60) WITHIN GROUP(ORDER BY score) AS top60
   FROM   tbl
   GROUP  BY 1
   ) sub;

I would rather call it something like "percentile_60".

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228