The database stores a table of the following form:
| Parent name | Start | End | Value |
|---|---|---|---|
| PN1 | 12 | 16 | 2 |
| PN1 | 19 | 29 | 4 |
| PN1 | 32 | 34 | 6 |
| … | … | … | … |
| PN2 | 4 | 17 | 3 |
| PN2 | 32 | 33 | 6 |
| … | … | … | … |
Is it possible to calculate the average by grouping the values according to the segment length condition?
That is. if the length of the segment is 30. the regrouped table is as follows:
| Parent name | Avg |
|---|---|
| PN1 | (2+4)/2 |
| PN1 | 6/1 |
| … | … |
| PN2 | 3/1 |
| PN2 | 6/1 |
| … | … |
Now I am not considering situations where the value of a segment may overlap with values within cells.
In fact, the task of grouping is to find a way to "collapse" the values.
>Solution :
You can group by how many whole segments fit under the "End" value using the floor() function. It would work the same with ceil() or nothing, if your segment length is an integer because dividing by an int will result in truncating everything after decimal point:
numeric_type / numeric_type → numeric_type
Division (for integral types, division truncates the result towards zero)
select "Parent name"
,avg(value)
,format( '(%s)/%s'
,string_agg(value::text,'+')
,count(*)) as calculation
from your_table
group by "Parent name", floor("End"/30)::int
order by "Parent name", max("End");
| Parent name | avg | calculation |
|---|---|---|
| PN1 | 3.0000000000000000 | (2+4)/2 |
| PN1 | 6.0000000000000000 | (6)/1 |
| PN2 | 3.0000000000000000 | (3)/1 |
| PN2 | 6.0000000000000000 | (6)/1 |