2016-07-29 1 views
0

Wir haben eine Tabelle mit Service-Bestimmungen für Menschen. Zum Beispiel:So finden Sie zusammenhängende Daten in zahlreichen Zeilen in SQL Server

id people_id dateStart dateEnd 
1 1   28.07.14 19.07.16 
2 2   14.04.15 16.02.16 
3 2   16.02.16 18.04.16 
4 2   18.04.16 27.06.16 
5 2   27.06.16 19.07.16 
6 2   19.07.16 NULL 
7 3   24.02.12 17.06.12 
8 3   23.07.12 19.09.12 
9 3   18.08.14 NULL 
10 4   28.06.15 NULL 
11 5   19.01.16 NULL 

brauche ich verschiedene person_id des (Clients) mit realem Startdatum des unfertigen ununterbrochenen Service zu extrahieren, die mehr als ein Jahr dauert und dann Tage zählen passieren. "Startdatum" und "Enddatum" von zwei verschiedenen Zeilen sollten gleich sein, um als zusammenhängend zu zählen. Ein Client kann nur einen nicht abgeschlossenen Dienst haben.
So das perfekte Ergebnis für die Tabelle oben wäre:

SELECT 
    --some other columns from PEOPLE, 
    p.PEOPLE_ID, 
    s.DATESTART, 
    DATEDIFF(DAY, s.DATESTART, GETDATE()) as lasts 
FROM 
    PEOPLE p 
    INNER JOIN service s on s.ID = 
    (
     SELECT TOP 1 s2.ID 
     FROM service s2 
     WHERE s2.PEOPLE_ID = p.PEOPLE_ID 
      AND s2.DATESTART IS NOT NULL 
      AND s2.DATEEND IS NULL 
     ORDER BY s2.DATESTART DESC 
    ) 
WHERE 
    DATEDIFF(DAY, s.DATESTART , GETDATE()) >= 365 

Aber ich kann nicht herausfinden, wie zusammenhängende Dienstleistungen bestimmen:

people_id dateStart lasts(days) 
2   14.04.15 472 
3   18.08.14 711 
4   28.06.15 397 

ich nicht Problem mit einem einzigen Dienst habe .

+0

Wenn 'dateEnd 'ist' null', bedeutet das, dass es weitergeht? – Ash

+0

@AshwinNair Ja ist es. Ich brauche nur aktive Clients. Wenn jemand keinen Dienst mit "dateEnd = NULL" hat, ist er ** nicht ** aktiv. –

+0

Welche Version von 'SQL Server' verwenden Sie? – Squirrel

Antwort

1

Mit lag() können Sie feststellen, wo Perioden des "kontinuierlichen" Service beginnen. Dann wird eine kumulative Summe dieser Flagge eine Gruppe bereitstellt, die für die Aggregation verwendet werden können:

select people_id, min(datestart) as datestart, 
     (case when count(dateend) = count(*) then max(dateend) end) as dateend 
from (select t.*, 
      sum(case when prev_dateend = datestart then 0 else 1 end) over 
       (partition by people_id order by datestart) as grp 
     from (select t.*, 
        lag(dateend) over (partition by people_id order by date_start) as prev_dateend 
      from t 
      ) t 
    ) t 
group by people_id, grp 
having count(*) > count(dateend); 
+0

Diese Abfrage scheint nicht die Anzahl der Tage zu erhalten, die das OP benötigt (Spalte 'Leisten (Tage) '). – Ash

+0

OP muss nur DATEDIFF() verwenden, um die Tage – Squirrel

+0

zu bekommen, also stimmen Sie zu, dass es nicht vollständig ist, dann:). Ich war neugierig und habe diese Abfrage ausprobiert und ich bekomme 4 statt 3 Zeilen, also muss das OP den Check für '> = 365 'hinzufügen. Außerdem bekomme ich 'NULL' für alle Zeilen unter der 'Datum'-Spalte. – Ash

0

Diese Abfrage:

select PeopleId, min(dateStart) as dateStart, sum(diff) as [lasts(days)] from 
(
    select P.*, datediff(day,datestart, DateEnd) as diff from 
     (select peopleId, dateStart, 
     isnull(dateend, cast(getdate() as date)) as DateEnd 
     from People 
     ) P 
    where Dateend in 
     (select DateStart from People 
      where PeopleId = P.PeopleId) 
      or DateEnd = cast(getdate() as date) -- check for continuous dates 
) P1 group by PeopleId having sum(diff)> 365  --check for > one year 

Die Kommentare in der Abfrage sollte die Dinge erklären

+0

Danke. Im Allgemeinen hatten Sie Recht, aber vergessen Sie eine andere Klausel. Der Client sollte mindestens eine Zeile haben, in der 'DateEnd IS NULL' ist (d. H. Aktiv). Also habe ich diesen Satz hinzugefügt und alles scheint jetzt in Ordnung zu sein. –

+0

Ich bin froh, dass ich geholfen habe. – Ash

Verwandte Themen