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

Cara terbaik untuk menghitung catatan dengan interval waktu sewenang-wenang di Rails+Postgres

Untungnya, Anda menggunakan PostgreSQL. Fungsi jendela generate_series() adalah temanmu.

Kasus uji

Diberikan tabel pengujian berikut (yang Anda seharusnya disediakan):

CREATE TABLE event(event_id serial, ts timestamp);
INSERT INTO event (ts)
SELECT generate_series(timestamp '2018-05-01'
                     , timestamp '2018-05-08'
                     , interval '7 min') + random() * interval '7 min';

Satu acara untuk setiap 7 menit (ditambah 0 hingga 7 menit, secara acak).

Solusi dasar

Kueri ini menghitung peristiwa untuk interval waktu arbitrer apa pun. 17 menit dalam contoh:

WITH grid AS (
   SELECT start_time
        , lead(start_time, 1, 'infinity') OVER (ORDER BY start_time) AS end_time
   FROM  (
      SELECT generate_series(min(ts), max(ts), interval '17 min') AS start_time
      FROM   event
      ) sub
   )
SELECT start_time, count(e.ts) AS events
FROM   grid       g
LEFT   JOIN event e ON e.ts >= g.start_time
                   AND e.ts <  g.end_time
GROUP  BY start_time
ORDER  BY start_time;
  • Kueri mengambil ts minimum dan maksimum dari tabel dasar untuk mencakup rentang waktu yang lengkap. Anda dapat menggunakan rentang waktu arbitrer sebagai gantinya.

  • Berikan apa saja interval waktu sesuai kebutuhan.

  • Menghasilkan satu baris untuk setiap slot waktu. Jika tidak ada kejadian yang terjadi selama interval tersebut, hitungannya adalah 0 .

  • Pastikan untuk menangani batas atas dan bawah dengan benar:

    • Hasil tak terduga dari kueri SQL dengan stempel waktu ANTARA
  • Fungsi jendela lead() memiliki fitur yang sering diabaikan:ini dapat memberikan default ketika tidak ada baris terdepan. Menyediakan 'infinity' dalam contoh. Jika tidak, interval terakhir akan dipotong dengan batas atas NULL .

Setara minimal

Kueri di atas menggunakan CTE dan lead() dan sintaksis verbose. Elegan dan mungkin lebih mudah dipahami, tetapi sedikit lebih mahal. Ini adalah versi yang lebih pendek, lebih cepat, dan minimal:

SELECT start_time, count(e.ts) AS events
FROM  (SELECT generate_series(min(ts), max(ts), interval '17 min') FROM event) g(start_time)
LEFT   JOIN event e ON e.ts >= g.start_time
                   AND e.ts <  g.start_time + interval '17 min'
GROUP  BY 1
ORDER  BY 1;

Contoh untuk "setiap 15 menit dalam seminggu terakhir"`

Dan memformat dengan to_char() .

SELECT to_char(start_time, 'YYYY-MM-DD HH24:MI'), count(e.ts) AS events
FROM   generate_series(date_trunc('day', localtimestamp - interval '7 days')
                     , localtimestamp
                     , interval '15 min') g(start_time)
LEFT   JOIN event e ON e.ts >= g.start_time
                   AND e.ts <  g.start_time + interval '15 min'
GROUP  BY start_time
ORDER  BY start_time;

Masih ORDER BY dan GROUP BY pada stempel waktu yang mendasari nilai , bukan pada string yang diformat. Itu lebih cepat dan lebih dapat diandalkan.

db<>main biola di sini

Jawaban terkait menghasilkan jumlah berjalan selama jangka waktu:

  • PostgreSQL:menjalankan hitungan baris untuk kueri 'menurut menit'



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL - tetapkan nilai sel default sesuai dengan nilai sel lain

  2. Cara Memantau PostgreSQL menggunakan Nagios

  3. Bagaimana cara menambahkan kolom jika tidak ada di PostgreSQL?

  4. Pembuatan data dan kualitas perangkat keras

  5. Apakah Postgres mendukung transaksi bersarang atau otonom?