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

Ottieni le app con il numero di recensioni più alto da una serie dinamica di giorni

penso questo è quello che stai cercando:

Postgres 13 o successivo

WITH cte AS (  -- MATERIALIZED
   SELECT app_id, min(review_date) AS earliest_review, count(*)::int AS total_ct
   FROM   reviews
   GROUP  BY 1
   )
SELECT *
FROM  (
   SELECT generate_series(min(review_date)
                        , max(review_date)
                        , '1 day')::date
   FROM   reviews
   ) d(review_window_start)
LEFT  JOIN LATERAL (
   SELECT total_ct, array_agg(app_id) AS apps
   FROM  (
      SELECT app_id, total_ct
      FROM   cte c
      WHERE  c.earliest_review >= d.review_window_start
      ORDER  BY total_ct DESC
      FETCH  FIRST 1 ROWS WITH TIES  -- new & hot
      ) sub
   GROUP  BY 1
   ) a ON true;

WITH TIES lo rende un po' più economico. Aggiunto in Postgres 13 (attualmente beta). Vedi:

Postgres 12 o più vecchio

WITH cte AS (  -- MATERIALIZED
   SELECT app_id, min(review_date) AS earliest_review, count(*)::int AS total_ct
   FROM   reviews
   GROUP  BY 1
   )
SELECT *
FROM  (
   SELECT generate_series(min(review_date)
                        , max(review_date)
                        , '1 day')::date
   FROM   reviews
   ) d(review_window_start)
LEFT  JOIN LATERAL (
   SELECT total_ct, array_agg(app_id) AS apps
   FROM  (
      SELECT total_ct, app_id
          ,  rank() OVER (ORDER BY total_ct DESC) AS rnk
      FROM   cte c
      WHERE  c.earliest_review >= d.review_window_start
      ) sub
   WHERE  rnk = 1
   GROUP  BY 1
   ) a ON true;

db<>violino qui

Come sopra, ma senza WITH TIES .

Non è necessario coinvolgere la tabella apps affatto. La tabella reviews ha tutte le informazioni di cui abbiamo bisogno.

Il CTE cte calcola la prima recensione e il conteggio totale corrente per app. Il CTE evita il calcolo ripetuto. Dovrebbe aiutare un bel po'.
È sempre materializzato prima di Postgres 12 e dovrebbe essere materializzato automaticamente in Postgres 12 poiché viene utilizzato molte volte nella query principale. Altrimenti potresti aggiungere la parola chiave MATERIALIZED in Postgres 12 o successivo per forzarlo. Vedi:

Il generate_series() ottimizzato call produce la serie di giorni dalla prima all'ultima revisione. Vedi:

Infine, il LEFT JOIN LATERAL hai già scoperto. Ma poiché più app possono collegarsi per la maggior parte delle recensioni, recupera tutti i vincitori, che possono essere 0 - n app. La query aggrega tutti i vincitori giornalieri in un array, quindi otteniamo un'unica riga di risultati per review_window_start . In alternativa, definisci i tiebreak per ottenerne al massimo uno vincitore. Vedi: