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:
- Generando tiempo serie entre dos fechas en PostgreSQL
- Únase a una consulta de conteo en un generate_series en postgres y también recupere valores nulos como "0"
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: