PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Holen Sie sich Apps mit der höchsten Bewertungszahl seit einer dynamischen Reihe von Tagen

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:

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: