PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Le funzioni aggregate non sono consentite in una query ricorsiva. C'è un modo alternativo per scrivere questa query?

Non è carino, ma ho trovato una soluzione:

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;

Nella parte ricorsiva della query, invece di chiamare GROUP BY e calcolando avg(r.rank) , utilizzo una funzione di finestra partizionata sulle stesse colonne. Questo ha lo stesso effetto del calcolo del ranking medio.

Uno svantaggio è che questo calcolo avviene più volte del necessario. Se potessimo GROUP BY quindi avg(r.rank) , sarebbe più efficiente di avg(r.rank) quindi GROUP BY .

Poiché ora ci sono duplicati nel risultato della query nidificata, sto usando DISTINCT per filtrarli e quindi la query esterna calcola un RANK() di tutti gli atleti in ogni category_id sulla base di queste medie.

Sarei comunque curioso di sapere se qualcuno conosce un modo migliore per farlo. Grazie