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ớiORDER 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 quaORDER 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 id
là NOT NULL
, nó chưa được chỉ định trong câu hỏi, vì vậy count(id)
là 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;