PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Вземете приложения с най-висок брой прегледи от динамична поредица от дни

Аз мисля това е, което търсите:

Postgres 13 или по-нов

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 го прави малко по-евтин. Добавен в Postgres 13 (в момента бета). Вижте:

Postgres 12 или по-стара версия

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 тук

Същото като по-горе, но без WITH TIES .

Не е необходимо да включваме таблицата apps изобщо. Таблицата reviews има цялата информация, от която се нуждаем.

CTE cte изчислява най-ранния преглед и текущия общ брой за приложение. CTE избягва повторното изчисление. Трябва да помогне доста.
Винаги се материализира преди Postgres 12 и трябва да се материализира автоматично в Postgres 12, тъй като се използва много пъти в основната заявка. В противен случай можете да добавите ключовата дума MATERIALIZED в Postgres 12 или по-нова, за да го принудите. Вижте:

Оптимизираният generate_series() повикването създава поредица от дни от най-ранния до последния преглед. Вижте:

И накрая, LEFT JOIN LATERAL вече си открил. Но тъй като няколко приложения могат да се обвържат за най-много отзиви, извлечете всички победители, които могат да бъдат 0 - n приложения. Заявката агрегира всички дневни победители в масив, така че получаваме един ред с резултат на review_window_start . Като алтернатива, дефинирайте тайбрек(ове), за да получите най-много един победител. Вижте:



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да премахнете дубликати, които се генерират с array_agg postgres функция

  2. Как мога да прикача база данни към приложение в Heroku?

  3. Postgresql как да изберете стойности в колоната от една таблица, които са налични само в друга таблица?

  4. Мога ли да използвам функциите на Postgres, за да намеря точки във въртящ се правоъгълник с фиксиран размер?

  5. Проблем със създаването на Postgres RDS в Cloudformation Template