Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

So identifizieren Sie die erste Lücke in mehreren Start- und Enddatumsbereichen für jedes einzelne Mitglied in T-SQL

Versuchen Sie Folgendes: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(*);

Siehe Abfragefortschritt hier:http://www.sqlfiddle.com/#!3/ c3365/20

So funktioniert es:Vergleichen Sie das aktuelle Enddatum mit dem nächsten Startdatum und überprüfen Sie die Datumslücke:

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;

Ausgabe:

| 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 |

Überprüfen Sie dann, ob ein Mitglied die gleiche Anzahl von Ansprüchen ohne Lücken zu seinen Gesamtansprüchen hat:

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;

Ausgabe:

| MEMBERCODE | COUNT | GAPLESS_COUNT |
--------------------------------------
|          1 |     3 |             3 |
|          2 |     2 |             1 |

Filtern Sie sie schließlich, Mitglieder ohne Lücken in ihren Ansprüchen:

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(*);

Ausgabe:

| MEMBERCODE |
--------------
|          1 |

Beachten Sie, dass Sie COUNT(*) > 1 nicht ausführen müssen um Mitglieder mit 2 oder mehr Ansprüchen zu erkennen. Anstatt LEFT JOIN zu verwenden verwenden wir JOIN , werden dadurch automatisch Mitglieder ausgeschlossen, die noch keinen zweiten Anspruch haben. Hier ist die (längere) Version, wenn Sie sich für LEFT JOIN entscheiden stattdessen (gleiche Ausgabe wie oben):

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

So sehen Sie Daten der obigen Abfrage vor dem Filtern:

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;

Ausgabe:

| 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) |

BEARBEITEN zur Anforderungsklärung:

Bei Ihrer Klarstellung wollten Sie auch Mitglieder einbeziehen, die noch keinen zweiten Anspruch haben, tun Sie dies stattdessen: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; 

Ausgabe:

| MEMBERCODE |
--------------
|          1 |
|          3 |

Die Technik besteht darin, das nextstartdate des Mitglieds zu zählen , wenn sie kein Datum für das nächste Startdatum haben (d. h. count(nextstartdate) = 0 ) dann sind es nur Einzelansprüche und auch gültig, dann hänge einfach diesen OR an Bedingung:

or count(nextstartdate) = 0; 

Eigentlich reicht die folgende Bedingung auch aus, ich wollte die Abfrage aber selbstdokumentierender machen, daher empfehle ich, auf das nächste Startdatum des Mitglieds zu zählen. Hier ist eine alternative Bedingung für das Zählen von Mitgliedern, die noch keinen zweiten Anspruch haben:

or count(*) = 1;

Übrigens müssen wir auch den Vergleich hiervon ändern:

sum(case when gap <= 1 then 1 end) = count(*)

dazu (da wir LEFT JOIN verwenden jetzt):

sum(case when gap <= 1 then 1 end) = count(gap)