myślę tego właśnie szukasz:
Postgres 13 lub nowszy
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
sprawia, że jest trochę tańszy. Dodano w Postgres 13 (obecnie beta). Zobacz:
Postgres 12 lub starszy
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 tutaj
Tak samo jak powyżej, ale bez WITH TIES
.
Nie musimy angażować tabeli apps
w ogóle. Tabela reviews
zawiera wszystkie potrzebne nam informacje.
CTE cte
oblicza najwcześniejszą recenzję i aktualną całkowitą liczbę na aplikację. CTE pozwala uniknąć powtórnych obliczeń. Powinno to trochę pomóc.
Zawsze jest zmaterializowane przed Postgresem 12 i powinno zostać zmaterializowane automatycznie w Postgresie 12, ponieważ jest używane wielokrotnie w głównym zapytaniu. W przeciwnym razie możesz dodać słowo kluczowe MATERIALIZED
w Postgres 12 lub nowszym, aby to wymusić. Zobacz:
Zoptymalizowana generate_series()
Zadzwoń produkuje serię dni od najwcześniejszego do ostatniego przeglądu. Zobacz:
- Czas generowania seria między dwiema datami w PostgreSQL
- Dołącz do zapytania licznika w generatorze serii w postgresie, a także pobierz wartości Null jako „0”
Wreszcie LEFT JOIN LATERAL
już odkryłeś. Ale ponieważ wiele aplikacji może wiązać się w przypadku większości recenzji wyszukaj wszystkich zwycięzców, którymi może być 0 – n aplikacji. Zapytanie agreguje wszystkich codziennych zwycięzców w tablicę, więc otrzymujemy jeden wiersz wyników na review_window_start
. Alternatywnie zdefiniuj rozstrzygające remisy, aby uzyskać najwyżej jeden zwycięzca. Zobacz: