Jag tror det här är vad du letar efter:
Postgres 13 eller senare
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
gör det lite billigare. Tillagd i Postgres 13 (för närvarande beta). Se:
Postgres 12 eller äldre
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<>fiol här
Samma som ovan, men utan WITH TIES
.
Vi behöver inte involvera tabellen apps
alls. Tabellen reviews
har all information vi behöver.
CTE cte
beräknar tidigaste recension och nuvarande totala antal per app. CTE undviker upprepade beräkningar. Borde hjälpa en del.
Det materialiseras alltid före Postgres 12, och bör materialiseras automatiskt i Postgres 12 eftersom det används många gånger i huvudfrågan. Annars kan du lägga till sökordet MATERIALIZED
i Postgres 12 eller senare för att tvinga fram det. Se:
Den optimerade generate_series()
call producerar serien av dagar från tidigaste till senaste recension. Se:
- Genereringstid serie mellan två datum i PostgreSQL
- Gå med i en räkningsfråga på en generera_serie i postgres och hämta även null-värden som "0"
Slutligen, LEFT JOIN LATERAL
du redan upptäckt. Men eftersom flera appar kan kopplas för flest recensioner, hämta alla vinnare, vilket kan vara 0 - n appar. Frågan samlar alla dagliga vinnare i en array, så vi får en enda resultatrad per review_window_start
. Alternativt, definiera tiebreaker för att få högst en vinnare. Se: