Kembalikan hanya beberapa menit dengan aktivitas
Terpendek
SELECT DISTINCT
date_trunc('minute', "when") AS minute
, count(*) OVER (ORDER BY date_trunc('minute', "when")) AS running_ct
FROM mytable
ORDER BY 1;
Gunakan date_trunc()
, ini mengembalikan apa yang Anda butuhkan.
Jangan sertakan id
dalam kueri, karena Anda ingin GROUP BY
irisan kecil.
count()
biasanya digunakan sebagai fungsi agregat polos. Menambahkan OVER
klausa membuatnya menjadi fungsi jendela. Abaikan PARTITION BY
dalam definisi jendela - Anda ingin penghitungan berjalan di semua baris . Secara default, itu dihitung dari baris pertama hingga rekan terakhir dari baris saat ini seperti yang didefinisikan oleh ORDER BY
. Panduan:
Opsi pembingkaian default adalah
RANGE UNBOUNDED PRECEDING
, yang sama denganRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
. DenganORDER BY
, ini menetapkan bingkai menjadi semua baris dari partisi yang dimulai melaluiORDER BY
terakhir baris saat ini rekan.
Dan itu terjadi tepat yang Anda butuhkan.
Gunakan count(*)
daripada count(id)
. Lebih cocok dengan pertanyaan Anda ("jumlah baris"). Biasanya sedikit lebih cepat dari count(id)
. Dan, sementara kita mungkin berasumsi bahwa id
adalah NOT NULL
, belum ditentukan dalam pertanyaan, jadi count(id)
apakah salah , sebenarnya, karena nilai NULL tidak dihitung dengan count(id)
.
Anda tidak dapat GROUP BY
potongan menit pada tingkat kueri yang sama. Fungsi agregat diterapkan sebelum fungsi jendela, fungsi jendela count(*)
hanya akan melihat 1 baris per menit dengan cara ini.
Namun, Anda dapat SELECT DISTINCT
, karena DISTINCT
diterapkan setelah fungsi jendela.
ORDER BY 1
hanyalah singkatan dari ORDER BY date_trunc('minute', "when")
di sini.1
adalah referensi referensi posisi ke ekspresi pertama dalam SELECT
daftar.
Gunakan to_char()
jika Anda perlu memformat hasilnya. Seperti:
SELECT DISTINCT
to_char(date_trunc('minute', "when"), 'DD.MM.YYYY HH24:MI') AS minute
, count(*) OVER (ORDER BY date_trunc('minute', "when")) AS running_ct
FROM mytable
ORDER BY date_trunc('minute', "when");
Tercepat
SELECT minute, sum(minute_ct) OVER (ORDER BY minute) AS running_ct
FROM (
SELECT date_trunc('minute', "when") AS minute
, count(*) AS minute_ct
FROM tbl
GROUP BY 1
) sub
ORDER BY 1;
Mirip seperti di atas, tapi:
Saya menggunakan subquery untuk mengumpulkan dan menghitung baris per menit. Dengan cara ini kita mendapatkan 1 baris per menit tanpa DISTINCT
di bagian luar SELECT
.
Gunakan sum()
sebagai fungsi agregat jendela sekarang untuk menjumlahkan jumlah dari subkueri.
Saya menemukan ini jauh lebih cepat dengan banyak baris per menit.
Sertakan menit tanpa aktivitas
Terpendek
@GabiMe bertanya dalam komentar bagaimana cara mendapatkan satu baris untuk setiap minute
dalam kerangka waktu, termasuk di mana tidak ada peristiwa yang terjadi (tidak ada baris di tabel dasar):
SELECT DISTINCT
minute, count(c.minute) OVER (ORDER BY minute) AS running_ct
FROM (
SELECT generate_series(date_trunc('minute', min("when"))
, max("when")
, interval '1 min')
FROM tbl
) m(minute)
LEFT JOIN (SELECT date_trunc('minute', "when") FROM tbl) c(minute) USING (minute)
ORDER BY 1;
Hasilkan baris untuk setiap menit dalam kerangka waktu antara peristiwa pertama dan terakhir dengan generate_series()
- di sini langsung berdasarkan nilai agregat dari subkueri.
LEFT JOIN
ke semua stempel waktu yang dipotong menjadi menit dan hitungan. NULL
nilai (di mana tidak ada baris) tidak menambah hitungan berjalan.
Tercepat
Dengan CTE:
WITH cte AS (
SELECT date_trunc('minute', "when") AS minute, count(*) AS minute_ct
FROM tbl
GROUP BY 1
)
SELECT m.minute
, COALESCE(sum(cte.minute_ct) OVER (ORDER BY m.minute), 0) AS running_ct
FROM (
SELECT generate_series(min(minute), max(minute), interval '1 min')
FROM cte
) m(minute)
LEFT JOIN cte USING (minute)
ORDER BY 1;
Sekali lagi, gabungkan dan hitung baris per menit pada langkah pertama, ini menghilangkan kebutuhan untuk DISTINCT
nanti .
Berbeda dari count()
, sum()
dapat mengembalikan NULL
. Bawaan ke 0
dengan COALESCE
.
Dengan banyak baris dan indeks pada "when"
versi dengan subquery ini adalah yang tercepat di antara beberapa varian yang saya uji dengan Postgres 9.1 - 9.4:
SELECT m.minute
, COALESCE(sum(c.minute_ct) OVER (ORDER BY m.minute), 0) AS running_ct
FROM (
SELECT generate_series(date_trunc('minute', min("when"))
, max("when")
, interval '1 min')
FROM tbl
) m(minute)
LEFT JOIN (
SELECT date_trunc('minute', "when") AS minute
, count(*) AS minute_ct
FROM tbl
GROUP BY 1
) c USING (minute)
ORDER BY 1;