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

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

Chỉ trả lại vài phút với hoạt động

Ngắn nhất

SELECT DISTINCT
       date_trunc('minute', "when") AS minute
     , count(*) OVER (ORDER BY date_trunc('minute', "when")) AS running_ct
FROM   mytable
ORDER  BY 1;

Sử dụng date_trunc() , nó trả về chính xác những gì bạn cần.

Không bao gồm id trong truy vấn, vì bạn muốn GROUP BY lát cắt phút.

count() thường được sử dụng như một hàm tổng hợp đơn giản. Thêm một OVER mệnh đề làm cho nó một chức năng cửa sổ. Bỏ qua PARTITION BY trong định nghĩa cửa sổ - bạn muốn số lượng đang chạy trên tất cả các hàng . Theo mặc định, số đó được tính từ hàng đầu tiên đến hàng cuối cùng của hàng hiện tại như được xác định bởi ORDER BY . Hướng dẫn sử dụng:

Tùy chọn khung mặc định là RANGE UNBOUNDED PRECEDING , có tên là RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW . Với ORDER BY , điều này đặt khung là tất cả các hàng từ phân vùng bắt đầu thông qua ORDER BY cuối cùng của hàng hiện tại ngang hàng.

Và điều đó xảy ra là chính xác những gì bạn cần.

Sử dụng count(*) thay vì count(id) . Nó phù hợp hơn với câu hỏi của bạn ("số hàng"). Nó thường hơi nhanh hơn hơn count(id) . Và, mặc dù chúng tôi có thể giả định rằng idNOT NULL , nó chưa được chỉ định trong câu hỏi, vì vậy count(id) sai , nói đúng ra, vì giá trị NULL không được tính bằng count(id) .

Bạn không thể GROUP BY các lát cắt phút ở cùng cấp độ truy vấn. Các hàm tổng hợp được áp dụng trước chức năng cửa sổ, chức năng cửa sổ count(*) sẽ chỉ thấy 1 hàng mỗi phút theo cách này.
Tuy nhiên, bạn có thể SELECT DISTINCT , bởi vì DISTINCT được áp dụng sau chức năng cửa sổ.

ORDER BY 1 chỉ là cách viết tắt của ORDER BY date_trunc('minute', "when") tại đây.
1 là một tham chiếu tham chiếu vị trí đến biểu thức đầu tiên trong SELECT danh sách.

Sử dụng to_char() nếu bạn cần định dạng kết quả. Như:

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");

Nhanh nhất

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;

Giống như phần trên, nhưng:

Tôi sử dụng một truy vấn con để tổng hợp và đếm số hàng mỗi phút. Bằng cách này, chúng tôi nhận được 1 hàng mỗi phút mà không cần DISTINCT trong SELECT bên ngoài .

Sử dụng sum() như chức năng tổng hợp cửa sổ bây giờ để cộng tổng số từ truy vấn con.

Tôi thấy điều này về cơ bản là nhanh hơn đáng kể với nhiều hàng mỗi phút.

Bao gồm các phút không có hoạt động

Ngắn nhất

@GabiMe đã hỏi trong một nhận xét về cách nhận hàng eone cho mọi minute trong khung thời gian, bao gồm cả những khung thời gian không có sự kiện nào xảy ra (không có hàng trong bảng cơ sở):

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;

Tạo một hàng cho mỗi phút trong khung thời gian giữa sự kiện đầu tiên và sự kiện cuối cùng với generate_series() - tại đây trực tiếp dựa trên các giá trị tổng hợp từ truy vấn con.

LEFT JOIN cho tất cả các dấu thời gian được cắt ngắn thành phút và đếm. NULL giá trị (nơi không tồn tại hàng) không thêm vào số lượng đang chạy.

Nhanh nhất

Với 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;

Một lần nữa, tổng hợp và đếm số hàng mỗi phút trong bước đầu tiên, nó không cần đến DISTINCT sau này .

Khác với count() , sum() có thể trả về NULL . Mặc định thành 0 với COALESCE .

Với nhiều hàng và một chỉ mục trên "when" phiên bản có truy vấn con này nhanh nhất trong số một vài biến thể mà tôi đã thử nghiệm với 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. Mẹo triển khai PostgreSQL trên nền tảng đám mây kết hợp

  2. Cách Cosh () hoạt động trong PostgreSQL

  3. Hiển thị hình ảnh trong Ireports bằng PostgreSql

  4. Cách tìm các bản ghi trùng lặp trong PostgreSQL

  5. SQLalchemy không thực hiện các thay đổi khi thiết lập vai trò