Ich denke das ist, was Sie suchen:
Postgres 13 oder neuer
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
macht es etwas billiger. Hinzugefügt in Postgres 13 (derzeit Beta). Siehe:
Postgres 12 oder älter
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 hier
Wie oben, aber ohne WITH TIES
.
Wir müssen die Tabelle apps
nicht einbeziehen überhaupt. Die Tabelle reviews
hat alle Informationen, die wir brauchen.
Der CTE cte
berechnet die früheste Überprüfung und die aktuelle Gesamtzahl pro App. Der CTE vermeidet wiederholte Berechnungen. Sollte ziemlich hilfreich sein.
Es wird immer vor Postgres 12 materialisiert und sollte in Postgres 12 automatisch materialisiert werden, da es viele Male in der Hauptabfrage verwendet wird. Andernfalls könnten Sie das Schlüsselwort MATERIALIZED
hinzufügen
in Postgres 12 oder höher, um es zu erzwingen. Siehe:
Die optimierte generate_series()
call erzeugt die Reihe der Tage von der frühesten bis zur letzten Überprüfung. Siehe:
- Zeit generieren Reihe zwischen zwei Daten in PostgreSQL
- Nehmen Sie an einer Zählabfrage für eine generate_series in Postgres teil und rufen Sie auch Nullwerte als "0" ab
Schließlich der LEFT JOIN LATERAL
hast du schon entdeckt. Aber da können mehrere Apps binden Rufen Sie für die meisten Bewertungen alle Gewinner ab, bei denen es sich um 0 bis n Apps handeln kann. Die Abfrage aggregiert alle Tagesgewinner in einem Array, sodass wir eine einzelne Ergebniszeile pro review_window_start
erhalten . Alternativ können Sie Tiebreaker definieren, um höchstens einen zu erhalten Gewinner. Siehe: