sql >> Database >  >> RDS >> PostgreSQL

Download apps met het hoogste aantal recensies sinds een dynamische reeks van dagen

Ik denk dit is wat je zoekt:

Postgres 13 of nieuwer

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 maakt het wat goedkoper. Toegevoegd in Postgres 13 (momenteel bèta). Zie:

Postgres 12 of ouder

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

Hetzelfde als hierboven, maar zonder WITH TIES .

We hoeven de tabel apps niet te betrekken helemaal niet. De tabel reviews heeft alle informatie die we nodig hebben.

De CTE cte berekent de vroegste beoordeling en het huidige totale aantal per app. De CTE vermijdt herhaalde berekeningen. Zou aardig wat moeten helpen.
Het wordt altijd gematerialiseerd vóór Postgres 12 en zou automatisch moeten worden gematerialiseerd in Postgres 12, omdat het vaak wordt gebruikt in de hoofdquery. Anders kunt u het trefwoord MATERIALIZED toevoegen in Postgres 12 of later om het te forceren. Zie:

De geoptimaliseerde generate_series() call produceert de reeks dagen van de eerste tot de laatste beoordeling. Zie:

Ten slotte, de LEFT JOIN LATERAL je hebt het al ontdekt. Maar aangezien meerdere apps kunnen binden voor de meeste beoordelingen haalt u alle winnaars op, dit kunnen 0 - n apps zijn. De zoekopdracht verzamelt alle dagelijkse winnaars in een array, zodat we één resultaatrij per review_window_start krijgen. . U kunt ook tiebreaker(s) definiëren om maximaal één te krijgen winnaar. Zie:



  1. probleem met Add_month in oracle, ik moet een factureringscyclus genereren

  2. Uitzondering dubbele sleutel invoegen opvangen

  3. Wat is de perfecte toolbox voor PL/SQL-ontwikkeling?

  4. Opgegeven sleutel was te lang; maximale sleutellengte is 767 bytes - ASPNet Identity MySQL