Hãy thử cách này: http://www.sqlfiddle.com/#!3/c3365/ 20
with s as
(
select *, row_number() over(partition by membercode order by startdate) rn
from tbl
)
,gaps as
(
select a.membercode, a.startdate, a.enddate, b.startdate as nextstartdate
,datediff(d, a.enddate, b.startdate) as gap
from s a
join s b on b.membercode = a.membercode and b.rn = a.rn + 1
)
select membercode
from gaps
group by membercode
having sum(case when gap <= 1 then 1 end) = count(*);
Xem tiến trình truy vấn tại đây: http://www.sqlfiddle.com/#!3/ c3365 / 20
Cách hoạt động, so sánh ngày kết thúc hiện tại với ngày bắt đầu tiếp theo và kiểm tra khoảng cách ngày:
with s as
(
select *, row_number() over(partition by membercode order by startdate) rn
from tbl
)
select a.membercode, a.startdate, a.enddate, b.startdate as nextstartdate
,datediff(d, a.enddate, b.startdate) as gap
from s a
join s b on b.membercode = a.membercode and b.rn = a.rn + 1;
Đầu ra:
| MEMBERCODE | STARTDATE | ENDDATE | NEXTSTARTDATE | GAP |
--------------------------------------------------------------
| 1 | 2010-01-15 | 2010-01-20 | 2010-01-19 | -1 |
| 1 | 2010-01-19 | 2010-01-22 | 2010-01-20 | -2 |
| 1 | 2010-01-20 | 2010-01-25 | 2010-01-26 | 1 |
| 2 | 2010-01-20 | 2010-01-25 | 2010-01-30 | 5 |
| 2 | 2010-01-30 | 2010-02-05 | 2010-02-04 | -1 |
Sau đó, kiểm tra xem một thành viên có cùng số lượng yêu cầu mà không có khoảng cách so với tổng số yêu cầu của họ:
with s as
(
select *, row_number() over(partition by membercode order by startdate) rn
from tbl
)
,gaps as
(
select a.membercode, a.startdate, a.enddate, b.startdate as nextstartdate
,datediff(d, a.enddate, b.startdate) as gap
from s a
join s b on b.membercode = a.membercode and b.rn = a.rn + 1
)
select membercode, count(*) as count, sum(case when gap <= 1 then 1 end) as gapless_count
from gaps
group by membercode;
Đầu ra:
| MEMBERCODE | COUNT | GAPLESS_COUNT |
--------------------------------------
| 1 | 3 | 3 |
| 2 | 2 | 1 |
Cuối cùng, lọc họ, những thành viên không có lỗ hổng trong tuyên bố của họ:
with s as
(
select *, row_number() over(partition by membercode order by startdate) rn
from tbl
)
,gaps as
(
select a.membercode, a.startdate, a.enddate, b.startdate as nextstartdate
,datediff(d, a.enddate, b.startdate) as gap
from s a
join s b on b.membercode = a.membercode and b.rn = a.rn + 1
)
select membercode
from gaps
group by membercode
having sum(case when gap <= 1 then 1 end) = count(*);
Đầu ra:
| MEMBERCODE |
--------------
| 1 |
Lưu ý rằng bạn không cần thực hiện COUNT(*) > 1
để phát hiện các thành viên có từ 2 yêu cầu trở lên. Thay vì sử dụng LEFT JOIN
, chúng tôi sử dụng JOIN
, điều này sẽ tự động loại bỏ các thành viên chưa có yêu cầu thứ hai. Đây là phiên bản (dài hơn) nếu bạn chọn sử dụng LEFT JOIN
thay vào đó (đầu ra tương tự như trên):
with s as
(
select *, row_number() over(partition by membercode order by startdate) rn
from tbl
)
,gaps as
(
select a.membercode, a.startdate, a.enddate, b.startdate as nextstartdate
,datediff(d, a.enddate, b.startdate) as gap
from s a
left join s b on b.membercode = a.membercode and b.rn = a.rn + 1
)
select membercode
from gaps
group by membercode
having sum(case when gap <= 1 then 1 end) = count(gap)
and count(*) > 1; -- members who have two ore more claims only
Đây là cách xem dữ liệu của truy vấn trên trước khi lọc:
with s as
(
select *, row_number() over(partition by membercode order by startdate) rn
from tbl
)
,gaps as
(
select a.membercode, a.startdate, a.enddate, b.startdate as nextstartdate
,datediff(d, a.enddate, b.startdate) as gap
from s a
left join s b on b.membercode = a.membercode and b.rn = a.rn + 1
)
select * from gaps;
Đầu ra:
| MEMBERCODE | STARTDATE | ENDDATE | NEXTSTARTDATE | GAP |
-----------------------------------------------------------------
| 1 | 2010-01-15 | 2010-01-20 | 2010-01-19 | -1 |
| 1 | 2010-01-19 | 2010-01-22 | 2010-01-20 | -2 |
| 1 | 2010-01-20 | 2010-01-25 | 2010-01-26 | 1 |
| 1 | 2010-01-26 | 2010-01-30 | (null) | (null) |
| 2 | 2010-01-20 | 2010-01-25 | 2010-01-30 | 5 |
| 2 | 2010-01-30 | 2010-02-05 | 2010-02-04 | -1 |
| 2 | 2010-02-04 | 2010-02-15 | (null) | (null) |
| 3 | 2010-02-15 | 2010-03-02 | (null) | (null) |
CHỈNH SỬA về việc làm rõ yêu cầu:
Khi bạn làm rõ, bạn cũng muốn bao gồm những thành viên chưa có yêu cầu thứ hai, hãy làm điều này thay thế: http://sqlfiddle.com/#!3/c3365/22
with s as
(
select *, row_number() over(partition by membercode order by startdate) rn
from tbl
)
,gaps as
(
select a.membercode, a.startdate, a.enddate, b.startdate as nextstartdate
,datediff(d, a.enddate, b.startdate) as gap
from s a
left join s b on b.membercode = a.membercode and b.rn = a.rn + 1
)
select membercode
from gaps
group by membercode
having sum(case when gap <= 1 then 1 end) = count(gap)
-- members who have yet to have a second claim are valid too
or count(nextstartdate) = 0;
Đầu ra:
| MEMBERCODE |
--------------
| 1 |
| 3 |
Kỹ thuật này là đếm nextstartdate
của thành viên , nếu họ không có ngày bắt đầu tiếp theo (tức là count(nextstartdate) = 0
) thì chúng chỉ là những xác nhận quyền sở hữu duy nhất và cũng hợp lệ, sau đó chỉ cần đính kèm OR
này điều kiện:
or count(nextstartdate) = 0;
Trên thực tế, điều kiện bên dưới cũng sẽ đủ, mặc dù vậy, tôi muốn làm cho truy vấn tự ghi lại nhiều hơn, do đó tôi khuyên bạn nên tính vào ngày bắt đầu tiếp theo của thành viên. Đây là một điều kiện thay thế để tính các thành viên chưa có yêu cầu thứ hai:
or count(*) = 1;
Btw, chúng ta cũng phải thay đổi so sánh từ cái này:
sum(case when gap <= 1 then 1 end) = count(*)
về điều này (vì chúng tôi đang sử dụng LEFT JOIN
bây giờ):
sum(case when gap <= 1 then 1 end) = count(gap)