Saya berpikir ini yang kamu cari:
Postgres 13 atau yang lebih baru
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
membuatnya sedikit lebih murah. Ditambahkan di Postgres 13 (saat ini beta). Lihat:
Postgres 12 atau lebih lama
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 di sini
Sama seperti di atas, tapi tanpa WITH TIES
.
Kami tidak perlu melibatkan tabel apps
sama sekali. Tabel reviews
memiliki semua informasi yang kami butuhkan.
cte
CTE menghitung ulasan paling awal &jumlah total saat ini per aplikasi. CTE menghindari perhitungan berulang. Harus sedikit membantu.
Itu selalu terwujud sebelum Postgres 12, dan harus terwujud secara otomatis di Postgres 12 karena digunakan berkali-kali dalam permintaan utama. Jika tidak, Anda dapat menambahkan kata kunci MATERIALIZED
di Postgres 12 atau lebih baru untuk memaksanya. Lihat:
generate_series()
yang dioptimalkan panggilan menghasilkan serangkaian hari dari ulasan paling awal hingga terbaru. Lihat:
- Menghasilkan waktu seri antara dua tanggal di PostgreSQL
- Bergabunglah dengan kueri penghitungan pada generate_series di postgres dan juga ambil nilai Null sebagai "0"
Terakhir, LEFT JOIN LATERAL
Anda sudah menemukan. Namun karena beberapa aplikasi dapat mengikat untuk ulasan terbanyak, ambil semua pemenang, yang dapat berupa 0 - n aplikasi. Kueri menggabungkan semua pemenang harian ke dalam larik, jadi kami mendapatkan satu baris hasil per review_window_start
. Atau, tentukan tiebreaker untuk mendapatkan paling banyak satu pemenang. Lihat: