Spróbuj tego: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(*);
Zobacz postęp zapytania tutaj:http://www.sqlfiddle.com/#!3/ c3365/20
Jak to działa, porównaj bieżącą datę zakończenia z następną datą rozpoczęcia i sprawdź różnicę dat:
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;
Wyjście:
| 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 |
Następnie sprawdź, czy członek ma taką samą liczbę roszczeń bez luk w łącznej liczbie roszczeń:
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;
Wyjście:
| MEMBERCODE | COUNT | GAPLESS_COUNT |
--------------------------------------
| 1 | 3 | 3 |
| 2 | 2 | 1 |
Na koniec odfiltruj ich, członków bez luk w swoich roszczeniach:
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(*);
Wyjście:
| MEMBERCODE |
--------------
| 1 |
Pamiętaj, że nie musisz wykonywać COUNT(*) > 1
aby wykryć członków z 2 lub więcej roszczeniami. Zamiast używać LEFT JOIN
, używamy JOIN
, spowoduje to automatyczne odrzucenie członków, którzy nie mają jeszcze drugiego roszczenia. Oto wersja (dłuższa), jeśli zdecydujesz się użyć LEFT JOIN
zamiast tego (to samo wyjście co powyżej):
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
Oto jak wyświetlić dane powyższego zapytania przed filtrowaniem:
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;
Wyjście:
| 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) |
EDYTUJ w sprawie wyjaśnienia wymagań:
W swoim wyjaśnieniu chcesz uwzględnić członków, którzy jeszcze nie mają drugiego roszczenia, zrób to: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;
Wyjście:
| MEMBERCODE |
--------------
| 1 |
| 3 |
Technika polega na zliczeniu nextstartdate
członka , jeśli nie mają daty następnej daty rozpoczęcia (tj. count(nextstartdate) = 0
), to są to tylko pojedyncze oświadczenia i są one również ważne, a następnie po prostu dołącz ten OR
warunek:
or count(nextstartdate) = 0;
Właściwie warunek poniżej też wystarczy, chciałem jednak, aby zapytanie było bardziej samodokumentujące, dlatego polecam liczyć na następną datę startową użytkownika. Oto alternatywny warunek liczenia członków, którzy nie mają jeszcze drugiego roszczenia:
or count(*) = 1;
Btw, musimy również zmienić porównanie z tego:
sum(case when gap <= 1 then 1 end) = count(*)
do tego (ponieważ używamy LEFT JOIN
teraz):
sum(case when gap <= 1 then 1 end) = count(gap)