sql >> Databáze >  >> RDS >> Sqlserver

Jak identifikovat první mezeru ve více počátečních a konečných obdobích pro každý odlišný člen v T-SQL

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

Podívejte se na průběh dotazu zde:http://www.sqlfiddle.com/#!3/ c3365/20

Jak to funguje, porovnejte aktuální datum ukončení s datem příštího zahájení a zkontrolujte mezeru v datech:

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;

Výstup:

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

Poté zkontrolujte, zda má člen stejný počet nároků bez mezer v celkovém počtu nároků:

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;

Výstup:

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

Nakonec je filtrujte, členy bez mezer ve svých nárocích:

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

Výstup:

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

Pamatujte, že nemusíte provádět COUNT(*) > 1 k detekci členů se 2 nebo více nároky. Místo použití LEFT JOIN , používáme JOIN , tím se automaticky vyřadí členové, kteří ještě nemají druhý nárok. Zde je verze (delší), pokud se rozhodnete použít LEFT JOIN místo toho (stejný výstup jako výše):

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

Zde je návod, jak zobrazit data výše uvedeného dotazu před filtrováním:

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;

Výstup:

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

UPRAVIT na objasnění požadavku:

Ve svém upřesnění jste chtěli zahrnout členy, kteří ještě nemají druhý nárok, udělejte to místo toho: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; 

Výstup:

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

Technikou je počítat nextstartdate člena , pokud nemají žádné další datum zahájení (tj. count(nextstartdate) = 0 ), pak jsou to pouze jednotlivé nároky a jsou také platné, pak stačí připojit toto OR podmínka:

or count(nextstartdate) = 0; 

Ve skutečnosti bude stačit i níže uvedená podmínka, chtěl jsem však udělat dotaz více samodokumentační, proto doporučuji počítat s datem příštího startu člena. Zde je alternativní podmínka pro počítání členů, kteří ještě nemají druhý nárok:

or count(*) = 1;

Btw, musíme také změnit srovnání z tohoto:

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

k tomu (protože používáme LEFT JOIN nyní):

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


  1. Má Oracle OCI funkci OCIPasswordChange šifrovat přenášené heslo

  2. Výčty Java, JPA a Výčty Postgres – Jak zajistím, aby spolupracovaly?

  3. Pgbackrest Restore and Restore Delta

  4. C# - Neočekávaná výjimka metody ověřování mysql_native_password