Update: I re-wrote my answer, because the previous one ignored certain requirements.
To keep track of the 2 previous top values, you can write a UDTF in JS to hold that ranking:
create or replace function udtf_top2_before(points float)
returns table (output_col array)
language javascript
as $$
{
processRow: function f(row, rowWriter, context){
rowWriter.writeRow({OUTPUT_COL: this.prevmax.slice().reverse()});
this.prevmax.push(row.POINTS);
// silly js sort https://stackoverflow.com/a/21595293/132438
this.prevmax = this.prevmax.sort(function (a, b) {return a - b;}).slice(-2);
}
, initialize: function(argumentInfo, context) {
this.prevmax = [];
}
}
$$;
Then that tabular UDF can will give you the numbers as expected:
with data as (
select v:author::string author, v:score::int score, v:subreddit, v:created_utc::timestamp ts
from reddit_comments_sample
where v:subreddit = 'wallstreetbets'
)
select author, score, ts
, output_col[0] prev_max
, output_col[1] prev_max2
, (prev_max+ifnull(prev_max2,prev_max))/2 avg
from (
select author, score, ts, output_col
from data, table(udtf_top2_before(score::float) over(partition by author order by ts))
order by author, ts
limit 100
)
UDTF based on my previous post:
Previously:
You can use row_number() over() to select the top 2, and then pivot with an array_agg():
with data as (
select v:author author, v:score::int score, v:subreddit, v:created_utc::timestamp ts
from reddit_comments_sample
where v:subreddit = 'wallstreetbets'
)
select author, arr[0] max_score, arr[1] max_score_2, (max_score+ifnull(max_score_2,max_score))/2 avg
from (
select author
, array_agg(score) within group (order by score::int desc) arr
from (
select author, score, ts
from data
qualify row_number() over(partition by author order by score desc) <= 2
)
group by 1
)
order by 4 desc
