PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

PostgreSQL:menjalankan hitungan baris untuk kueri 'menurut menit'

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 dengan RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW . Dengan ORDER BY , ini menetapkan bingkai menjadi semua baris dari partisi yang dimulai melalui ORDER 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;



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. CONSTRAINT untuk memeriksa nilai dari tabel yang terkait dari jarak jauh (melalui join dll.)

  2. Baris perintah Windows PSQL:apakah ada cara untuk mengizinkan login tanpa kata sandi?

  3. PostgreSQL melalui SSH Tunnel

  4. Pemulihan cadangan PostgreSQL dan TimescaleDB menggunakan ClusterControl CLI

  5. Kembalikan beberapa bidang sebagai catatan di PostgreSQL dengan PL/pgSQL