Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Comment identifier le premier écart dans plusieurs plages de dates de début et de fin pour chaque membre distinct dans T-SQL

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

Voir la progression de la requête ici :http://www.sqlfiddle.com/#!3/ c3365/20

Comment cela fonctionne, comparez la date de fin actuelle à sa prochaine date de début et vérifiez l'écart de date :

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;

Sortie :

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

Vérifiez ensuite si un membre a le même nombre de réclamations sans aucun écart par rapport à ses réclamations totales :

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;

Sortie :

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

Enfin, filtrez-les, membres sans lacunes dans leurs revendications :

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

Sortie :

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

Notez que vous n'avez pas besoin de faire COUNT(*) > 1 pour détecter les membres avec 2 réclamations ou plus. Au lieu d'utiliser LEFT JOIN , nous utilisons JOIN , cela éliminera automatiquement les membres qui n'ont pas encore eu de deuxième réclamation. Voici la version (plus longue) si vous choisissez d'utiliser LEFT JOIN à la place (même résultat que ci-dessus) :

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

Voici comment afficher les données de la requête ci-dessus avant le filtrage :

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;

Sortie :

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

MODIFIER sur la clarification des exigences :

Sur votre clarification, vous vouliez inclure les membres qui n'ont pas encore eu de deuxième réclamation, faites ceci à la place :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; 

Sortie :

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

La technique consiste à compter la nextstartdate du membre , s'ils n'ont pas de prochaine date de début (c'est-à-dire count(nextstartdate) = 0 ) alors ce ne sont que des revendications uniques et valides aussi, alors joignez simplement ce OR condition :

or count(nextstartdate) = 0; 

En fait, la condition ci-dessous suffira également, je voulais cependant rendre la requête plus auto-documentée, donc je recommande de compter sur la prochaine date de début du membre. Voici une condition alternative pour compter les membres qui n'ont pas encore eu de deuxième réclamation :

or count(*) = 1;

Au fait, nous devons également modifier la comparaison :

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

à ceci (car nous utilisons LEFT JOIN maintenant):

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