sql >> Databasteknik >  >> RDS >> PostgreSQL

Få appar med det högsta antalet recensioner sedan en dynamisk serie av dagar

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:

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:



  1. konvertera oracle blob till xml-typ

  2. PHP isset() med flera parametrar

  3. Matcha en fras som slutar på ett prefix med fulltextsökning

  4. Göra livesökning på en databas med CodeIgniter, php5 och MySQL