PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Obtenez les applications avec le plus grand nombre d'avis depuis une série dynamique de jours

Je pense voici ce que vous recherchez :

Postgres 13 ou version ultérieure

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 le rend un peu moins cher. Ajouté dans Postgres 13 (actuellement bêta). Voir :

Postgres 12 ou version antérieure

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<>violon ici

Comme ci-dessus, mais sans WITH TIES .

Nous n'avons pas besoin d'impliquer la table apps du tout. La table reviews a toutes les informations dont nous avons besoin.

Le CTE cte calcule la première révision et le nombre total actuel par application. Le CTE évite les calculs répétés. Cela devrait aider un peu.
Il est toujours matérialisé avant Postgres 12 et devrait être matérialisé automatiquement dans Postgres 12 car il est utilisé plusieurs fois dans la requête principale. Sinon, vous pouvez ajouter le mot clé MATERIALIZED dans Postgres 12 ou version ultérieure pour le forcer. Voir :

Le generate_series() optimisé call produit la série de jours de la première à la dernière revue. Voir :

Enfin, le LEFT JOIN LATERAL vous avez déjà découvert. Mais comme plusieurs applications peuvent être liées pour le plus grand nombre d'avis, récupérez tous les gagnants, qui peuvent être de 0 à n applications. La requête regroupe tous les gagnants quotidiens dans un tableau, nous obtenons donc une seule ligne de résultat par review_window_start . Vous pouvez également définir des conditions de départage pour en obtenir au plus un gagnant. Voir :