PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Cách tốt nhất để đếm các bản ghi theo khoảng thời gian tùy ý trong Rails + Postgres

May mắn thay, bạn đang sử dụng PostgreSQL. Hàm cửa sổ generate_series() là bạn của bạn.

Trường hợp thử nghiệm

Cho bảng kiểm tra sau (mà bạn lẽ ra phải cung cấp):

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';

Một sự kiện cứ sau 7 phút (ngẫu nhiên cộng với 0 đến 7 phút).

Giải pháp cơ bản

Truy vấn này đếm các sự kiện cho bất kỳ khoảng thời gian tùy ý nào. 17 phút trong ví dụ:

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;
  • Truy vấn truy xuất ts tối thiểu và tối đa từ bảng cơ sở để bao gồm toàn bộ phạm vi thời gian. Thay vào đó, bạn có thể sử dụng một khoảng thời gian tùy ý.

  • Cung cấp bất kỳ khoảng thời gian khi cần thiết.

  • Tạo một hàng cho mọi ca thời gian. Nếu không có sự kiện nào xảy ra trong khoảng thời gian đó, số lượng là 0 .

  • Đảm bảo xử lý giới hạn trên và giới hạn dưới một cách chính xác:

    • Kết quả không mong muốn từ truy vấn SQL với GIỮA các dấu thời gian
  • Hàm cửa sổ lead() có một tính năng thường bị bỏ qua:nó có thể cung cấp giá trị mặc định khi không tồn tại hàng đầu. Cung cấp 'infinity' trong ví dụ. Nếu không, khoảng thời gian cuối cùng sẽ bị cắt bằng một giới hạn trên NULL .

Tương đương tối thiểu

Truy vấn trên sử dụng CTE và lead() và cú pháp dài dòng. Thanh lịch và có thể dễ hiểu hơn, nhưng đắt hơn một chút. Đây là phiên bản ngắn hơn, nhanh hơn, tối thiểu:

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;

Ví dụ cho "15 phút một lần trong tuần qua" `

Và định dạng với 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;

Vẫn ORDER BYGROUP BY trên dấu thời gian cơ bản giá trị , không phải trên chuỗi đã định dạng. Điều đó nhanh hơn và đáng tin cậy hơn.

db <> fiddle here

Câu trả lời có liên quan tạo ra số lượng đang chạy trong khung thời gian:

  • PostgreSQL:số hàng đang chạy cho truy vấn 'theo phút'



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm cách nào để tạo chỉ mục trên trường JSON trong Postgres?

  2. Mẹo &Thủ thuật để Điều hướng Cộng đồng PostgreSQL

  3. Tổng quan về Biên dịch Just-in-Time (JIT) cho PostgreSQL

  4. Cách EXCEPT hoạt động trong PostgreSQL

  5. Làm cách nào để nhập tệp JSON vào PostgreSQL?