Я считаю, что лучший вариант сделать это - разворачивать таблицу (иметь по одной строке на счет), а затем ранжировать их. Если вы хотите получить точный результат с оригинальными результатами, вы можете либо снова повернуть таблицу, либо объединить результаты с помощью id
.
Это мое предложение:
with input(id, score1, score2, score3) as (
select 123, 14, 561, 580 union all
select 456, 626, 771, 843 union all
select 789, 844, 998, 904 union all
select 111, 922, 677, 301 union all
select 222, 665, 578, 678 union all
select 333, 416, 631, 320
),
unpivotted(id, score_label, score) as (
select
id,
case x
when 1 then 'score1'
when 2 then 'score2'
when 3 then 'score3'
end,
case x
when 1 then score1
when 2 then score2
when 3 then score3
end
from input
cross join (select 1 as x union all select 2 union all select 3) as three
),
ranked as (
select *,
rank() over (partition by id order by score desc) as rnk
from unpivotted
)
select distinct
id,
nth_value(score_label, 1) over (partition by id order by rnk rows between unbounded preceding and unbounded following ) as high_score_label,
nth_value(score_label, 2) over (partition by id order by rnk rows between unbounded preceding and unbounded following) as second_score_label,
nth_value(score, 1) over (partition by id order by rnk rows between unbounded preceding and unbounded following ) as high_score,
nth_value(score, 2) over (partition by id order by rnk rows between unbounded preceding and unbounded following) as second_score
from ranked
order by id
Результат:
# id high_score_label second_score_label high_score second_score
1 111 score1 score2 922 677
2 123 score3 score2 580 561
3 222 score3 score1 678 665
4 333 score2 score1 631 416
5 456 score3 score2 843 771
6 789 score2 score3 998 904