To nie jest ładne, ale znalazłem rozwiązanie:
WITH RECURSIVE rankings(rankable_type, rankable_id, athlete, value, rank) AS (
SELECT 'Sport', sport_id, athlete, seconds, RANK() over(PARTITION BY sport_id ORDER BY seconds)
FROM lap_times lt
UNION ALL
SELECT 'Category', *, rank() OVER(PARTITION by category_id ORDER BY avg_rank) FROM (
SELECT DISTINCT category_id, athlete, avg(r.rank) OVER (PARTITION by category_id, athlete) AS avg_rank
FROM categories c
JOIN memberships m ON m.category_id = c.id
JOIN rankings r ON r.rankable_type = m.member_type AND r.rankable_id = m.member_id
) _
)
SELECT * FROM rankings;
W rekurencyjnej części zapytania, zamiast wywoływania GROUP BY
i obliczanie avg(r.rank)
, używam funkcji okna podzielonej na te same kolumny. Ma to ten sam efekt przy obliczaniu średniej pozycji.
Jedną wadą jest to, że te obliczenia zdarzają się więcej razy, niż jest to konieczne. Gdybyśmy mogli GROUP BY
następnie avg(r.rank)
, co byłoby bardziej wydajne niż avg(r.rank)
następnie GROUP BY
.
Ponieważ w wyniku zagnieżdżonego zapytania są teraz duplikaty, używam DISTINCT
aby je odfiltrować, a następnie zewnętrzne zapytanie oblicza RANK()
wszystkich sportowców w każdym category_id
na podstawie tych średnich.
Nadal chciałbym usłyszeć, czy ktoś zna lepszy sposób na zrobienie tego. Dzięki