sql >> Database teknologi >  >> RDS >> PostgreSQL

Få apps med det højeste antal anmeldelser siden en dynamisk række af dage

Jeg tror dette er hvad du leder efter:

Postgres 13 eller nyere

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 lidt billigere. Tilføjet i Postgres 13 (i øjeblikket 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<>fiddle her

Samme som ovenfor, men uden WITH TIES .

Vi behøver ikke at involvere tabellen apps overhovedet. Tabellen reviews har alle de oplysninger, vi har brug for.

CTE cte beregner den tidligste anmeldelse og det aktuelle samlede antal pr. app. CTE undgår gentagen beregning. Det burde hjælpe en del.
Det er altid materialiseret før Postgres 12, og bør materialiseres automatisk i Postgres 12, da det bruges mange gange i hovedforespørgslen. Ellers kan du tilføje søgeordet MATERIALIZED i Postgres 12 eller senere for at tvinge det. Se:

Den optimerede generate_series() call producerer rækken af ​​dage fra tidligst til seneste anmeldelse. Se:

Til sidst, LEFT JOIN LATERAL du allerede har opdaget. Men da flere apps kan knyttes for de fleste anmeldelser, hent alle vindere, som kan være 0 - n apps. Forespørgslen samler alle daglige vindere i en matrix, så vi får en enkelt resultatrække pr. review_window_start . Alternativt kan du definere tiebreaker for at få højst én vinder. Se:



  1. Fjerner duplikerede rækker fra tabellen i Oracle

  2. Løsninger til, hvordan du læser SQL Server-transaktionslogfil uden fejl

  3. MySQL bliver ved med at gå ned

  4. Diskplads implikationer af at indstille MySQL kolonneværdi til NULL i stedet for 0 eller ''