Không rõ bạn xác định loại type
cho mỗi thời kỳ. Tôi đã chọn số lượng tối thiểu.
Giả sử định nghĩa bảng cơ bản này:
CREATE TABLE tbl (person text, eventdate date, type int);
Về cơ bản, tôi đề xuất chức năng cửa sổ trong hai truy vấn con lồng nhau để xác định các thành viên của cùng một chu kỳ (đảo). Sau đó tổng hợp lại:
SELECT person, period
, min(eventdate) AS startdate
, max(eventdate) AS enddate
, count(*) AS days
, min(type) AS type
FROM (
SELECT person, eventdate, type
, count(gap) OVER (PARTITION BY person ORDER BY eventdate) AS period
FROM (
SELECT person, eventdate, type
, CASE WHEN lag(eventdate) OVER (PARTITION BY person ORDER BY eventdate)
> eventdate - 6 -- within 5 days
THEN NULL -- same period
ELSE TRUE -- next period
END AS gap
FROM tbl
) sub
) sub
GROUP BY person, period
ORDER BY person, period;
Kết quả (dựa trên dữ liệu mẫu của bạn):
person | period | startdate | enddate | days | type
----------+--------+------------+------------+------+------
<uuid-1> | 1 | 2016-05-14 | 2016-05-22 | 5 | 300
<uuid-1> | 2 | 2016-05-30 | 2016-06-01 | 2 | 300
<uuid-1> | 3 | 2016-06-21 | 2016-06-21 | 1 | 300
<uuid-2> | 1 | 2016-05-22 | 2016-05-27 | 2 | 301
<uuid-2> | 2 | 2016-06-15 | 2016-06-23 | 4 | 300
<uuid-2> | 3 | 2016-06-30 | 2016-06-30 | 1 | 300
<uuid-3> | 1 | 2016-05-14 | 2016-05-14 | 1 | 300
<uuid-3> | 2 | 2016-06-30 | 2016-06-30 | 1 | 300
<uuid-4> | 1 | 2016-06-16 | 2016-06-16 | 1 | 300
<uuid-4> | 2 | 2016-06-30 | 2016-06-30 | 1 | 300
<uuid-5> | 1 | 2016-06-20 | 2016-06-20 | 1 | 300
Nếu cùng một ngày cho cùng một người, bạn có thể nhập nhiều lần với các loại khác nhau và bạn chỉ muốn đếm khác biệt ngày, hãy làm cho nó:count(DISTINCT eventdate) AS days
.
Có liên quan, với giải thích chi tiết:
- Chọn chuỗi liên tục dài nhất
- Cách gắn nhãn các nhóm trong postgresql khi quyền thuộc về nhóm phụ thuộc vào dòng trước?
BTW, eventdate - 6
hoạt động cho kiểu dữ liệu date
, nhưng không dành cho timestamp
: