Xây dựng trên bảng này (không sử dụng từ khóa SQL "date" dưới dạng tên cột.):
CREATE TABLE tbl(
pid int
, the_date date
, PRIMARY KEY (pid, the_date)
);
Truy vấn:
SELECT pid, the_date
, row_number() OVER (PARTITION BY pid, grp ORDER BY the_date) AS in_streak
FROM (
SELECT *
, the_date - '2000-01-01'::date
- row_number() OVER (PARTITION BY pid ORDER BY the_date) AS grp
FROM tbl
) sub
ORDER BY pid, the_date;
Trừ một date
từ một date
khác mang lại integer
. Vì bạn đang tìm kiếm các ngày liên tiếp, nên mỗi hàng tiếp theo sẽ lớn hơn một . Nếu chúng ta trừ đi row_number()
từ đó, toàn bộ chuỗi kết thúc trong cùng một nhóm (grp
) per pid
. Sau đó, thật đơn giản để xử lý số lượng mỗi nhóm.
grp
được tính với hai phép trừ, sẽ nhanh nhất. Một giải pháp thay thế nhanh chóng không kém có thể là:
the_date - row_number() OVER (PARTITION BY pid ORDER BY the_date) * interval '1d' AS grp
Một phép nhân, một phép trừ. Việc nối và ép kiểu chuỗi là tốn kém hơn. Kiểm tra với EXPLAIN ANALYZE
.
Đừng quên phân vùng theo pid
bổ sung trong cả hai các bước hoặc bạn sẽ vô tình trộn các nhóm cần được tách biệt.
Sử dụng truy vấn con, vì truy vấn đó thường nhanh hơn CTE . Không có gì ở đây mà một truy vấn con thuần túy không thể làm được.
Và vì bạn đã đề cập đến nó:dense_rank()
rõ ràng là không cần thiết ở đây. Cơ bản row_number()
thực hiện công việc.