PostgreSQL: come visualizzare i primi N record di ogni gruppo


Di recente mi è capitato di dover produrre un report dove si volevano, per ogni venditore inserito nei database aziendali, le prime 5 categorie merceologiche in cui vende più offerte.
Il problema di scrivere una query per selezionare i primi N elementi di un gruppo non è banale.
Semplificando al massimo il caso reale, si può vedere come se in gioco ci fosse un'unica tabella offers, dove ogni record è composto da:

  • id
  • venditore (seller)
  • categoria dell'offerta (category)
La richiesta non è facilmente esprimibile con una query ma, ho scoperto che da PostgreSQL 9.1 viene offerta una sintassi molto naif per realizzarla. 
Bisogna combinare due window function, ovvero due funzioni che permettono di fare calcoli su insiemi di righe:
  1. row_number(): fornisce il numero di riga in un certo insieme, partendo da 1
  2. select over partition: permette di selezionare qualcosa in una partizione di dati
La query che risponde all'esigenza di avere le prime 5 categorie di ogni venditore è:

select partitioned_by_seller.seller, partitioned_by_seller.category
from (
select row_number() over (partition by seller order by cnt desc) as rownumber, t.*
from (
select seller, category, count(*) as cnt
from offers
group by seller, category
) t) partitioned_by_seller
where partitioned_by_seller.rownumber <= 5
Sicuramente è un po' annidata e non di facile comprensione a una primissima lettura ma indiscutibilmente un modo molto potente per selezionare più record appartenenti a uno stesso gruppo in modo performante e compatto.

Comments

Popular posts from this blog

"Back to values" agile retrospective format

Contracts: diagonal saber vs. agile

ScuolaXP 2017 - Com'è andata?