sql >> Base de Datos >  >> RDS >> PostgreSQL

Obtenga aplicaciones con el recuento de reseñas más alto desde una serie dinámica de días

yo creo esto es lo que buscas:

Postgres 13 o posterior

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 hace un poco más barato. Agregado en Postgres 13 (actualmente beta). Ver:

Postgres 12 o anterior

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<>fiddle aquí

Igual que arriba, pero sin WITH TIES .

No necesitamos involucrar la tabla apps en absoluto. La tabla reviews tiene toda la información que necesitamos.

El CTE cte calcula la revisión más antigua y el recuento total actual por aplicación. El CTE evita el cómputo repetido. Debería ayudar bastante.
Siempre se materializa antes de Postgres 12 y debería materializarse automáticamente en Postgres 12, ya que se usa muchas veces en la consulta principal. De lo contrario, podría agregar la palabra clave MATERIALIZED en Postgres 12 o posterior para forzarlo. Ver:

El generate_series() optimizado call produce la serie de días desde la primera hasta la última revisión. Ver:

Finalmente, el LEFT JOIN LATERAL ya lo descubriste. Pero dado que varias aplicaciones pueden vincularse para obtener la mayor cantidad de reseñas, recupere todos los ganadores, que pueden ser 0 - n aplicaciones. La consulta agrega todos los ganadores diarios en una matriz, por lo que obtenemos una sola fila de resultados por review_window_start . Alternativamente, defina desempates para obtener como máximo uno ganador. Ver: