sql >> Databasteknik >  >> RDS >> Sqlserver

Hur man identifierar det första gapet i flera start- och slutdatumintervall för varje distinkt medlem i T-SQL

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

Se frågeförloppet här:http://www.sqlfiddle.com/#!3/ c3365/20

Så här fungerar det, jämför det aktuella slutdatumet med nästa startdatum och kontrollera datumluckan:

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;

Utdata:

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

Kontrollera sedan om en medlem har samma antal anspråk utan några luckor till dess totala anspråk:

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;

Utdata:

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

Slutligen, filtrera dem, medlemmar utan luckor i sina anspråk:

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

Utdata:

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

Observera att du inte behöver göra COUNT(*) > 1 för att upptäcka medlemmar med 2 eller fler anspråk. Istället för att använda LEFT JOIN , vi använder JOIN , kommer detta automatiskt att kassera medlemmar som ännu inte har ett andra anspråk. Här är versionen (längre) om du väljer att använda LEFT JOIN istället (samma utdata som ovan):

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

Så här ser du data från ovanstående fråga före filtrering:

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;

Utdata:

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

REDIGERA om kravförtydligande:

I ditt förtydligande ville du inkludera medlemmar som ännu inte har gjort andra anspråk, gör så här istället: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; 

Utdata:

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

Tekniken är att räkna medlemmens nextstartdate , om de inte har något nästa startdatum(dvs. count(nextstartdate) = 0 ) då är de endast enstaka anspråk och giltiga också, bifoga bara denna OR skick:

or count(nextstartdate) = 0; 

Egentligen räcker villkoret nedan också, jag ville dock göra frågan mer självdokumenterande, därför rekommenderar jag att du räknar med medlemmens nästa startdatum. Här är ett alternativt villkor för att räkna medlemmar som ännu inte har fått ett andra anspråk:

or count(*) = 1;

Btw, vi måste också ändra jämförelsen från detta:

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

till detta (eftersom vi använder LEFT JOIN nu):

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


  1. mysql-fråga för att välja allt utom

  2. Genomför en begränsning med främmande nyckel för kolumner i samma tabell

  3. Ubuntu ORA-24960:attributet OCI_ATTR_USERNAME är större än den maximalt tillåtna längden på 255

  4. Inga resultat av SQL-fråga efter lyckad CSV-import i mysql med LOAD DATA LOCAL INFILE